Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
32 / 32 |
|
100.00% |
5 / 5 |
CRAP | |
100.00% |
1 / 1 |
guesser | |
100.00% |
32 / 32 |
|
100.00% |
5 / 5 |
24 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
register_guessers | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
8 | |||
sort_priority | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
guess | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
6 | |||
choose_mime_type | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
6 |
1 | <?php |
2 | /** |
3 | * |
4 | * This file is part of the phpBB Forum Software package. |
5 | * |
6 | * @copyright (c) phpBB Limited <https://www.phpbb.com> |
7 | * @license GNU General Public License, version 2 (GPL-2.0) |
8 | * |
9 | * For full copyright and license information, please see |
10 | * the docs/CREDITS.txt file. |
11 | * |
12 | */ |
13 | |
14 | namespace phpbb\mimetype; |
15 | |
16 | class guesser |
17 | { |
18 | /** |
19 | * @const Default priority for mimetype guessers |
20 | */ |
21 | const PRIORITY_DEFAULT = 0; |
22 | |
23 | /** |
24 | * @var array guessers |
25 | */ |
26 | protected $guessers; |
27 | |
28 | /** |
29 | * Construct a mimetype guesser object |
30 | * |
31 | * @param array $mimetype_guessers Mimetype guesser service collection |
32 | */ |
33 | public function __construct($mimetype_guessers) |
34 | { |
35 | $this->register_guessers($mimetype_guessers); |
36 | } |
37 | |
38 | /** |
39 | * Register MimeTypeGuessers and sort them by priority |
40 | * |
41 | * @param array $mimetype_guessers Mimetype guesser service collection |
42 | * |
43 | * @throws \LogicException If incorrect or not mimetype guessers have |
44 | * been supplied to class |
45 | */ |
46 | protected function register_guessers($mimetype_guessers) |
47 | { |
48 | foreach ($mimetype_guessers as $guesser) |
49 | { |
50 | $is_supported = (method_exists($guesser, 'is_supported')) ? 'is_supported' : ''; |
51 | $is_supported = (method_exists($guesser, 'isSupported')) ? 'isSupported' : $is_supported; |
52 | $is_supported = (method_exists($guesser, 'isGuesserSupported')) ? 'isGuesserSupported' : $is_supported; |
53 | |
54 | if (empty($is_supported)) |
55 | { |
56 | throw new \LogicException('Incorrect mimetype guesser supplied.'); |
57 | } |
58 | |
59 | if ($guesser->$is_supported()) |
60 | { |
61 | $this->guessers[] = $guesser; |
62 | } |
63 | } |
64 | |
65 | if (empty($this->guessers)) |
66 | { |
67 | throw new \LogicException('No mimetype guesser supplied.'); |
68 | } |
69 | |
70 | // Sort guessers by priority |
71 | usort($this->guessers, array($this, 'sort_priority')); |
72 | } |
73 | |
74 | /** |
75 | * Sort the priority of supplied guessers |
76 | * This is a compare function for usort. A guesser with higher priority |
77 | * should be used first and vice versa. usort() orders the array values |
78 | * from low to high depending on what the comparison function returns |
79 | * to it. Return value should be smaller than 0 if value a is smaller |
80 | * than value b. This has been reversed in the comparison function in |
81 | * order to sort the guessers from high to low. |
82 | * Method has been set to public in order to allow proper testing. |
83 | * |
84 | * @param object $guesser_a Mimetype guesser a |
85 | * @param object $guesser_b Mimetype guesser b |
86 | * |
87 | * @return int If both guessers have the same priority 0, bigger |
88 | * than 0 if first guesser has lower priority, and lower |
89 | * than 0 if first guesser has higher priority |
90 | */ |
91 | public function sort_priority($guesser_a, $guesser_b) |
92 | { |
93 | $priority_a = (int) (method_exists($guesser_a, 'get_priority')) ? $guesser_a->get_priority() : self::PRIORITY_DEFAULT; |
94 | $priority_b = (int) (method_exists($guesser_b, 'get_priority')) ? $guesser_b->get_priority() : self::PRIORITY_DEFAULT; |
95 | |
96 | return $priority_b - $priority_a; |
97 | } |
98 | |
99 | /** |
100 | * Guess mimetype of supplied file |
101 | * |
102 | * @param string $file Path to file |
103 | * @param string $file_name The real file name |
104 | * |
105 | * @return string|false Guess for mimetype of file or false if file can't be opened |
106 | */ |
107 | public function guess($file, $file_name = '') |
108 | { |
109 | if (!is_file($file)) |
110 | { |
111 | return false; |
112 | } |
113 | |
114 | if (!is_readable($file)) |
115 | { |
116 | return false; |
117 | } |
118 | |
119 | $mimetype = 'application/octet-stream'; |
120 | |
121 | $args = (array) func_get_args(); |
122 | foreach ($this->guessers as $guesser) |
123 | { |
124 | $guess = (method_exists($guesser, 'guess')) ? 'guess' : ''; |
125 | $guess = (method_exists($guesser, 'guessMimeType')) ? 'guessMimeType' : $guess; |
126 | |
127 | $mimetype_guess = $guesser->$guess(...$args); |
128 | |
129 | $mimetype = $this->choose_mime_type($mimetype, $mimetype_guess); |
130 | } |
131 | // Return any mimetype if we got a result or the fallback value |
132 | return $mimetype; |
133 | } |
134 | |
135 | /** |
136 | * Choose the best mime type based on the current mime type and the guess |
137 | * If a guesser returns nulls or application/octet-stream, we will keep |
138 | * the current guess. Guesses with a slash inside them will be favored over |
139 | * already existing ones. However, any guess that will pass the first check |
140 | * will always overwrite the default application/octet-stream. |
141 | * |
142 | * @param string $mime_type The current mime type |
143 | * @param string|null|false $guess The current mime type guess |
144 | * |
145 | * @return string The best mime type based on current mime type and guess |
146 | */ |
147 | public function choose_mime_type($mime_type, $guess) |
148 | { |
149 | if ($guess === false || $guess === null || $guess == 'application/octet-stream') |
150 | { |
151 | return $mime_type; |
152 | } |
153 | |
154 | if ($mime_type == 'application/octet-stream' || strpos($guess, '/') !== false) |
155 | { |
156 | $mime_type = $guess; |
157 | } |
158 | |
159 | return $mime_type; |
160 | } |
161 | } |