Completed
Push — master ( a99636...57f009 )
by Nazar
04:33
created

Mime::hasExtension()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 16
rs 8.8571
cc 5
eloc 10
nc 5
nop 1
1
<?php
2
3
/**
4
 * LICENSE: This source code is subject to the license that is available
5
 * in the LICENSE file distributed along with this package.
6
 *
7
 * @package    Mime
8
 * @author     Matthew Caruana Galizia <[email protected]>
9
 * @copyright  Karwana Ltd
10
 * @since      File available since Release 1.0.0
11
 */
12
13
namespace Karwana\Mime;
14
15
class Mime {
16
17
	private static $mime_types;
18
19
	private static function ensureDataLoaded() {
20
		if (!isset(static::$mime_types)) {
0 ignored issues
show
Bug introduced by
Since $mime_types is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $mime_types to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
21
			$json_path = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Resources', 'mime_types.json'));
22
			static::$mime_types = json_decode(file_get_contents($json_path), true);
0 ignored issues
show
Bug introduced by
Since $mime_types is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $mime_types to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
23
		}
24
	}
25
26
27
	/**
28
	 * Get the MIME type associated with a given extension.
29
	 *
30
	 * @param string $extension A file extension e.g. pdf.
31
	 *
32
	 * @return string|null The associated MIME type or null if none found.
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
33
	 */
34
	public static function getTypeForExtension($extension) {
35
		static::ensureDataLoaded();
0 ignored issues
show
Bug introduced by
Since ensureDataLoaded() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of ensureDataLoaded() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
36
37
		$extension = strtolower($extension);
38
		foreach (static::$mime_types as $mime_type => $extensions) {
0 ignored issues
show
Bug introduced by
Since $mime_types is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $mime_types to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
39
			if (is_array($extensions)) {
40
				if (in_array($extension, $extensions, true)) {
41
					return $mime_type;
42
				}
43
			} else if ($extension === $extensions) {
44
				return $mime_type;
45
			}
46
		}
47
	}
48
49
50
	/**
51
	 * Get the extension associated with a given MIME type.
52
	 *
53
	 * @param string $mime_type A MIME type e.g. application/pdf.
54
	 *
55
	 * @return string|null The first available associated extension or null if none found.
56
	 */
57
	public static function getExtensionForType($mime_type) {
58
		static::ensureDataLoaded();
0 ignored issues
show
Bug introduced by
Since ensureDataLoaded() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of ensureDataLoaded() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
59
60
		if (!static::hasType($mime_type)) {
61
			return;
62
		}
63
64
		$extensions = static::$mime_types[$mime_type];
0 ignored issues
show
Bug introduced by
Since $mime_types is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $mime_types to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
65
		if (is_array($extensions)) {
66
			return $extensions[0];
67
		}
68
69
		return $extensions;
70
	}
71
72
73
	/**
74
	 * Get all the extensions associated with a given MIME type.
75
	 *
76
	 * @param string $mime_type A MIME type e.g. application/pdf.
77
	 *
78
	 * @return string[]|null An array of all the associated extensions or null if none found.
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
79
	 */
80
	public static function getExtensionsForType($mime_type) {
81
		static::ensureDataLoaded();
0 ignored issues
show
Bug introduced by
Since ensureDataLoaded() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of ensureDataLoaded() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
82
83
		if (static::hasType($mime_type)) {
84
			return (array) static::$mime_types[$mime_type];
0 ignored issues
show
Bug introduced by
Since $mime_types is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $mime_types to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
85
		}
86
	}
87
88
89
	/**
90
	 * Check if an extension is known.
91
	 *
92
	 * @param string $extension An extension e.g. pdf.
93
	 *
94
	 * @return boolean
95
	 */
96
	public static function hasExtension($extension) {
97
		static::ensureDataLoaded();
0 ignored issues
show
Bug introduced by
Since ensureDataLoaded() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of ensureDataLoaded() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
98
99
		$extension = strtolower($extension);
100
		foreach (static::$mime_types as $extensions) {
0 ignored issues
show
Bug introduced by
Since $mime_types is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $mime_types to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
101
			if (is_array($extensions)) {
102
				if (in_array($extension, $extensions, true)) {
103
					return true;
104
				}
105
			} else if ($extension === $extensions) {
106
				return true;
107
			}
108
		}
109
110
		return false;
111
	}
112
113
114
	/**
115
	 * Check if a MIME type is known.
116
	 *
117
	 * @param string $mime_type A MIME type e.g. application/pdf.
118
	 *
119
	 * @return boolean
120
	 */
121
	public static function hasType($mime_type) {
122
		static::ensureDataLoaded();
0 ignored issues
show
Bug introduced by
Since ensureDataLoaded() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of ensureDataLoaded() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
123
		return isset(static::$mime_types[$mime_type]);
0 ignored issues
show
Bug introduced by
Since $mime_types is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $mime_types to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
124
	}
125
126
127
	/**
128
	 * Guess the MIME type of a given file, first by checking the extension then by falling back to magic.
129
	 *
130
	 * @param string $file_path Relative or absolute path to an existing file.
131
	 * @param string $reference_name Use this name for detection based on the extension.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $reference_name not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
132
	 * @param string $default Default MIME type.
133
	 *
134
	 * @return string|null The associated MIME type or the default if none found.
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
135
	 */
136
	public static function guessType($file_path, $reference_name = null, $default = 'application/octet-stream') {
137
		if (!$reference_name) {
138
			$reference_name = basename($file_path);
139
		}
140
141
		$extension = pathinfo($reference_name, PATHINFO_EXTENSION);
142
		if ($extension and $mime_type = static::getTypeForExtension($extension)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
143
			return $mime_type;
144
		}
145
146
		// While it's true that the extension doesn't determine the type,
147
		// only use finfo as a fallback because it's bad at detecting text
148
		// types like CSS and JavaScript.
149
		if ($mime_type = static::getMagicType($file_path)) {
150
			return $mime_type;
151
		}
152
153
		return $default;
154
	}
155
156
157
	/**
158
	 * Guess the extension of a given file, first by checking the path then by falling back to magic.
159
	 *
160
	 * @param string $file_path Relative or absolute path to an existing file.
161
	 * @param string $reference_name Use this name for detection based on the extension.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $reference_name not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
162
	 * @param string $default Default extension.
163
	 *
164
	 * @return string|null The associated extension or the default if none found.
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
165
	 */
166
	public static function guessExtension($file_path, $reference_name = null, $default = 'bin') {
167
		if (!$reference_name) {
168
			$reference_name = basename($file_path);
169
		}
170
171
		if ($extension = pathinfo($reference_name, PATHINFO_EXTENSION) and static::hasExtension($extension)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
172
			return strtolower($extension);
173
		}
174
175
		$mime_type = static::getMagicType($file_path);
176
		if ($mime_type and $extension = static::getExtensionForType($mime_type)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
177
			return $extension;
178
		}
179
180
		return $default;
181
	}
182
183
184
	/**
185
	 * Get the MIME type of a file using magic.
186
	 *
187
	 * @param string $file_path Relative or absolute path to an existing file.
188
	 *
189
	 * @return string|null The associated MIME type or null if no known type was detected.
190
	 */
191
	public static function getMagicType($file_path) {
192
		$file_info = finfo_open(FILEINFO_MIME_TYPE);
193
		$mime_type = finfo_file($file_info, $file_path);
194
		finfo_close($file_info);
195
196
		// Only return valid types, in order to maintain circular compatibility between methods.
197
		if (static::hasType($mime_type)) {
198
			return $mime_type;
199
		}
200
	}
201
}
202