Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
MimeTypes
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
8 / 8
17
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 getMimeTypes
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getMimeType
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getMimeTypeNameFromFileExtension
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 getFileExtensionsFromMimeTypeName
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 isValidMimeTypeName
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isValidMimeTypeFileExtension
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 detect
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3/**
4 * @author: Doug Wilbourne (dougwilbourne@gmail.com)
5 */
6
7declare(strict_types=1);
8
9namespace pvc\http\mime;
10
11use Psr\SimpleCache\CacheInterface;
12use pvc\http\err\MimeTypesUnreadableStreamException;
13use pvc\http\err\UnknownMimeTypeDetectedException;
14use pvc\interfaces\http\mime\MimeTypeInterface;
15use pvc\interfaces\http\mime\MimeTypesInterface;
16use pvc\interfaces\http\mime\MimeTypesSrcInterface;
17use Symfony\Component\Cache\Adapter\FilesystemAdapter;
18use Symfony\Component\Cache\Psr16Cache;
19use Throwable;
20
21/**
22 * Class mimetype
23 */
24class MimeTypes implements MimeTypesInterface
25{
26    protected MimeTypesSrcInterface $mimeTypesSrc;
27
28    protected CacheInterface $cache;
29
30    protected string $cacheKey = 'mimeTypes';
31
32    /**
33     * @var array<string, MimeTypeInterface>
34     */
35    protected array $mimeTypes;
36
37    public function __construct(
38        ?MimeTypesSrcInterface $src = null,
39        ?CacheInterface $cache = null,
40        ?int $ttl = null,
41    )
42    {
43        $this->mimeTypesSrc = $src ?: new MimeTypesSrcJsDelivr();
44
45        if (!$cache instanceof \Psr\SimpleCache\CacheInterface) {
46            $psr6Cache = new FilesystemAdapter();
47            $this->cache = new Psr16Cache($psr6Cache);
48        } else {
49            $this->cache = $cache;
50        }
51
52        if ($ttl === null) {
53            /**
54             * valid for one day
55             */
56            $ttl = 24 * 60 * 60;
57        }
58        $this->cache->set($this->cacheKey, $this->mimeTypesSrc->getMimeTypes(),
59            $ttl);
60    }
61
62    /**
63     * @return array<string, MimeTypeInterface>
64     * @throws \Psr\SimpleCache\InvalidArgumentException
65     */
66    public function getMimeTypes(): array
67    {
68        /** @var array<string, MimeTypeInterface> $result */
69        $result = $this->cache->get($this->cacheKey);
70        return $result;
71    }
72
73    /**
74     * @param string $mimeTypeName
75     * @return MimeTypeInterface|null
76     */
77    public function getMimeType(string $mimeTypeName): ?MimeTypeInterface
78    {
79        $mimeTypes = $this->getMimeTypes();
80        return $mimeTypes[$mimeTypeName] ?? null;
81    }
82
83    /**
84     * @inheritDoc
85     */
86    public function getMimeTypeNameFromFileExtension(string $fileExt): ?string
87    {
88        foreach ($this->getMimeTypes() as $mimeType) {
89            if (in_array($fileExt, $mimeType->getFileExtensions(), true)) {
90                return $mimeType->getMimeTypeName();
91            }
92        }
93        return null;
94    }
95
96    /**
97     * @inheritDoc
98     */
99    public function getFileExtensionsFromMimeTypeName(string $mimeTypeName): array
100    {
101        $mimeTypes = $this->getMimeTypes();
102        $mt = $mimeTypes[$mimeTypeName] ?? null;
103        return $mt ? $mt->getFileExtensions() : [];
104    }
105
106    /**
107     * @inheritDoc
108     */
109    public function isValidMimeTypeName(string $mimeTypeName): bool
110    {
111        $mimeTypes = $this->getMimeTypes();
112        return isset($mimeTypes[$mimeTypeName]);
113    }
114
115    /**
116     * { @inheritDoc }
117     */
118    public function isValidMimeTypeFileExtension(string $fileExt): bool
119    {
120        return !is_null($this->getMimeTypeNameFromFileExtension($fileExt));
121    }
122
123    /**
124     * @param resource $stream
125     * @return MimeTypeInterface
126     * @throws MimeTypesUnreadableStreamException
127     * @throws UnknownMimeTypeDetectedException
128     */
129    public function detect($stream): MimeTypeInterface
130    {
131        /**
132         * mime_content_type throws a type error if it is not supplied a valid resource
133         */
134        try {
135            $detected = mime_content_type($stream);
136        } catch (Throwable $e) {
137            throw new MimeTypesUnreadableStreamException($e);
138        }
139
140        /**
141         * conceivably could return a mime type that is unknown in the list of mime types supplied by the cdn that
142         * this library is using
143         */
144        if ((false === $detected) || !$contentMimeType = $this->getMimeType($detected)) {
145            throw new UnknownMimeTypeDetectedException($detected);
146        }
147        return $contentMimeType;
148    }
149}