66

I check the file extension for upload or not uploaded. My example methods worked, but now I need to understand if my methods (using pathinfo) is true. Is there another better and faster way?

$filename = $_FILES['video_file']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if ($ext !== 'gif' || $ext !== 'png' || $ext !== 'jpg') {
    echo 'error';
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
BBKing
  • 2,279
  • 8
  • 38
  • 44
  • 11
    why is the filed called 'video_file' yet you're only allowing images.. – cream May 06 '13 at 07:53
  • 4
    I found this question looking for valid file extensions. I'm not answering the question here, but I'd like to indicate that you have a logic error in in your if statement. It must be `&&` between the conditions and not `||`... Just thought I'd share my view. – itsols Sep 13 '16 at 03:39
  • I recommend using **Reza S**'s solution. and if dealing with images I also suggest using `getimagesize` php function to detect if the file is actually an image. returns false if image not detected. – Hike Nalbandyan Mar 21 '19 at 12:51

10 Answers10

168

Using if( $ext !== 'gif') might not be efficient. What if you allow like 20 different extensions?

Try:

$allowed = array('gif', 'png', 'jpg');
$filename = $_FILES['video_file']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if (!in_array($ext, $allowed)) {
    echo 'error';
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Baba
  • 94,024
  • 28
  • 166
  • 217
  • I was uploading a filename with capitals (DOG.JPG), so I had to add $filename = strtolower($filename); – Mikeys4u Sep 14 '16 at 15:39
  • @Baba Hello sir, how can we do this in the multiple file upload.? and i also get the error on $ext it mean i cannot get my file extension from this code. what should i do? – always-a-learner Jan 16 '17 at 06:24
  • 1
    Re *"efficient"*: Do you mean *"[sufficient](https://en.wiktionary.org/wiki/sufficient#Adjective)"*? – Peter Mortensen Nov 30 '19 at 15:55
  • 1
    This procedure is not safe. A user could rename a dangerous file as jpg and save it to the server. To make sure that only pictures are uploaded that can be processed as expected, I would recommend checking for the MimeType. (See other solution below: https://stackoverflow.com/a/10456149/2320007) – Sarah Trees Dec 02 '20 at 10:37
69

Checking the file extension is not considered best practice. The preferred method of accomplishing this task is by checking the files MIME type.

From PHP:

<?php
    $finfo = finfo_open(FILEINFO_MIME_TYPE); // Return MIME type
    foreach (glob("*") as $filename) {
        echo finfo_file($finfo, $filename) . "\n";
    }
    finfo_close($finfo);
?>

The above example will output something similar to which you should be checking.

text/html
image/gif
application/vnd.ms-excel

Although MIME types can also be tricked (edit the first few bytes of a file and modify the magic numbers), it's harder than editing a filename. So you can never be 100% sure what that file type actually is, and care should be taken about handling files uploaded/emailed by your users.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Reza S
  • 9,480
  • 3
  • 54
  • 84
  • 4
    I almost doubt there is a way to get the REAL file extension. Everywhere there are answers "to analyze filename" which is the worst way... Thanks a lot for this answer! – instead Sep 24 '13 at 17:23
  • 2
    This answer should be at the top, it's very easy for someone to change a file extension! – Talk nerdy to me Feb 26 '16 at 03:23
  • What you suggest if the MIME is fake one ? A malicious user can easily upload files using a script or some other automated application that allows sending of HTTP POST requests, which allow him to send a fake mime-type. – Prafulla Kumar Sahu Jun 24 '16 at 09:31
  • 3
    @PrafullaKumarSahu You can find a detailed answer to your question here: http://stackoverflow.com/a/8028436/196917 – Reza S Jun 24 '16 at 20:07
  • 1
    I found a better resource may be this link will be removed in future but for now it seems to be a great one. https://www.acunetix.com/websitesecurity/upload-forms-threat/ – Prafulla Kumar Sahu Jun 27 '16 at 05:22
  • 2
    I presume that BBKing is also looking for a way to prevent webshells being uploaded. A mime type is easily changed in a HTTP request. Checking the extension is a better (although not ideal) approach since files without the correct extensions will not be executable. Check the OWASP resource on this: • https://www.owasp.org/index.php/Unrestricted_File_Upload – Silver Jan 30 '19 at 18:27
14

Personally,I prefer to use preg_match() function:

if(preg_match("/\.(gif|png|jpg)$/", $filename))

or in_array()

$exts = array('gif', 'png', 'jpg'); 
if(in_array(end(explode('.', $filename)), $exts)

With in_array() can be useful if you have a lot of extensions to validate and perfomance question. Another way to validade file images: you can use @imagecreatefrom*(), if the function fails, this mean the image is not valid.

For example:

function testimage($path)
{
   if(!preg_match("/\.(png|jpg|gif)$/",$path,$ext)) return 0;
   $ret = null;
   switch($ext)
   {
       case 'png': $ret = @imagecreatefrompng($path); break;
       case 'jpeg': $ret = @imagecreatefromjpeg($path); break;
       // ...
       default: $ret = 0;
   }

   return $ret;
}

then:

$valid = testimage('foo.png');

Assuming that foo.png is a PHP-script file with .png extension, the above function fails. It can avoid attacks like shell update and LFI.

Jack
  • 16,276
  • 55
  • 159
  • 284
6

pathinfo is cool but your code can be improved:

$filename = $_FILES['video_file']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
$allowed = array('jpg','png','gif');
if( ! in_array( $ext, $allowed ) ) {echo 'error';}

Of course simply checking the extension of the filename would not guarantee the file type as a valid image. You may consider using a function like getimagesize to validate uploaded image files.

Varol
  • 1,798
  • 1
  • 22
  • 30
4

file type can be checked in other ways also. I believe this is the easiest way to check the uploaded file type.. if u are dealing with an image file then go for the following code. if you are dealing with a video file then replace the image check with a video check in the if block.. have fun

     $img_up = $_FILES['video_file']['type'];
$img_up_type = explode("/", $img_up);
$img_up_type_firstpart = $img_up_type[0];

if($img_up_type_firstpart == "image") { // image is the image file type, you can deal with video if you need to check video file type

/* do your logical code */ }

maazza
  • 7,016
  • 15
  • 63
  • 96
priyam
  • 71
  • 6
  • $_FILES['field_name']['type'] is a user defined and therefore should not be relied upon for validation. You should use php's exif_imagetype or getimagesize function to check details / type of your image. – dading84 Oct 27 '16 at 10:40
3

To properly achieve this, you'd be better off by checking the mime type.

function get_mime($file) {
  if (function_exists("finfo_file")) {
    $finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
    $mime = finfo_file($finfo, $file);
    finfo_close($finfo);
    return $mime;
  } else if (function_exists("mime_content_type")) {
    return mime_content_type($file);
  } else if (!stristr(ini_get("disable_functions"), "shell_exec")) {
    // http://stackoverflow.com/a/134930/1593459
    $file = escapeshellarg($file);
    $mime = shell_exec("file -bi " . $file);
    return $mime;
  } else {
    return false;
  }
}
//pass the file name as
echo(get_mime($_FILES['file_name']['tmp_name']));
Rotimi
  • 4,783
  • 4
  • 18
  • 27
2

Not sure if this would have a faster computational time, but another option...

$acceptedFormats = array('gif', 'png', 'jpg');

if(!in_array(pathinfo($filename, PATHINFO_EXTENSION), $acceptedFormats))) {
    echo 'error';
}
liz
  • 830
  • 14
  • 32
1

i think this might work for you

//<?php
    //checks file extension for images only
    $allowed =  array('gif','png' ,'jpg');
    $file = $_FILES['file']['name'];
    $ext = pathinfo($file, PATHINFO_EXTENSION);
        if(!in_array($ext,$allowed) ) 
            { 
//?>
<script>
       alert('file extension not allowed');
       window.location.href='some_link.php?file_type_not_allowed_error';
</script>

//<?php
exit(0);
    }
//?>
0

How to validate file extension (jpg/jpeg only) on a form before upload takes place. A variation on another posted answer here with an included data filter which may be useful when evaluating other posted form values. Note: error is left blank if empty as this was an option for my users, not a requirement.

<?php
if(isset($_POST['save'])) {

//Validate image
if (empty($_POST["image"])) {
$imageError = "";
} else {
$image = test_input($_POST["image"]);
$allowed =  array('jpeg','jpg');
$ext = pathinfo($image, PATHINFO_EXTENSION);
if(!in_array($ext,$allowed) ) {
$imageError = "jpeg only";
}
}

}

// Validate data
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
<?

Your html will look something like this;

<html>
<head>
</head>

<body>
<!-- Validate -->
<?php include_once ('validate.php'); ?>

<!-- Form -->
<form method="post" action="">

<!-- Image -->
<p>Image <?php echo $imageError; ?></p>
<input type="file" name="image" value="<?php echo $image; ?>" />

<p><input type="submit" name="save" value="SAVE" /></p>
</form>

</body>
</html>
-2

use this function

 function check_image_extension($image){

        $images_extentions = array("jpg","JPG","jpeg","JPEG","png","PNG");

        $image_parts = explode(".",$image);

        $image_end_part = end($image_parts);

        if(in_array($image_end_part,$images_extentions ) == true){

            return time() . "." . $image_end_part;


        }else{

            return false;
        }


    }
Sajjad Asaad
  • 71
  • 1
  • 4