Generating MIME Type in PHP is not Magic
Sorry about the late post everyone. I had a long week and went to bed before making sure a post was queued. Hopefully you’ll forgive me.
I’m working on a project where I needed to generate a MIME type given a file name. Not only did I need to create a solution that worked, I also needed the solution to be compatible with PHP 4/5 and not require any additional software to be installed on the host. I thought this would be a simple matter of finding a PHP function that does this. Unfortunately, things were not as simple as this.
Problems with finfo_open
I found a very helpful PHP, Mime Types and Fileinfo post on Jelly and Custard. The “Mime Types in PHP 4.x” seemed to be exactly what I wanted. I quickly tried it out on my server, and it failed instantly with the following error:
Since I have PHP 5.2.6 running on my dev server, I was very confused since the post said that this was a “PHP 4.x” solution. I pulled up the PHP doc on the finfo_open function and was very surprised to see that the function is a PHP 5.3.0+ function. Fortunately, my version of PHP was just before this so that I could actually catch the error.
Turns out that the Jelly and Custard post points to another post, Installing PECL Modules, where instructions are given for installing the Fileinfo PECL Package. Installing this package allows versions prior to 5.3.0 to use the finfo_* functions via PECL.
This is not what I want. I’m working toward a solution that doesn’t require the installation of any additional software, and so far I’ve only seen solutions that require this. There has to be a better way.
Problems with mime_content_type
I then found the mime_content_type function. This looks better. However, PHP has marked this function as deprecated due to the PECL Fileinfo package. Relying on a deprecated function has numerous problems: it may throw warnings if used on versions of PHP that know the function is deprecated, most likely won’t receive any updates in the future, and could possibly be removed from future versions of PHP.
In addition to the deprecated issue, the mime_content_type function is laced with problems. In order to use the function the PHP on your system must have been built with the “--with-mime-magic” option. The function also relies upon the “mime_magic.magicfile” ini configuration to tell it where to find the magic file used to detect the MIME type of the file. This magic file may or may not exist/may or may not be readable.
Initial Testing
These problems led to interesting results when I tested it on my CentOS dedicated and Hostgator servers.
On my CentOS 5.2 dedicated server, I have PHP 5.2.6. The PHP build on this server was not built with the “--with-mime-magic” option, so it doesn’t have access to the mime_content_type function at all. In addition to this, since the version is just before 5.3 and I haven’t installed the Fileinfo PECL package, my dedicated server does not have access to either of the official PHP solutions without installing additional software.
On my Hostgator shared server, I have access to PHP 5.2.8. Unlike my dedicated server, this server’s PHP build was built with the “--with-mime-magic” option. “This is great,” I thought. I ran a test, and the function did indeed exist. Like my CentOS server, my Hostgator server does not have the Fileinfo PECL package and does not have PHP 5.3, so the mime_content_typefinfo_* functions are no go.
I did some more testing on my Hostgator server and was disappointed to find that the mime_content_type function exists yet is completely worthless. I tested file after file ranging from simple text files, to HTML documents, to a variety of image types. Every single test failed to produce a MIME type. When I say “failed”, I don’t mean that the program crashed with an error. The failure was worse than this, it simply returned an empty string to every single request.
I found that my Hostgator server’s PHP is set up to use the “/usr/local/apache/conf/magic” file to do it’s MIME magic. However, this file is not able to be read by my user. This means that the version of PHP might as well not have been built with the “--with-mime-magic” option at all.
It seems clear to me by now that there will not be an easy solution to this problem.
Final Solution
What I need is a solution that will first try to use the Fileinfo functions since they are the current standard. It will then fall back to using the mime_content_type function if and only if the function exists. Since the function is deprecated and PHP versions don’t actually package the replacement functions natively until 5.3.0, I need to also protect the code against conditions where neither Fileinfo nor mime_content_type are available. The final fallback will be manually generating the MIME type based upon an array match.
Using the fallback is not desirable since I probably won’t be updating the MIME types in the array very often, if at all. However, having it is better than having the code completely fail for common, present day MIME types. Hopefully, the conditions necessary to rely upon this fallback will become more and more rare as time goes on.
In addition to checking for the existence of the functions I’ll try to use, I need to make sure that the methods tried actually produce results. If a method fails to produce a non-empty value, I’ll move on to the next method.
The Code
I got the original idea for this code from a comment by svogal on the PHP doc site. I modified it to match my desired final solution.
The code is far to large to post here. You can download it here.
The array that I built for the mime types is quite large. Since I have a /etc/mime.types file (which is standard in most distros and provided by the mailcap package), I simply used it to generate my array. I quickly built a Perl script that parses through the mime.types file and outputs a file containing the PHP code to create the array. This script makes it easy for me to update the array any time the mime.types file is updated.
You can download my Perl script here. Simply run “perl generateMimeTypes” from the command line to build the array. The array code is put in a file called mime_type_var.code.
Examples
Simple Use
The code is fairly simple to use. Simply include or require the code in your own script and then call the get_file_mime_type function by passing the file’s path as the parameter.
-
<?php
-
require( ‘mime_type_lib.php’ );
-
-
$mime_type = get_file_mime_type( ‘/home/user/public_html/image.jpg’ );
-
echo "$mime_type\n";
-
?>
This produces the following output:
Note that PHP’s more advanced functions have the ability to dig into the content of the file to identify the MIME type, so if your system can make use of those functions and the file is not a JPEG image, the results could vary.
Using the debug Parameter
I’ve also provided a debug parameter that allows you to also get information on what method was used to get the MIME type. This may be helpful if you need to determine how sure you are that the detected MIME type is accurate. When the debug parameter is used, an associative array will be returned with a mime_type key and a method key.
This produces the following output:
Method: from_array
The possible methods are: fileinfo, mime_content_type, from_array, and last_resort. The first two should be self-explanitory. from_array means that the resulting MIME type was pulled from the array built into the function. last_resort means that the type could not be identified which results in a generic MIME type of “application/octet-stream” being used.
Conclusion
Frankly, I’m disappointed in the solutions provided by PHP to detect MIME types. I have access to a very stable, highly-regarded shared host and an extremely powerful, up-to-date dedicated host, neither of which have the ability to use either of the PHP solutions to detect MIME types without adding additional software.
I don’t remember which version of PHP my dedicated box started with, but I did upgrade to 5.1.6 using the standard repository back in October. I was only able to update to 5.2.6 by using the Utter Ramblings repository by Jason Litka. True, I could compile and install 5.3 or the PECL package myself, but I produce software for people who don’t have a clue what a compiler is, let alone what repositories or PECL extensions are.
It’s things like this that make development a pain. I could always just be a jerk of a developer, have the line “requires PHP 5.3+”, and tell all people that can’t run the software to check the requirements. However, I think that my job is to make the end-user’s life easier, not more complicated.
Hopefully others that have had woes dealing with this situation can make use of my code, and we can all just wait a few years until the majority of hosts have a PHP version that supports these calls natively.
Tags: CentOS, Fileinfo, Hostgator, MIME, mime_content_type, PECL, PHPShare This Post
Related Posts
Receive Updates
New posts on gaarai.com delivered directly to your email.






thank you. your code reduced my work.
I’m glad that I could help sure.
Hi!
There are some commonly misdetected types when using fileinfo. These are mostly MS Office ones. Example: docx is basically a ZIP file, so fileinfo will always fail detecting. I completed the list you’re using, and have another one, that has to be used before calling fileinfo to avoid the failure.
Drop me an email, and I’ll send you my list.
Balazs
Sounds good wodka. An email is headed your way shortly.
Thanks. Much appreciated.
You’re welcome montess.
Thanks for sharing your code, I’ve been trying to figure this out for a long time…saved me a lot of workarounds!
mate, you are a life saver – works a treat!
great for anyone on shared hosting with limited ability to change configuration.
Thanks for sharing.