Sometimes, when uploading files using <input> tag, I encounter problem where the file extension doesn't match with its mime type defined in application/config/mimes.php. For example when I upload a .doc file, it turns out that its mime type is actually application/octet-stream, not application/msword as expected.
I had this problem sometimes in the past. I did work around by adding application/octet-stream to .doc mime array. But is there a proper way to fix it?
I think the browser have force my file's mime type somehow. Is there any kind of HTTP header or html meta tag to prevent this?
As you can see here this a common problem and the solution you applied is legitimate.
It is not due to problem with codeignitor. It is due to php issue. For instance finfo_file function will return image with extension jpeg as image/png.
So, solution is go to config/mimes.php file and then add corresponding extension.
In case you do not know what is the extension behind the scene php is picking add this code to check.
$finfo = #finfo_open(FILEINFO_MIME);
$mime = #finfo_file($finfo, $_FILES["myname"]['tmp_name']);
$mime will be extension which php finally returns.
Related
Good day!
My code return incorrect type for this pdf file. For another pdf file this code is good.
$finfo = #finfo_open(FILEINFO_MIME);
$mime = #finfo_file($finfo, 'upload/123.pdf');
finfo_close($finfo);
print_r($mime);
This is answer:
application/octet-stream; charset=binary
This is what i need:
application/pdf
This is pdf file
https://dropmefiles.com/x6slw
Thank you!
Well I was curious, downloaded your file and yes on running your code it didn't give me application/pdf but instead application/octet-stream; charset=binary
Since the finfo function relies on the file signature (bytes) to find out the file MIME type I made a guess - something must be wrong with the signature so I analyzed it under a Hex-viewer and this is what I found
Your file
Normal file
To be identified properly the PDF signature should be present at the very start but in your file it was offset by 4 bytes. Since finfo could not find the correct MIME type it fell back to its generic "application/octet-stream; charset=binary"
So how to fix?
I must admit that php's inbuilt functions are pretty good for usual tasks but sometimes here and there you may encounter those "edge case" that's where 3rd party open source libraries come in and here I found which can fix it for you.
PhpMimeType : https://github.com/katzien/PhpMimeType
$type = \MimeType\MimeType::getType('123.pdf');
print_r($type); //"application/pdf"
// Yay!
This has come up before and I've followed this answer but no joy.
I'm trying to upload a .docx file to my CI app but it's giving me
The filetype you are attempting to upload is not allowed.
Now, when I vardump the mimetype of the received file by changing line 199 of system/libraries/upload.php to
$this->_file_mime_type($_FILES[$field]); die(var_dump($this->file_type));
I get
application/vnd.openxmlformats-officedocument.wordprocessingml.document;
charset=binary
...and that IS listed in my application/config/mimes.php file as an acceptable mime for docx.
This being the case, what else could be wrong?
It turns out that, somewhere along the CI flow, the mime had morphed from
application/vnd.openxmlformats-officedocument.wordprocessingml.document
to
application/msword
I have no idea at which point, or why, this happened. When I run the following in my CI controller method, I get the former.
$finfo = finfo_open(FILEINFO_MIME);
$mime = finfo_file($finfo, 'path/to/file.docx');
var_dump($mime);
So I've no idea how it changed to the latter along the way.
Needless to say, adding 'application/msword' to the allowed_types area of the upload options (passed to $this->upload->initialize($options)) solves the problem.
I just recently had the same problem and lost all day to solve it, but without success.
I recommend that you do not waste your time and just allow all the files and then do a php function to check if the file is .docx
my question is:
Is there some relation between a file extension and it's mime type? I mean, if i get a file, for instance, .php and change it's extension to .png will also change it's mime type?
Short answer: Yes.
Slightly longer answer: Mime types and file extensions provide hints to how to deal with a file. Whereas file extensions are commonly used for your OS to decide what program to open a file with, Mime types are used by your browser to decide how to present some data (or the server on how to interpret received data). Both are optional but it's a good practice to have an agreement. Changing the mime type a file is served as depends on your webserver. I believe Apache has settings somewhere to map from extensions to mime types. If you have your own back end serving content you can potentially serve content with any arbitrary mime type, for example, in PHP:
<?php
// We'll be outputting a PDF
header('Content-Type: application/pdf');
...
or
<?php
header('Content-Type: application/javascript');
echo "//script code here"
File extensions are hints as to the kind of data the file contains. MIME types are labels for the kind of data in a file. One file extension maps to at most one MIME type. One MIME type maps to zero or more file extensions. A good example is image/jpeg, which maps to both .jpg and .jpeg.
Theory aside, the MIME type a browser gives you is usually reliable, but if you require certainty you must then assume the browser has been compromised.
In such case, on the server using PHP, you can check that a given file matches a given MIME type with the FInfo extension:
$path = '/path/to/your/file.pdf';
$info = finfo_open(FILEINFO_MIME_TYPE);
switch (finfo_file($info, $fpath)) {
case 'application/pdf':
// hooray, this is what you want
// do whatever
break;
default:
throw new RuntimeException('I said give me a PDF!');
}
Or if you want a simple function:
function is_mime_type($path, $mime) {
return (finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path) === $mime);
}
if (is_mime_type('/path/to/file.pdf', 'application/pdf')) {
// hooray
}
Here is a similar answer that documents other approaches to accomplish this goal.
And here's an answer asking about the mapping between file extensions and MIME types.
When handling uploaded files $_FILES['foo']['type'] is not at all reliable. I've found if you change the extension on OS X the 'type' is changed automatically.
Instead consider:
$fileInfo = new \finfo(FILEINFO_MIME);
$mimeType = $fileInfo->buffer(file_get_contents($_FILES['foo']['tmp_name']));
$mimeType = explode(';', $mimeType);
Now, if I rename a PHP script to .jpg and upload it (on OS X 10.10) $_FILES['foo']['type'] = image/jpeg and $mimeType = text/x-php.
The file type can easily be changed but how can PHP's finfo::buffer be spoofed? What is the difference between what PHP checked for $_FILES['foo']['type'] and finfo(FILEINFO_MIME)?
PHP doesn't check anything in the $_FILES type; when uploading a file, the sending browser is sending meta data of what it thinks the file type is. $_FILES['file']['type'] simply reflects this value uploaded by the browser. Obviously, anyone can spoof this at will.
Finfo uses the magic database, which is simply a collection of identifying characteristics of file types. I.e., all JPEG files have a characteristic header, all ZIP files start a certain way, this file type has these number of leading bytes, that file type has those kinds of trailing bytes etc. etc. This is harder to spoof, if you actually want to produce a valid file of a certain type, but by no means impossible.
$_FILES gets it's type from the Content-Type header of the mime part that contains the file. That part is created by whatever sends the file, usually a browser which will guess the type based on the file extension.
The fileinfo extension, on the other hand, relies on the magic_open library. If I remember correctly, magic_open will check multiple attributes of the file, including file headers to determine the mimetype. Try embedding php in an html file. I believe, since the file header is <!DOCTYPE html> it will determine text/html is the mime type.
I have a file upload, it works great in everything except for firefox, it keeps saying the mimetype isnt supported. This is my code:
if(isset($_POST[submitfile]))
{
$uploadedsong = $_FILES['soup']['tmp_name'];
$mimetype = $_FILES['soup']['type'];
if($mimetype=="audio/mpeg"||$mimetype=="audio/x-mpeg-3"||$mimetype=="audio/mp3"||$mimetype=="audio/x-mpeg"||$mimetype=="audio/x-mp3"||$mimetype=="audio/mpeg3"||$mimetype=="audio/x-mpeg3"||$mimetype=="audio/mpg"||$mimetype=="audio/x-mpg"||$mimetype=="audio/x-mpegaudio")
{
This is allowing uploads for every browser, EXCEPT firefox! extremely frustrating, i dont know why this is happening. Any ideas?
The mime-type for the file-upload is totally informative and not further explicitly (and specifically) binding of what's-o-ever. Don't rely to it.
Firefox is doing nothing wrong here, it's the wrong expectations you've coded into your script - from the PHP ManualDocs:
$_FILES['userfile']['type']
The mime type of the file, if the browser provided this information. An example would be "image/gif". This mime type is however not checked on the PHP side and therefore don't take its value for granted.
So the use of this information is limited, it is not strict.
You should log which mime-type was uploaded, because you can't test against all browser/OS combinations.
Inspecting the file is necessary as well if you want to ensure it follows the convention of a mp3 file. Next to fileinfoDocs (which is for all files), there is php-reader and Zend_Mimme_Magic and a lot of other mp3 files related libraries.
Try using this to get the mime type
$file_info = new finfo(FILEINFO_MIME);
$mime_type = $file_info->file($file);