PHP: How to properly check MIME type of a file?
To get MIME type, developers generally depend on $_FILES['input_name']['type']
. But this is absolutely vulnerable. Because a malicious user can set one of image/jpg
, image/png
, image/gif
etc. MIME types to a file that is not actually an image. In that case, the malicious user may get your script pass to upload other files instead of an image and execute your script for their purposes which is dangerous.
So I recommend that you not depend on the following snippet to get MIME of a file
$_FILES['input_name']['type'];
Rather I would recommend that you use this mime_content_type()
function to get MIME type but with the help of other PHP's built-in functions. And that is is_uploaded_file()
function. What it does is:
This is useful to help ensure that a malicious user hasn't tried to
trick the script into working on files upon which it should not be
working--for instance, /etc/passwd.This sort of check is especially important if there is any chance that
anything done with uploaded files could reveal their contents to the
user, or even to other users on the same system.
So to make this function work properly it needs a specific argument. Check out the code below:
if (is_uploaded_file($_FILES['input_name']['tmp_name'])) {
// Do other stuff.
}
This function returns true
on success, false
otherwise. So if it returns true
then you're ok with the file. Thanks to this function. Now mime_content_type()
function comes into play. How? Look at the code below:
if (is_uploaded_file($_FILES['input_name']['tmp_name'])) {
// Notice how to grab MIME type.
$mime_type = mime_content_type($_FILES['input_name']['tmp_name']);
// If you want to allow certain files
$allowed_file_types = ['image/png', 'image/jpeg', 'application/pdf'];
if (! in_array($mime_type, $allowed_file_types)) {
// File type is NOT allowed.
}
// Set up destination of the file
$destination = '/path/to/move/your/file/';
// Now you move/upload your file
if (move_uploaded_file ($_FILES['input_name']['tmp_name'] , $destination)) {
// File moved to the destination
}
}
BTW, for novice, do not try remote URL with this function to get MIME type. The code below will not work:
mime_content_type('http://www.example.com/uploads/example.png');
But the one below would work:
mime_content_type('/source/to/your/file/etc.png');
Hope you would enjoy uploading files from now on.
Getting mime type from file name in php
If you check the documentation, you can see that you are not doing anything wrong.
But if you do a bit more research:
https://stackoverflow.com/a/3664655/3784145
you can see that the mime type you get is correct, but the extension doesn't need to match with the mime type as explained here:
http://nl3.php.net/manual/en/function.mime-content-type.php#85879
I would therefore use the files suffix to determine the files mime type.
(as seen in the first example)
Detecting MIME type in PHP
Have you looked into this PEAR package?
http://pear.php.net/package/MIME_Type
How to detect MIME type of plain text files: CSS, Javascript, ini, sql?
Since I didn't find a proper library, I wrote my own magic file that detects all of my test files properly.
My application first tries my custom magic file for detection and falls back to the normal/system magic file if no type is detected.
The code it on github, see https://github.com/cweiske/MIME_Type_PlainDetect .
The magic file is at data/programming.magic and can be used with file -f programming.magic /path/to/source
Correct way to detect mime type in php
Based on this I've ported it to PHP:
function getMicrosoftOfficeMimeInfo($file) {
$fileInfo = array(
'word/' => array(
'type' => 'Microsoft Word 2007+',
'mime' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'extension' => 'docx'
),
'ppt/' => array(
'type' => 'Microsoft PowerPoint 2007+',
'mime' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'extension' => 'pptx'
),
'xl/' => array(
'type' => 'Microsoft Excel 2007+',
'mime' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'extension' => 'xlsx'
)
);
$pkEscapeSequence = "PK\x03\x04";
$file = new BinaryFile($file);
if ($file->bytesAre($pkEscapeSequence, 0x00)) {
if ($file->bytesAre('[Content_Types].xml', 0x1E)) {
if ($file->search($pkEscapeSequence, null, 2000)) {
if ($file->search($pkEscapeSequence, null, 1000)) {
$offset = $file->tell() + 26;
foreach ($fileInfo as $searchWord => $info) {
$file->seek($offset);
if ($file->bytesAre($searchWord)) {
return $fileInfo[$searchWord];
}
}
return array(
'type' => 'Microsoft OOXML',
'mime' => null,
'extension' => null
);
}
}
}
}
return false;
}
class BinaryFile_Exception extends Exception {}
class BinaryFile_Seek_Method {
const ABSOLUTE = 1;
const RELATIVE = 2;
}
class BinaryFile {
const SEARCH_BUFFER_SIZE = 1024;
private $handle;
public function __construct($file) {
$this->handle = fopen($file, 'r');
if ($this->handle === false) {
throw new BinaryFile_Exception('Cannot open file');
}
}
public function __destruct() {
fclose($this->handle);
}
public function tell() {
return ftell($this->handle);
}
public function seek($offset, $seekMethod = null) {
if ($offset !== null) {
if ($seekMethod === null) {
$seekMethod = BinaryFile_Seek_Method::ABSOLUTE;
}
if ($seekMethod === BinaryFile_Seek_Method::RELATIVE) {
$offset += $this->tell();
}
return fseek($this->handle, $offset);
} else {
return true;
}
}
public function read($length) {
return fread($this->handle, $length);
}
public function search($string, $offset = null, $maxLength = null, $seekMethod = null) {
if ($offset !== null) {
$this->seek($offset);
} else {
$offset = $this->tell();
}
$bytesRead = 0;
$bufferSize = ($maxLength !== null ? min(self::SEARCH_BUFFER_SIZE, $maxLength) : self::SEARCH_BUFFER_SIZE);
while ($read = $this->read($bufferSize)) {
$bytesRead += strlen($read);
$search = strpos($read, $string);
if ($search !== false) {
$this->seek($offset + $search + strlen($string));
return true;
}
if ($maxLength !== null) {
$bufferSize = min(self::SEARCH_BUFFER_SIZE, $maxLength - $bytesRead);
if ($bufferSize == 0) {
break;
}
}
}
return false;
}
public function getBytes($length, $offset = null, $seekMethod = null) {
$this->seek($offset, $seekMethod);
$read = $this->read($length);
return $read;
}
public function bytesAre($string, $offset = null, $seekMethod = null) {
return ($this->getBytes(strlen($string), $offset) == $string);
}
}
Usage:
$info = getMicrosoftOfficeMimeInfo('hi.docx');
/*
Array
(
[type] => Microsoft Word 2007+
[mime] => application/vnd.openxmlformats-officedocument.wordprocessingml.document
[extension] => docx
)
*/
$info = getMicrosoftOfficeMimeInfo('hi.xlsx');
/*
Array
(
[type] => Microsoft Excel 2007+
[mime] => application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
[extension] => xlsx
)
*/
$info = getMicrosoftOfficeMimeInfo('hi.pptx');
/*
Array
(
[type] => Microsoft PowerPoint 2007+
[mime] => application/vnd.openxmlformats-officedocument.presentationml.presentation
[extension] => pptx
)
*/
$info = getMicrosoftOfficeMimeInfo('hi.zip');
// bool(false)
How do I detect MIME type via a file handle in PHP?
Instead of passing a file handle or a string, pass an SplFileObject. Using this, you get OO access to the file without directly calling file system functions. Functions that require a pathname can still by used by calling ->getRealPath() on the object.
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime_type = $finfo->file( $fileObject->getRealPath() );
Detect MIME Type of file extracted from Database
You can get mime type using finfo_open and finfo_buffer. In this example i read content of a image from google and get its mimetype:
<?php
$Resource = finfo_open(FILEINFO_MIME);
$Info = finfo_buffer($Resource, file_get_contents('https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png')); // Returns: image/png; charset=binary
list($Mime, $Other) = explode(";", $Info);
echo $Mime; // image/png
Related Topics
How to Convert PHP Regex to JavaScript Regex
Uploading a File via Ajax with PHP
Execute PHP Script Before Every PHP Script
PHP Sending Variables to File_Get_Contents()
Turkish Characters Are Not Displayed Correctly
How to Enable Curl for an Installed Ubuntu Lamp Stack
Best Way to Connect to MySQL with PHP Securely
Reverse Order of Foreach List Items
PHP Dynamic Name for Object Property
Printing Content of a Xml File Using Xml Dom
PHP Undefined Index Error $_Files
Differencebetween the | and || Operators
Phpmailer Character Encoding Issues