aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/phpbb/mimetype/guesser.php
blob: f8cbffe8f53988f5bd050b11cd7ed57fa2a450ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/

namespace phpbb\mimetype;

class guesser
{
	/**
	* @const Default priority for mimetype guessers
	*/
	const PRIORITY_DEFAULT = 0;

	/**
	* @var array guessers
	*/
	protected $guessers;

	/**
	* Construct a mimetype guesser object
	*
	* @param array $mimetype_guessers Mimetype guesser service collection
	*/
	public function __construct($mimetype_guessers)
	{
		$this->register_guessers($mimetype_guessers);
	}

	/**
	* Register MimeTypeGuessers and sort them by priority
	*
	* @param array $mimetype_guessers Mimetype guesser service collection
	*
	* @throws \LogicException If incorrect or not mimetype guessers have
	*			been supplied to class
	*/
	protected function register_guessers($mimetype_guessers)
	{
		foreach ($mimetype_guessers as $guesser)
		{
			$is_supported = (method_exists($guesser, 'is_supported')) ? 'is_supported' : '';
			$is_supported = (method_exists($guesser, 'isSupported')) ? 'isSupported' : $is_supported;

			if (empty($is_supported))
			{
				throw new \LogicException('Incorrect mimetype guesser supplied.');
			}

			if ($guesser->$is_supported())
			{
				$this->guessers[] = $guesser;
			}
		}

		if (empty($this->guessers))
		{
			throw new \LogicException('No mimetype guesser supplied.');
		}

		// Sort guessers by priority
		usort($this->guessers, array($this, 'sort_priority'));
	}

	/**
	* Sort the priority of supplied guessers
	* This is a compare function for usort. A guesser with higher priority
	* should be used first and vice versa. usort() orders the array values
	* from low to high depending on what the comparison function returns
	* to it. Return value should be smaller than 0 if value a is smaller
	* than value b. This has been reversed in the comparison function in
	* order to sort the guessers from high to low.
	* Method has been set to public in order to allow proper testing.
	*
	* @param object $guesser_a Mimetype guesser a
	* @param object $guesser_b Mimetype guesser b
	*
	* @return int 	If both guessers have the same priority 0, bigger
	*		than 0 if first guesser has lower priority, and lower
	*		than 0 if first guesser has higher priority
	*/
	public function sort_priority($guesser_a, $guesser_b)
	{
		$priority_a = (int) (method_exists($guesser_a, 'get_priority')) ? $guesser_a->get_priority() : self::PRIORITY_DEFAULT;
		$priority_b = (int) (method_exists($guesser_b, 'get_priority')) ? $guesser_b->get_priority() : self::PRIORITY_DEFAULT;

		return $priority_b - $priority_a;
	}

	/**
	* Guess mimetype of supplied file
	*
	* @param string $file Path to file
	* @param string $file_name The real file name
	*
	* @return string Guess for mimetype of file
	*/
	public function guess($file, $file_name = '')
	{
		if (!is_file($file))
		{
			return false;
		}

		if (!is_readable($file))
		{
			return false;
		}

		$mimetype = 'application/octet-stream';

		foreach ($this->guessers as $guesser)
		{
			$mimetype_guess = $guesser->guess($file, $file_name);

			$mimetype = $this->choose_mime_type($mimetype, $mimetype_guess);
		}
		// Return any mimetype if we got a result or the fallback value
		return $mimetype;
	}

	/**
	 * Choose the best mime type based on the current mime type and the guess
	 * If a guesser returns nulls or application/octet-stream, we will keep
	 * the current guess. Guesses with a slash inside them will be favored over
	 * already existing ones. However, any guess that will pass the first check
	 * will always overwrite the default application/octet-stream.
	 *
	 * @param	string	$mime_type	The current mime type
	 * @param	string	$guess		The current mime type guess
	 *
	 * @return string The best mime type based on current mime type and guess
	 */
	public function choose_mime_type($mime_type, $guess)
	{
		if ($guess === null || $guess == 'application/octet-stream')
		{
			return $mime_type;
		}

		if ($mime_type == 'application/octet-stream' || strpos($guess, '/') !== false)
		{
			$mime_type = $guess;
		}

		return $mime_type;
	}
}