Passed
Pull Request — master (#15)
by mon
02:22
created

Type::getMediaComment()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace FileEye\MimeMap;
4
5
/**
6
 * Class for working with MIME types
7
 */
8
class Type
9
{
10
    /**
11
     * Short format [e.g. image/jpeg] for strings.
12
     */
13
    const SHORT_TEXT = 0;
14
15
    /**
16
     * Full format [e.g. image/jpeg; p="1"] for strings.
17
     */
18
    const FULL_TEXT = 1;
19
20
    /**
21
     * Full format with comments [e.g. image/jpeg; p="1" (comment)] for strings.
22
     */
23
    const FULL_TEXT_WITH_COMMENTS = 2;
24
25
    /**
26
     * The MIME media type.
27
     *
28
     * @var string
29
     */
30
    protected $media;
31
32
    /**
33
     * The MIME media type comment.
34
     *
35
     * @var string
36
     */
37
    protected $mediaComment;
38
39
    /**
40
     * The MIME media sub-type.
41
     *
42
     * @var string
43
     */
44
    protected $subType;
45
46
    /**
47
     * The MIME media sub-type comment.
48
     *
49
     * @var string
50
     */
51
    protected $subTypeComment;
52
53
    /**
54
     * Optional MIME parameters
55
     *
56
     * @var TypeParameter[]
57
     */
58
    protected $parameters = [];
59
60
    /**
61
     * Constructor.
62
     *
63
     * The type string will be parsed and the appropriate class vars set.
64
     *
65
     * @param string $type MIME type
66
     */
67 54
    public function __construct($type)
68
    {
69 54
        $this->parse($type);
70 47
    }
71
72
    /**
73
     * Parse a mime-type and set the class variables.
74
     *
75
     * @param string $type MIME type to parse
76
     *
77
     * @return void
78
     */
79 54
    protected function parse($type)
80
    {
81
        // Media and SubType are separated by a slash '/'.
82 54
        $media = TypeParser::parseStringPart($type, 0, '/');
83
84 53
        if (!$media['string']) {
85 3
            throw new MalformedTypeException('Media type not found');
86
        }
87 50
        if (!$media['delimiter_matched']) {
88 1
            throw new MalformedTypeException('Slash \'/\' to separate media type and subtype not found');
89
        }
90
91 49
        $this->media = strtolower($media['string']);
92 49
        $this->mediaComment = $media['comment'];
93
94
        // SubType and Parameters are separated by semicolons ';'.
95 49
        $sub = TypeParser::parseStringPart($type, $media['end_offset'] + 1, ';');
96
97 48
        if (!$sub['string']) {
98 1
            throw new MalformedTypeException('Media subtype not found');
99
        }
100
101 47
        $this->subType = strtolower($sub['string']);
102 47
        $this->subTypeComment = $sub['comment'];
103
104
        // Loops through the parameter.
105 47
        while ($sub['delimiter_matched']) {
106 26
            $sub = TypeParser::parseStringPart($type, $sub['end_offset'] + 1, ';');
107 26
            $tmp = explode('=', $sub['string'], 2);
108 26
            $p_name = trim($tmp[0]);
109 26
            $p_val = trim($tmp[1]);
110 26
            if ($p_val[0] == '"' && $p_val[strlen($p_val) - 1] == '"') {
111
                $p_val = substr($p_val, 1, -1);
112
            }
113 26
            $p_val = str_replace('\\"', '"', $p_val);
114 26
            $this->addParameter($p_name, $p_val, $sub['comment']);
115
        }
116 47
    }
117
118
    /**
119
     * Does this type have any parameters?
120
     *
121
     * @return boolean true if type has parameters, false otherwise
122
     */
123 28
    public function hasParameters()
124
    {
125 28
        return (bool) $this->parameters;
126
    }
127
128
    /**
129
     * Get a MIME type's parameters
130
     *
131
     * @return TypeParameter[] Type's parameters
132
     */
133 29
    public function getParameters()
134
    {
135 29
        return $this->parameters;
136
    }
137
138
    /**
139
     * Get a MIME type's parameter
140
     *
141
     * @param string $name Parameter name
142
     *
143
     * @return TypeParameter|null
144
     */
145 23
    public function getParameter($name)
146
    {
147 23
        return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
148
    }
149
150
    /**
151
     * Get a MIME type's media.
152
     *
153
     * Note: 'media' refers to the portion before the first slash.
154
     *
155
     * @return string Type's media.
156
     */
157 41
    public function getMedia()
158
    {
159 41
        return $this->media;
160
    }
161
162
    /**
163
     * Get a MIME type's media comment.
164
     *
165
     * @return string Type's media comment.
166
     */
167 28
    public function getMediaComment()
168
    {
169 28
        return $this->mediaComment;
170
    }
171
172
    /**
173
     * Get a MIME type's subtype.
174
     *
175
     * @return string Type's subtype, null if invalid mime type.
176
     */
177 42
    public function getSubType()
178
    {
179 42
        return $this->subType;
180
    }
181
182
    /**
183
     * Get a MIME type's subtype comment.
184
     *
185
     * @return string Type's subtype comment, null if invalid mime type.
186
     */
187 28
    public function getSubTypeComment()
188
    {
189 28
        return $this->subTypeComment;
190
    }
191
192
    /**
193
     * Create a textual MIME type from object values
194
     *
195
     * This function performs the opposite function of parse().
196
     *
197
     * @param int $format The format of the output string.
198
     *
199
     * @return string MIME type string
200
     */
201 41
    public function toString($format = Type::FULL_TEXT)
202
    {
203 41
        $type = strtolower($this->media);
204 41
        if ($format > Type::FULL_TEXT && isset($this->mediaComment)) {
205 2
            $type .= ' (' .  $this->mediaComment . ')';
206
        }
207 41
        $type .= '/' . strtolower($this->subType);
208 41
        if ($format > Type::FULL_TEXT && isset($this->subTypeComment)) {
209 5
            $type .= ' (' .  $this->subTypeComment . ')';
210
        }
211 41
        if ($format > Type::SHORT_TEXT && count($this->parameters)) {
212 23
            foreach ($this->parameters as $parameter) {
213 23
                $type .= '; ' . $parameter->toString($format);
214
            }
215
        }
216 41
        return $type;
217
    }
218
219
    /**
220
     * Is this type experimental?
221
     *
222
     * Note: Experimental types are denoted by a leading 'x-' in the media or
223
     *       subtype, e.g. text/x-vcard or x-world/x-vrml.
224
     *
225
     * @return boolean true if type is experimental, false otherwise
226
     */
227 1
    public function isExperimental()
228
    {
229 1
        if (substr($this->getMedia(), 0, 2) == 'x-' || substr($this->getSubType(), 0, 2) == 'x-') {
230 1
            return true;
231
        }
232 1
        return false;
233
    }
234
235
    /**
236
     * Is this a vendor MIME type?
237
     *
238
     * Note: Vendor types are denoted with a leading 'vnd. in the subtype.
239
     *
240
     * @return boolean true if type is a vendor type, false otherwise
241
     */
242 1
    public function isVendor()
243
    {
244 1
        if (substr($this->getSubType(), 0, 4) == 'vnd.') {
245 1
            return true;
246
        }
247 1
        return false;
248
    }
249
250
    /**
251
     * Is this a wildcard type?
252
     *
253
     * @return boolean true if type is a wildcard, false otherwise
254
     */
255 12
    public function isWildcard()
256
    {
257 12
        if (($this->getMedia() === '*' && $this->getSubtype() === '*') || strpos($this->getSubtype(), '*') !== false) {
258 6
            return true;
259
        }
260 9
        return false;
261
    }
262
263
    /**
264
     * Perform a wildcard match on a MIME type
265
     *
266
     * Example:
267
     * $type = new Type('image/png');
268
     * $type->wildcardMatch('image/*');
269
     *
270
     * @param string $wildcard Wildcard to check against
271
     *
272
     * @return boolean true if there was a match, false otherwise
273
     */
274 1
    public function wildcardMatch($wildcard)
275
    {
276 1
        $wildcard_type = new static($wildcard);
277
278 1
        if (!$wildcard_type->isWildcard()) {
279 1
            return false;
280
        }
281
282 1
        $wildcard_re = strtr($wildcard_type->toString(static::SHORT_TEXT), [
283 1
            '/' => '\\/',
284
            '*' => '.*',
285
        ]);
286 1
        $subject = $this->toString(static::SHORT_TEXT);
287
288 1
        return preg_match("/$wildcard_re/", $subject) === 1;
289
    }
290
291
    /**
292
     * Add a parameter to this type
293
     *
294
     * @param string $name    Parameter name
295
     * @param string $value   Parameter value
296
     * @param string $comment Comment for this parameter
297
     *
298
     * @return void
299
     */
300 26
    public function addParameter($name, $value, $comment = null)
301
    {
302 26
        $this->parameters[$name] = new TypeParameter($name, $value, $comment);
303 26
    }
304
305
    /**
306
     * Remove a parameter from this type
307
     *
308
     * @param string $name Parameter name
309
     *
310
     * @return void
311
     */
312 1
    public function removeParameter($name)
313
    {
314 1
        unset($this->parameters[$name]);
315 1
    }
316
317
    /**
318
     * Builds a list of MIME types.
319
     *
320
     * If the current type is a wildcard, than all the types matching the
321
     * wildcard will be returned.
322
     *
323
     * @param bool $strict
324
     *   (Optional) if true a MappingException is thrown when no type is
325
     *   found, if false it returns an empty array as a default.
326
     *   Defaults to true.
327
     *
328
     * @throws MappingException if no mapping found and $strict is true.
329
     *
330
     * @return string[]
331
     */
332 6
    public function buildTypesList($strict = true)
333
    {
334 6
        $map = MapHandler::map();
335 6
        $subject = $this->toString(static::SHORT_TEXT);
336
337
        // Find all types.
338 6
        $types = [];
339 6
        if (!$this->isWildcard()) {
340 6
            if ($map->hasType($subject)) {
341 6
                $types[] = $subject;
342
            }
343
        } else {
344 1
            foreach ($map->listTypes($subject) as $t) {
345 1
                $types[] = $t;
346
            }
347
        }
348
349
        // No types found, throw exception or return emtpy array.
350 6
        if (empty($types)) {
351 3
            if ($strict) {
352 1
                throw new MappingException('No MIME type found for ' . $subject . ' in map');
353
            } else {
354 2
                return [];
355
            }
356
        }
357
        
358 5
        return $types;
359
    }
360
361
    /**
362
     * Returns all the aliases related to the MIME type(s).
363
     *
364
     * If the current type is a wildcard, than all aliases of all the
365
     * types matching the wildcard will be returned.
366
     *
367
     * @param bool $strict
368
     *   (Optional) if true a MappingException is thrown when no mapping is
369
     *   found, if false it returns an empty array as a default.
370
     *   Defaults to true.
371
     *
372
     * @throws MappingException if no mapping found and $strict is true.
373
     *
374
     * @return string[]
375
     */
376 1 View Code Duplication
    public function getAliases($strict = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
377
    {
378 1
        $map = MapHandler::map();
379 1
        $types = $this->buildTypesList($strict);
380
381
        // Build the array of aliases.
382 1
        $aliases = [];
383 1
        foreach ($types as $t) {
384 1
            foreach ($map->getTypeAliases($t) as $a) {
385 1
                $aliases[$a] = $a;
386
            }
387
        }
388
389 1
        return array_keys($aliases);
390
    }
391
392
    /**
393
     * Returns the MIME type's preferred file extension.
394
     *
395
     * @param bool $strict
396
     *   (Optional) if true a MappingException is thrown when no mapping is
397
     *   found, if false it returns null as a default.
398
     *   Defaults to true.
399
     *
400
     * @throws MappingException if no mapping found and $strict is true.
401
     *
402
     * @return string
403
     */
404 7
    public function getDefaultExtension($strict = true)
405
    {
406 7
        $map = MapHandler::map();
407 7
        $subject = $this->toString(static::SHORT_TEXT);
408
409 7
        if (!$this->isWildcard()) {
410 4
            $proceed = $map->hasType($subject);
411
        } else {
412 3
            $proceed = count($map->listTypes($subject)) === 1;
413
        }
414
415 7
        if (!$proceed) {
416 5
            if ($strict) {
417 4
                throw new MappingException('Cannot determine default extension for type: ' . $this->toString(static::SHORT_TEXT));
418
            } else {
419 1
                return null;
420
            }
421
        }
422
423 3
        return $this->getExtensions()[0];
424
    }
425
426
    /**
427
     * Returns all the file extensions related to the MIME type(s).
428
     *
429
     * If the current type is a wildcard, than all extensions of all the
430
     * types matching the wildcard will be returned.
431
     *
432
     * @param bool $strict
433
     *   (Optional) if true a MappingException is thrown when no mapping is
434
     *   found, if false it returns an empty array as a default.
435
     *   Defaults to true.
436
     *
437
     * @throws MappingException if no mapping found and $strict is true.
438
     *
439
     * @return string[]
440
     */
441 6 View Code Duplication
    public function getExtensions($strict = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
442
    {
443 6
        $map = MapHandler::map();
444 6
        $types = $this->buildTypesList($strict);
445
446
        // Build the array of extensions.
447 5
        $extensions = [];
448 5
        foreach ($types as $t) {
449 5
            foreach ($map->getTypeExtensions($t) as $e) {
450 5
                $extensions[$e] = $e;
451
            }
452
        }
453
454 5
        return array_keys($extensions);
455
    }
456
}
457