Hi all,

I'm working on a file upload script in which, for security reasons, I check if the file is allowed to be uploaded. I want to do so based on 3 - 4 checks.

First I check the file extension which is easy. But not very trustworthy. Who says I can't rename malicous_code.php to malicous_code.gif... :xbones:

So secondly I check the MIME type sent by the browser with the upload. This is given in the variable $_FILES['userfile']['type']. As the PHP manual mentions this isn't something you should fully trust because it isn't checked by PHP and thus is something one can manipulate. Besides I found documentation that MSIE bases the MIME info it sends in this variable on the file extension :xbones:

These checks complement each other. 1+1=3 in this case... If I were to just check the MIME things can go very wrong. Most images allow comments to be attached into them. So I could write malicious code to the comment of a gif and rename this image.gif to image.php. The MIME will still be image/gif eventhough the extension is php. It will pass the upload check and when the file is called with a browser the server will pass the file thru the php interpreter resulting into the malicious code in the image comment being run... :xbones:

Now if I were to just allow webimages for upload I could double check the MIME with getimagesize() and image_type_to_mime_type(). And I could strip the malicious code in the comment by recreating the image.

$size = getimagesize($_FILES['userfile']['tmp_name']);
if(!in_array(image_type_to_mime_type($size[2]), $allowed_mime)) {
   //return error
   exit;
}
$tmp_img = @imagecreatefromjpeg($_FILES['userfile']['tmp_name']);
if(!$tmp_img) {
   //return error
} else {
   imagejpeg($tmp_img, 'path/'.$_FILES['userfile']['name']);
}

But what if I do want to allow other MIME types? Like for uploading Adobe Illustrator files (application/postscript ai eps ps)?

I've tried the depreaceated mime_content_type() and it does the job for some MIME types but doesn't recognize a whole lot of others, for instance an illustrator.ai

mime_content_type($_FILES['userfile']['tmp_name']);

Why is this, or what am I doing wrong? Is it beacause the magic.mime file isn't up to date?

Ofcourse I should check the MIME with the fileinfo functions but I haven't gotten to that yet as I want to write this script to work on older server setups too.

Anyone know a way of checking the MIME type of uploaded files?

Cheers

    Hey NogDog,

    Thanx for your, somewhat short, reply 🙂 I will look into it. But do you happen to know why mime_content_type() doesn't return values for some files? I've pulled a different magic.mime file from somewhere and although it gave the next error:

    warning: mime_magic: invalid type 0 in mconvert()

    It did also return correct MIME types for some files which the old magic.mime that came with the original installation package didn't. I've tried Googling for magic.mime updates to no avail...

    Any clues to what is wrong are welcome!!!

    Cheers

      I have not worked with it and don't know anything about it other than what's in the manual page for [man]mime_content_type[/man], which says that it is deprecated and that you should instead use the fileinfo PECL extension.

        I reckon no one else knows how to get this magic.mime to work on a win32 machine? I find there is zero to none information on mime_content_type()... and find it very hard to figure out what is going wrong!?!?

          I have tried both fileinfo PECL and mime_content_type
          and did not get anyone to work.
          🙁

            It turns out that this PEAR Class primary tries to use
            if (function_exists('mime_content_type')) {
            $type = mime_content_type($file);

            function autoDetect($file, $params = false)
                {
                    @include_once 'System/Command.php';
                    if (function_exists('mime_content_type')) {
                        $type = mime_content_type($file);
                    } else if (class_exists('System_Command')) {
                        $type = MIME_Type::_fileAutoDetect($file);
                    } else {
                        return PEAR::raiseError("Sorry, can't autodetect; you need the mime_magic extension or System_Command and 'file' installed to use this function.");
                    }

            About [man]fileinfo[/man].
            I did LoadModule php_fileinfo.dll

            Now there is much trouble to get it to work.
            This you can find out by searching with google.
            It has to do with getting fileinfo to find and accept the reference file as valid.
            The file is /php/extras/magic.mime or /usr/share/misc/magic

            In fact I didnt get [man]fileinfo[/man] to work without error.
            I tried some examples found at php.net and in other internet discussions.

            If anyone get it to work in some way:
            Please let me know!
            thanks

            This is how it should work, accoording to www.php.net

            <?php
            
            // return mime type ala mimetype extension
            $finfo = new finfo(FILEINFO_MIME, "/usr/share/misc/magic"); 
            
            if (!$finfo) {
                echo "Opening fileinfo database failed";
                exit();
            }
            
            
            // note: must be REALPATH
            $filename = "/usr/local/something.txt";
            // echo mime type
            echo $finfo->file($filename);
            
            /* close connection */
            $finfo->close();
            
            ?>

              Hi Halojoy,

              U might want to check out this.

              I haven't yet tested it as I really want mime_content_type() to work... it is a PHP function so it should work goshdarnit!@!!!@#@#$

                Hendricus wrote:

                Hi Halojoy,

                U might want to check out this.

                I haven't yet tested it as I really want mime_content_type() to work... it is a PHP function so it should work goshdarnit!@!!!@#@#$

                thanks, I will check your link.


                I have been at this case now, for several hours!
                And I have gotten [man]fileinfo[/man] to work.
                But boy!, it was a lot of searching and fixing bugs. That php_fileinfo.dll is far from debugged, yet.

                First, I am on Windows XP, running Apache 2.2.6 (latest) and PHP 5.2.4.

                In the script below, I have created my own get_mime() function.
                As you can see it uses finfo = [man]fileinfo[/man]

                I have created 7 testfiles.
                Only the first & the last have correct extensions. One .php & one .pdf
                The beginning tells real type:
                html_faked.pdf ... means a HTML file with .pdf extension
                after ........ comes the return from my get_mime() function
                Output:

                php_real.php .... application/x-httpd-php
                php_faked.pdf .... application/x-httpd-php
                html_faked.pdf .... text/html
                txt_faked.pdf .... text/plain; charset=us-ascii
                jpg_faked.pdf .... image/jpeg
                rar_faked.pdf .... application/x-rar
                pdf_real.pdf .... application/pdf

                Here is my code:

                <?php
                
                function get_mime( $file ){
                    // my path:    mime_magic.magicfile = "c:/php/extras/magic"
                    $finfo = finfo_open(FILEINFO_MIME,ini_get('mime_magic.magicfile'));
                    if(!$finfo) exit( "Opening fileinfo database failed" );
                    $mime_type = finfo_file($finfo, realpath($file));
                    finfo_close($finfo);
                    return $mime_type;
                }
                
                $file = 'php_real.php';
                echo $file.' .... '.get_mime( $file ).'<br />';
                $file = 'php_faked.pdf';
                echo $file.' .... '.get_mime( $file ).'<br />';
                $file = 'html_faked.pdf';
                echo $file.' .... '.get_mime( $file ).'<br />';
                $file = 'txt_faked.pdf';
                echo $file.' .... '.get_mime( $file ).'<br />';
                $file = 'jpg_faked.pdf';
                echo $file.' .... '.get_mime( $file ).'<br />';
                $file = 'rar_faked.pdf';
                echo $file.' .... '.get_mime( $file ).'<br />';
                $file = 'pdf_real.pdf';
                echo $file.' .... '.get_mime( $file ).'<br />';
                
                exit();
                ?>
                  Write a Reply...