10

I have an input where you can upload images, the only allowed images types are:

png, jpg, jpeg

before the image is inserted to the database it checks if the pictures are png,jpg,jpeg. But now for security reasons I need to check the mime type before or after the first check.

How do I do this? This is my code:

<?php

$iAmountOfFiles = count($_FILES['Filename']['name']);

while($iAmountOfFiles >= 1) {

    $iAmountOfFiles--;

    $aFileProperties = pathinfo($_FILES['Filename']['name'][$iAmountOfFiles]);
    if(!in_array(strtolower($aFileProperties["extension"]), $aExtensionWhitelist)) {
        echo "Bestands type niet toegestaan";
        // exit;
        continue;
    }

    $sTarget = ROOT.BACKEND."/pages/bezienswaardigheden-toevoegen/uploads/";
    $sUniqueFileNameHash = hash('adler32', time().rand());
    $Filename = basename($sUniqueFileNameHash."-".$_FILES['Filename']['name'][$iAmountOfFiles]);
    $Filename = basename($aFileProperties["filename"]."-".$sUniqueFileNameHash.".".strtolower($aFileProperties["extension"]));

    // Writes the Filename to the server
    if(move_uploaded_file($_FILES['Filename']['tmp_name'][$iAmountOfFiles], $sTarget.$Filename)) {

    // here needs to come the mime check
unclexo
  • 3,691
  • 2
  • 18
  • 26
emmea
  • 113
  • 1
  • 1
  • 6
  • Please go read [ask]. You are expected to actually put in some effort yourself first, before you come asking here. Your question currently gives no indication whatsoever that you actually tried though, you basically just dropped off your requirement here. A plain _“How do i do this?”_ is not an appropriate way to ask here. We are not here so that you can just outsource any research to us. – 04FS Jan 30 '20 at 12:46
  • Does this answer your question? [Getting mime type from file name in php](https://stackoverflow.com/questions/35299457/getting-mime-type-from-file-name-in-php) – Martin Apr 04 '20 at 08:15
  • here; `$result = new finfo();print $result->file($filename, FILEINFO_MIME_TYPE);` – Martin Apr 04 '20 at 08:20

3 Answers3

26

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.

unclexo
  • 3,691
  • 2
  • 18
  • 26
  • `move_uploaded_file` will also check for valid upload file. From the [docs](https://www.php.net/manual/en/function.move-uploaded-file.php) ..."If filename is not a valid upload file, then no action will occur, and `move_uploaded_file()` will return `FALSE`." – Fahmi Jan 30 '20 at 17:45
  • @Fahmi Yes it does! But it is always a good practice using `is_uploaded_file()` before going for `move_uploaded_file()` to upload the file. Because it makes sure any malicious user hasn't tried to trick the script executing the file being uploaded. – unclexo Jan 30 '20 at 18:09
3

you can get mime type by file content:

public static function getMimeTypeFromFileContent(string &$content): string
{
    return (new finfo(FILEINFO_MIME_TYPE))->buffer($content);
}

file content you can get by $content = file_get_contents($pathToFile);

1

Using above simple [ you can say bigger one ] function, you can extract or get the mime type of a file or you can say content.

But before, for using this function you might have need done some pre-configuration,

Like you have to sure that you turned or configured curl extension, filesystem releted extension and finfo extension in php.ini file.

Here, I am describing the whole process of this function in a short.

  1. First, we are storing all the updated mime type as an array from official apache mime type url.

You can also get this mime type file in your apache conf directory insted of using url. In this function we are using live url to get all the mime type.

  1. But the zeroth process for this function is to validate that apache url is live or not.

  2. After validating the url, if the url is validated [ means live ], we store all mimes from that url as an array called $mimes

If the url isn't live or exist we are manually making an array with some common extension available.

  1. Then we validate the content as file.

  2. Then we check the PHP pathinfo function to insure that is there any file extension or not. If there, store it.

  3. After that we checking the $mimes array with our content extension as $mimes array index.

  4. Finally we are returning the index value of $mimes array as content mime type through $content_mime variable.

That's it.

<?php
    /**
     * **get_content_mime_type
     *
     * @param  string $content, the content or the file whose mime type you want to know.
     * @return string
     */
    function get_content_mime_type($content)
    {
        $url = 'http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types';
        $url_live = false;
        $handle = curl_init($url);
        curl_setopt_array($handle, array(
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_NOBODY => true,
            CURLOPT_HEADER => false,
            CURLOPT_RETURNTRANSFER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_SSL_VERIFYPEER => false
        ));
        $response = curl_exec($handle);
        $httpCode = curl_getinfo($handle, CURLINFO_EFFECTIVE_URL);
        $httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
        if ($httpCode == 200)
        {
            $url_live = true;
        }
        $url_live = $url_live;
        curl_close($handle);
        $mimes = array();
        if ($url_live)
        {
            $mimes_file = file_get_contents($url);
            preg_match_all('#^([^\s]{2,}?)\s+(.+?)$#ism', $mimes_file, $matches, PREG_SET_ORDER);
            foreach ($matches as $match)
            {
                $exts = explode(" ", $match[2]);
                foreach ($exts as $ext)
                {
                    $mimes[$ext] = $match[1];
                }
            }
        }
        else
        {
            $mimes = array(
                'txt' => 'text/plain',
                'htm' => 'text/html',
                'html' => 'text/html',
                'php' => 'text/html',
                'css' => 'text/css',
                'js' => 'application/javascript',
                'json' => 'application/json',
                'xml' => 'application/xml',
                'swf' => 'application/x-shockwave-flash',
                'flv' => 'video/x-flv',
                // images
                'png' => 'image/png',
                'jpe' => 'image/jpeg',
                'jpeg' => 'image/jpeg',
                'jpg' => 'image/jpeg',
                'gif' => 'image/gif',
                'bmp' => 'image/bmp',
                'ico' => 'image/vnd.microsoft.icon',
                'tiff' => 'image/tiff',
                'tif' => 'image/tiff',
                'svg' => 'image/svg+xml',
                'svgz' => 'image/svg+xml',
                // archives
                'zip' => 'application/zip',
                'rar' => 'application/x-rar-compressed',
                'exe' => 'application/x-msdownload',
                'msi' => 'application/x-msdownload',
                'cab' => 'application/vnd.ms-cab-compressed',
                // audio/video
                'mp3' => 'audio/mpeg',
                'qt' => 'video/quicktime',
                'mov' => 'video/quicktime',
                // adobe
                'pdf' => 'application/pdf',
                'psd' => 'image/vnd.adobe.photoshop',
                'ai' => 'application/postscript',
                'eps' => 'application/postscript',
                'ps' => 'application/postscript',
                // ms office
                'doc' => 'application/msword',
                'rtf' => 'application/rtf',
                'xls' => 'application/vnd.ms-excel',
                'ppt' => 'application/vnd.ms-powerpoint',
                'docx' => 'application/msword',
                'xlsx' => 'application/vnd.ms-excel',
                'pptx' => 'application/vnd.ms-powerpoint',
                // open office
                'odt' => 'application/vnd.oasis.opendocument.text',
                'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
            );
        }
        $content_mime = 'unknown';
        if (is_file($content))
        {
            if (isset(pathinfo($content) ['extension']))
            {
                $content_ext = pathinfo($content) ['extension'];
                if (isset($mimes[$content_ext]))
                {
                    $content_mime = $mimes[$content_ext];
                }
                else
                {
                    if (is_readable($content) && is_executable($content))
                    {
                        $finfo = finfo_open(FILEINFO_MIME_TYPE);
                        $content_mime = finfo_file($finfo, $content);
                        if ($content_mime === null | $content_mime === "")
                        {
                            $content_mime = "application/octet-stream";
                        }
                        else
                        {
                            $content_mime = $content_mime;
                        }
                        finfo_close($finfo);
                    }
                    else
                    {
                        $content_mime = "application/octet-stream";
                    }
                }
            }
        }
        else
        {
            // return whatever you want
            // $content_mime = 'unknown';
            
        }
        $content_mime = $content_mime;
        return $content_mime;
    }
    ?>