Passed
Push — master ( 3fc76b...c4daa3 )
by f
14:51
created

Formats::can()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.0416

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 9
rs 10
ccs 5
cts 6
cp 0.8333
cc 3
nc 3
nop 2
crap 3.0416
1
<?php
2
namespace wapmorgan\UnifiedArchive;
3
4
use wapmorgan\UnifiedArchive\Drivers\AlchemyZippy;
5
use wapmorgan\UnifiedArchive\Drivers\Basic\BasicDriver;
6
use wapmorgan\UnifiedArchive\Drivers\Cab;
7
use wapmorgan\UnifiedArchive\Drivers\Iso;
8
use wapmorgan\UnifiedArchive\Drivers\NelexaZip;
9
use wapmorgan\UnifiedArchive\Drivers\OneFile\Bzip;
10
use wapmorgan\UnifiedArchive\Drivers\OneFile\Gzip;
11
use wapmorgan\UnifiedArchive\Drivers\OneFile\Lzma;
12
use wapmorgan\UnifiedArchive\Drivers\Rar;
13
use wapmorgan\UnifiedArchive\Drivers\SevenZip;
14
use wapmorgan\UnifiedArchive\Drivers\SplitbrainPhpArchive;
15
use wapmorgan\UnifiedArchive\Drivers\TarByPear;
16
use wapmorgan\UnifiedArchive\Drivers\TarByPhar;
17
use wapmorgan\UnifiedArchive\Drivers\Zip;
18
19
class Formats
20
{
21
    // archived and compressed
22
    const ZIP = 'zip';
23
    const SEVEN_ZIP = '7z';
24
    const RAR = 'rar';
25
    const CAB = 'cab';
26
    const TAR = 'tar';
27
    const TAR_GZIP = 'tgz';
28
    const TAR_BZIP = 'tbz2';
29
    const TAR_LZMA = 'txz';
30
    const TAR_LZW = 'tar.z';
31
    const ARJ = 'arj';
32
33
    // compressed
34
    const GZIP = 'gz';
35
    const BZIP = 'bz2';
36
    const LZMA = 'xz';
37
38
    // non-usual archives
39
    const UEFI = 'uefi';
40
    const GPT = 'gpt';
41
    const MBR = 'mbr';
42
    const MSI = 'msi';
43
    const ISO = 'iso';
44
    const DMG = 'dmg';
45
    const UDF = 'udf';
46
    const RPM = 'rpm';
47
    const DEB = 'deb';
48
49
    /**
50
     * @var string[] List of archive format drivers.
51
     * Selection priority depends on placement in the list
52
     */
53
    public static $drivers = [
54
        Zip::class,
55
        Rar::class,
56
        Gzip::class,
57
        Bzip::class,
58
        Lzma::class,
59
        TarByPhar::class,
60
        SevenZip::class,
61
        AlchemyZippy::class,
62
        SplitbrainPhpArchive::class,
63
        NelexaZip::class,
64
        TarByPear::class,
65
        Iso::class,
66
        Cab::class,
67
    ];
68
69
    /** @var array<string, array<string>> List of all available types with their drivers */
70
    protected static $declaredDriversFormats;
71
72
    /** @var array List of all drivers with formats and support-state */
73
    protected static $supportedDriversFormats;
74
75
    protected static $oneLevelExtensions = [
76
        'zip' => Formats::ZIP,
77
        'jar' => Formats::ZIP,
78
        '7z' => Formats::SEVEN_ZIP,
79
        'rar' => Formats::RAR,
80
        'gz' => Formats::GZIP,
81
        'bz2' => Formats::BZIP,
82
        'xz' => Formats::LZMA,
83
        'iso' => Formats::ISO,
84
        'cab' => Formats::CAB,
85
        'tar' => Formats::TAR,
86
        'tgz' => Formats::TAR_GZIP,
87
        'tbz2' => Formats::TAR_BZIP,
88
        'txz' => Formats::TAR_LZMA,
89
        'arj' => Formats::ARJ,
90
        'efi' => Formats::UEFI,
91
        'gpt' => Formats::GPT,
92
        'mbr' => Formats::MBR,
93
        'msi' => Formats::MSI,
94 36
        'dmg' => Formats::DMG,
95
        'rpm' => Formats::RPM,
96
        'deb' => Formats::DEB,
97 36
        'udf' => Formats::UDF,
98
    ];
99 36
100 12
    protected static $twoLevelExtensions = [
101 12
        'tar.gz' => Formats::TAR_GZIP,
102 4
        'tar.bz2' => Formats::TAR_BZIP,
103 8
        'tar.xz' => Formats::TAR_LZMA,
104 4
        'tar.z' => Formats::TAR_LZW,
105 4
    ];
106 4
107
    protected static $mimeTypes = [
108
        'application/zip' => Formats::ZIP,
109
        'application/x-7z-compressed' => Formats::SEVEN_ZIP,
110
        'application/x-rar' => Formats::RAR,
111
        'application/zlib' => Formats::GZIP,
112
        'application/gzip'  => Formats::GZIP,
113 24
        'application/x-gzip' => Formats::GZIP,
114 18
        'application/x-bzip2' => Formats::BZIP,
115 6
        'application/x-lzma' => Formats::LZMA,
116 18
        'application/x-iso9660-image' => Formats::ISO,
117 4
        'application/vnd.ms-cab-compressed' => Formats::CAB,
118 14
        'application/x-tar' => Formats::TAR,
119 1
        'application/x-gtar' => Formats::TAR_GZIP,
120 13
    ];
121
122 13
    /**
123
     * Detect archive type by its filename or content
124 13
     *
125
     * @param string $originalFileName Archive filename
126 13
     * @param bool $contentCheck Whether archive type can be detected by content
127 4
     * @return null|bool One of UnifiedArchive type constants OR null if type is not detected
128 9
     */
129
    public static function detectArchiveFormat($originalFileName, $contentCheck = true)
130 9
    {
131 6
        $fileName = strtolower($originalFileName);
132 3
133 1
        // by file name
134 2
        $ld_offset = strrpos($fileName, '.');
135 1
        if ($ld_offset !== false) {
136 1
            $ext = substr($fileName, $ld_offset + 1);
137 1
            $sld_offset = strrpos($fileName, '.', - (strlen($ext) + 2)); // 1 byte for ., 1 for another char
138
            if ($sld_offset !== false) {
139
                $complex_ext = substr($fileName, $sld_offset + 1);
140
                if (isset(static::$twoLevelExtensions[$complex_ext])) {
141
                    return static::$twoLevelExtensions[$complex_ext];
142
                }
143
            }
144
            if (isset(static::$oneLevelExtensions[$ext])) {
145
                return static::$oneLevelExtensions[$ext];
146
            }
147
        }
148
149
        // by file content
150
        if ($contentCheck && function_exists('mime_content_type')) {
151
            $mime_type = mime_content_type($originalFileName);
152
            if (isset(static::$mimeTypes[$mime_type])) {
153
                return static::$mimeTypes[$mime_type];
154
            }
155
        }
156
157
        return false;
158
    }
159
160
    /**
161
     * Checks whether specific archive type can be opened with current system configuration
162
     *
163
     * @param string $format One of predefined archive types (class constants)
164
     * @return bool
165
     */
166
    public static function canOpen($format)
167
    {
168
        return static::can($format, Abilities::OPEN);
169
    }
170
171
    /**
172
     * Checks whether specified archive can be streamed
173
     *
174 25
     * @param string $format One of predefined archive types (class constants)
175
     * @return bool
176 25
     */
177
    public static function canStream($format)
178 25
    {
179 6
        return static::can($format, Abilities::STREAM_CONTENT);
180
    }
181 6
182 6
    /**
183
     * Checks whether specified archive can be created
184 6
     *
185
     * @param string $format One of predefined archive types (class constants)
186
     * @return bool
187
     */
188 25
    public static function canCreate($format)
189
    {
190
        return static::can($format, Abilities::CREATE);
191
    }
192
193
    /**
194
     * Checks whether specified archive can be created
195
     *
196
     * @param string $format One of predefined archive types (class constants)
197
     * @return bool
198
     */
199
    public static function canAppend($format)
200
    {
201
        return static::can($format, Abilities::APPEND);
202
    }
203
204
    /**
205
     * Checks whether specified archive can be created
206
     *
207
     * @param string $format One of predefined archive types (class constants)
208 2
     * @return bool
209
     */
210 2
    public static function canUpdate($format)
211
    {
212
        return static::can($format, Abilities::DELETE);
213
    }
214
215
    /**
216
     * Checks whether specified archive can be created
217
     *
218
     * @param string $format One of predefined archive types (class constants)
219 2
     * @return bool
220
     */
221 2
    public static function canEncrypt($format)
222
    {
223
        return static::can($format, Abilities::CREATE_ENCRYPTED);
224
    }
225
226
    /**
227
     * @param $format
228
     * @return void
229
     */
230 2
    protected static function getFormatSupportStatus($format)
231
    {
232 2
        static::getAllPossibleFormatsAndDrivers();
233
        if (!isset(static::$supportedDriversFormats[$format])) {
234
            static::$supportedDriversFormats[$format] = [];
235
            if (!isset(static::$declaredDriversFormats[$format])) {
236
                return;
237
            }
238
            /** @var BasicDriver $format_driver */
239
            foreach (static::$declaredDriversFormats[$format] as $format_driver) {
240
                static::$supportedDriversFormats[$format][$format_driver] = $format_driver::getFormatAbilities($format);
241
            }
242
        }
243
    }
244
245
    /**
246
     * @param string $format
247
     * @param string $ability
248
     * @return bool
249
     */
250
    public static function can($format, $ability)
251 4
    {
252
        self::getFormatSupportStatus($format);
253 4
        foreach (static::$supportedDriversFormats[$format] as $driver => $driver_abilities) {
254 4
            if (in_array($ability, $driver_abilities, true)) {
255
                return true;
256
            }
257 4
        }
258 4
        return false;
259 4
    }
260
261
    /**
262
     * @param string $format
263
     * @param int[] $abilities
264
     * @return string|null
265
     */
266
    public static function getFormatDriver($format, array $abilities = [])
267
    {
268
        self::getFormatSupportStatus($format);
269
        foreach (static::$supportedDriversFormats[$format] as $driver => $driver_abilities) {
270 25
            if (count(array_intersect($driver_abilities, $abilities)) === count($abilities)) {
271
                return $driver;
272 25
            }
273
        }
274 25
275
        return null;
276
    }
277 25
278 23
    /**
279
     * @param string $archiveFormat
280 2
     * @return int|string|null
281 2
     */
282 2
    public static function getFormatExtension($archiveFormat)
283
    {
284
        return
285
            array_search($archiveFormat, static::$twoLevelExtensions)
286
            ?: array_search($archiveFormat, static::$oneLevelExtensions)
287
            ?: null;
288
    }
289
290
    /**
291
     * @param $format
292
     * @return null|string
293
     */
294
    public static function getFormatMimeType($format)
295
    {
296
        return array_search($format, static::$mimeTypes, true)
297
            ?: null;
298
    }
299
300
    public static function getDeclaredDriverFormats()
301
    {
302
        static::getAllPossibleFormatsAndDrivers();
303
        return static::$declaredDriversFormats;
304
    }
305
306
    public static function getSupportedDriverFormats()
307
    {
308
        foreach (self::getDeclaredDriverFormats() as $format => $formatDrivers) {
309
            self::getFormatSupportStatus($format);
310
        }
311
        return static::$supportedDriversFormats;
312
    }
313
314
    /**
315
     * Tests system configuration
316
     */
317
    protected static function getAllPossibleFormatsAndDrivers()
318
    {
319
        if (static::$declaredDriversFormats === null) {
0 ignored issues
show
introduced by
The condition static::declaredDriversFormats === null is always false.
Loading history...
320
            static::$declaredDriversFormats = [];
321
            foreach (static::$drivers as $handlerClass)
322
            {
323 25
                $handler_formats = $handlerClass::getFormats();
324
                foreach ($handler_formats as $handler_format)
325 25
                {
326 1
                    static::$declaredDriversFormats[$handler_format][] = $handlerClass;
327 1
                }
328
            }
329 1
        }
330 1
    }
331
332 1
    /**
333
     * @param string $format
334
     * @param string $ability
335
     * @return bool
336 25
     * @deprecated Use {{Formats::can}} instead
337
     */
338
    public static function checkFormatSupportAbility($format, $ability)
339
    {
340
        return static::can($format, $ability);
341
    }
342
}
343