Passed
Push — master ( 26093e...7ed8f5 )
by mon
02:06
created

Type::getSubTypeComment()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
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 61
    public function __construct($type)
68
    {
69 61
        TypeParser::parse($type, $this);
70 54
    }
71
72
    /**
73
     * Gets a MIME type's media.
74
     *
75
     * Note: 'media' refers to the portion before the first slash.
76
     *
77
     * @return string
78
     *   Type's media.
79
     */
80 47
    public function getMedia()
81
    {
82 47
        return $this->media;
83
    }
84
85
    /**
86
     * Sets a MIME type's media.
87
     *
88
     * @param string $media
89
     *   Type's media.
90
     *
91
     * @return $this
92
     */
93 56
    public function setMedia($media)
94
    {
95 56
        $this->media = $media;
96 56
        return $this;
97
    }
98
99
    /**
100
     * Gets a MIME type's media comment.
101
     *
102
     * @return string Type's media comment.
103
     */
104 29
    public function getMediaComment()
105
    {
106 29
        return $this->mediaComment;
107
    }
108
109
    /**
110
     * Sets a MIME type's media comment.
111
     *
112
     * @param string Type's media comment.
0 ignored issues
show
Documentation Bug introduced by
The doc comment Type's at position 0 could not be parsed: Unknown type name 'Type's' at position 0 in Type's.
Loading history...
113
     *
114
     * @return $this
115
     */
116 56
    public function setMediaComment($comment)
117
    {
118 56
        $this->mediaComment = $comment;
119 56
        return $this;
120
    }
121
122
    /**
123
     * Gets a MIME type's subtype.
124
     *
125
     * @return string
126
     *   Type's subtype, null if invalid mime type.
127
     */
128 48
    public function getSubType()
129
    {
130 48
        return $this->subType;
131
    }
132
133
    /**
134
     * Sets a MIME type's subtype.
135
     *
136
     * @param string $sub_type
137
     *   Type's subtype.
138
     *
139
     * @return $this
140
     */
141 54
    public function setSubType($sub_type)
142
    {
143 54
        $this->subType = $sub_type;
144 54
        return $this;
145
    }
146
147
    /**
148
     * Gets a MIME type's subtype comment.
149
     *
150
     * @return string
151
     *   Type's subtype comment, null if invalid mime type.
152
     */
153 29
    public function getSubTypeComment()
154
    {
155 29
        return $this->subTypeComment;
156
    }
157
158
    /**
159
     * Sets a MIME type's subtype comment.
160
     *
161
     * @param string $comment
162
     *   Type's subtype comment.
163
     *
164
     * @return $this
165
     */
166 54
    public function setSubTypeComment($comment)
167
    {
168 54
        $this->subTypeComment = $comment;
169 54
        return $this;
170
    }
171
172
    /**
173
     * Does this type have any parameters?
174
     *
175
     * @return boolean
176
     *   True if type has parameters, false otherwise.
177
     */
178 29
    public function hasParameters()
179
    {
180 29
        return (bool) $this->parameters;
181
    }
182
183
    /**
184
     * Get a MIME type's parameters.
185
     *
186
     * @return TypeParameter[]
187
     */
188 30
    public function getParameters()
189
    {
190 30
        return $this->parameters;
191
    }
192
193
    /**
194
     * Get a MIME type's parameter.
195
     *
196
     * @param string $name
197
     *   Parameter name
198
     *
199
     * @return TypeParameter|null
200
     */
201 24
    public function getParameter($name)
202
    {
203 24
        return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
204
    }
205
206
    /**
207
     * Add a parameter to this type
208
     *
209
     * @param string $name
210
     *   Parameter name.
211
     * @param string $value
212
     *   Parameter value.
213
     * @param string $comment
214
     *   Comment for this parameter.
215
     *
216
     * @return void
217
     */
218 27
    public function addParameter($name, $value, $comment = null)
219
    {
220 27
        $this->parameters[$name] = new TypeParameter($name, $value, $comment);
221 27
    }
222
223
    /**
224
     * Remove a parameter from this type.
225
     *
226
     * @param string $name
227
     *   Parameter name.
228
     *
229
     * @return void
230
     */
231 1
    public function removeParameter($name)
232
    {
233 1
        unset($this->parameters[$name]);
234 1
    }
235
236
    /**
237
     * Create a textual MIME type from object values.
238
     *
239
     * This function performs the opposite function of parse().
240
     *
241
     * @param int $format
242
     *   The format of the output string.
243
     *
244
     * @return string
245
     *   MIME type string.
246
     */
247 48
    public function toString($format = Type::FULL_TEXT)
248
    {
249 48
        $type = strtolower($this->media);
250 48
        if ($format > Type::FULL_TEXT && isset($this->mediaComment)) {
251 3
            $type .= ' (' .  $this->mediaComment . ')';
252
        }
253 48
        $type .= '/' . strtolower($this->subType);
254 48
        if ($format > Type::FULL_TEXT && isset($this->subTypeComment)) {
255 6
            $type .= ' (' .  $this->subTypeComment . ')';
256
        }
257 48
        if ($format > Type::SHORT_TEXT && count($this->parameters)) {
258 24
            foreach ($this->parameters as $parameter) {
259 24
                $type .= '; ' . $parameter->toString($format);
260
            }
261
        }
262 48
        return $type;
263
    }
264
265
    /**
266
     * Is this type experimental?
267
     *
268
     * Note: Experimental types are denoted by a leading 'x-' in the media or
269
     *       subtype, e.g. text/x-vcard or x-world/x-vrml.
270
     *
271
     * @return boolean
272
     *   True if type is experimental, false otherwise.
273
     */
274 1
    public function isExperimental()
275
    {
276 1
        if (substr($this->getMedia(), 0, 2) == 'x-' || substr($this->getSubType(), 0, 2) == 'x-') {
277 1
            return true;
278
        }
279 1
        return false;
280
    }
281
282
    /**
283
     * Is this a vendor MIME type?
284
     *
285
     * Note: Vendor types are denoted with a leading 'vnd. in the subtype.
286
     *
287
     * @return boolean
288
     *   True if type is a vendor type, false otherwise.
289
     */
290 1
    public function isVendor()
291
    {
292 1
        if (substr($this->getSubType(), 0, 4) == 'vnd.') {
293 1
            return true;
294
        }
295 1
        return false;
296
    }
297
298
    /**
299
     * Is this a wildcard type?
300
     *
301
     * @return boolean
302
     *   True if type is a wildcard, false otherwise.
303
     */
304 17
    public function isWildcard()
305
    {
306 17
        if (($this->getMedia() === '*' && $this->getSubtype() === '*') || strpos($this->getSubtype(), '*') !== false) {
307 8
            return true;
308
        }
309 14
        return false;
310
    }
311
312
    /**
313
     * Is this an alias?
314
     *
315
     * @return boolean
316
     *   True if type is an alias, false otherwise.
317
     */
318 15
    public function isAlias()
319
    {
320 15
        if ($this->isWildcard()) {
321 5
            return false;
322
        }
323
324 12
        $map = MapHandler::map();
325 12
        $subject = $this->toString(static::SHORT_TEXT);
326 12
        return $map->hasAlias($subject);
327
    }
328
329
    /**
330
     * Perform a wildcard match on a MIME type
331
     *
332
     * Example:
333
     * $type = new Type('image/png');
334
     * $type->wildcardMatch('image/*');
335
     *
336
     * @param string $wildcard
337
     *   Wildcard to check against.
338
     *
339
     * @return boolean
340
     *   True if there was a match, false otherwise.
341
     */
342 1
    public function wildcardMatch($wildcard)
343
    {
344 1
        $wildcard_type = new static($wildcard);
345
346 1
        if (!$wildcard_type->isWildcard()) {
347 1
            return false;
348
        }
349
350 1
        $wildcard_re = strtr($wildcard_type->toString(static::SHORT_TEXT), [
351 1
            '/' => '\\/',
352
            '*' => '.*',
353
        ]);
354 1
        $subject = $this->toString(static::SHORT_TEXT);
355
356 1
        return preg_match("/$wildcard_re/", $subject) === 1;
357
    }
358
359
    /**
360
     * Builds a list of MIME types existing in the map.
361
     *
362
     * If the current type is a wildcard, than all the types matching the
363
     * wildcard will be returned.
364
     *
365
     * @param bool $strict
366
     *   (Optional) if true a MappingException is thrown when no type is
367
     *   found, if false it returns an empty array as a default.
368
     *   Defaults to true.
369
     *
370
     * @throws MappingException if no mapping found and $strict is true.
371
     *
372
     * @return string[]
373
     */
374 8
    protected function buildTypesList($strict = true)
375
    {
376 8
        $map = MapHandler::map();
377 8
        $subject = $this->toString(static::SHORT_TEXT);
378
379
        // Find all types.
380 8
        $types = [];
381 8
        if (!$this->isWildcard()) {
382 8
            if ($map->hasType($subject)) {
383 8
                $types[] = $subject;
384
            }
385
        } else {
386 1
            foreach ($map->listTypes($subject) as $t) {
387 1
                $types[] = $t;
388
            }
389
        }
390
391
        // No types found, throw exception or return emtpy array.
392 8
        if (empty($types)) {
393 5
            if ($strict) {
394 2
                throw new MappingException('No MIME type found for ' . $subject . ' in map');
395
            } else {
396 3
                return [];
397
            }
398
        }
399
400 6
        return $types;
401
    }
402
403
    /**
404
     * Returns the unaliased MIME type.
405
     *
406
     * @return Type
407
     *   $this if the current type is not an alias, the parent type if the
408
     *   current type is an alias.
409
     */
410 11
    protected function getUnaliasedType()
411
    {
412 11
        if (!$this->isAlias()) {
413 11
            return $this;
414
        } else {
415 3
            $map = MapHandler::map();
416 3
            $subject = $this->toString(static::SHORT_TEXT);
417 3
            $types = $map->getAliasTypes($subject);
418 3
            return new static($types[0]);
419
        }
420
    }
421
422
    /**
423
     * Returns a description for the MIME type, if existing in the map.
424
     *
425
     * @param bool $include_acronym
426
     *   (Optional) if true and an acronym description exists for the type,
427
     *   the returned description will contain the acronym and its description,
428
     *   appended with a comma. Defaults to false.
429
     *
430
     * @return string|null
431
     */
432 1
    public function getDescription($include_acronym = false)
433
    {
434 1
        if ($this->isWildcard()) {
435 1
            return null;
436
        }
437
438 1
        $map = MapHandler::map();
439 1
        $subject = $this->getUnaliasedType()->toString(static::SHORT_TEXT);
440 1
        $descriptions = $map->getTypeDescriptions($subject);
441 1
        $res = null;
442 1
        if (isset($descriptions[0])) {
443 1
            $res = $descriptions[0];
444
        }
445 1
        if ($include_acronym && isset($descriptions[1])) {
446 1
            $res .= ', ' . $descriptions[1];
447
        }
448 1
        return $res;
449
    }
450
451
    /**
452
     * Returns all the aliases related to the MIME type(s).
453
     *
454
     * If the current type is a wildcard, than all aliases of all the
455
     * types matching the wildcard will be returned.
456
     *
457
     * @param bool $strict
458
     *   (Optional) if true a MappingException is thrown when no mapping is
459
     *   found, if false it returns an empty array as a default.
460
     *   Defaults to true.
461
     *
462
     * @throws MappingException if error and $strict is true.
463
     *
464
     * @return string[]
465
     */
466 4
    public function getAliases($strict = true)
467
    {
468
        // Fail if the current type is an alias already.
469 4
        if ($this->isAlias()) {
470 2
            if ($strict) {
471 1
                $subject = $this->toString(static::SHORT_TEXT);
472 1
                throw new MappingException("Cannot get aliases for '{$subject}', it is an alias itself");
473
            } else {
474 1
                return [];
475
            }
476
        }
477
478 3
        $map = MapHandler::map();
479 3
        $types = $this->buildTypesList($strict);
480
481
        // Build the array of aliases.
482 2
        $aliases = [];
483 2
        foreach ($types as $t) {
484 2
            foreach ($map->getTypeAliases($t) as $a) {
485 2
                $aliases[$a] = $a;
486
            }
487
        }
488
489 2
        return array_keys($aliases);
490
    }
491
492
    /**
493
     * Returns the MIME type's preferred file extension.
494
     *
495
     * @param bool $strict
496
     *   (Optional) if true a MappingException is thrown when no mapping is
497
     *   found, if false it returns null as a default.
498
     *   Defaults to true.
499
     *
500
     * @throws MappingException if no mapping found and $strict is true.
501
     *
502
     * @return string
503
     */
504 7
    public function getDefaultExtension($strict = true)
505
    {
506 7
        $map = MapHandler::map();
507 7
        $unaliased_type = $this->getUnaliasedType();
508 7
        $subject = $unaliased_type->toString(static::SHORT_TEXT);
509
510 7
        if (!$unaliased_type->isWildcard()) {
511 4
            $proceed = $map->hasType($subject);
512
        } else {
513 3
            $proceed = count($map->listTypes($subject)) === 1;
514
        }
515
516 7
        if (!$proceed) {
517 5
            if ($strict) {
518 4
                throw new MappingException('Cannot determine default extension for type: ' . $unaliased_type->toString(static::SHORT_TEXT));
519
            } else {
520 1
                return null;
521
            }
522
        }
523
524 3
        return $unaliased_type->getExtensions()[0];
525
    }
526
527
    /**
528
     * Returns all the file extensions related to the MIME type(s).
529
     *
530
     * If the current type is a wildcard, than all extensions of all the
531
     * types matching the wildcard will be returned.
532
     *
533
     * @param bool $strict
534
     *   (Optional) if true a MappingException is thrown when no mapping is
535
     *   found, if false it returns an empty array as a default.
536
     *   Defaults to true.
537
     *
538
     * @throws MappingException if no mapping found and $strict is true.
539
     *
540
     * @return string[]
541
     */
542 6
    public function getExtensions($strict = true)
543
    {
544 6
        $map = MapHandler::map();
545 6
        $types = $this->getUnaliasedType()->buildTypesList($strict);
546
547
        // Build the array of extensions.
548 5
        $extensions = [];
549 5
        foreach ($types as $t) {
550 5
            foreach ($map->getTypeExtensions($t) as $e) {
551 5
                $extensions[$e] = $e;
552
            }
553
        }
554
555 5
        return array_keys($extensions);
556
    }
557
}
558