49

I am uploading a file in php and only want to upload it if it's a csv file. I believe my syntax is right for the content type. It always goes to else statement when it's a csv file. What I am doing wrong here?

if (($_FILES["file"]["type"] == "text/csv"))
{

}
else
{

}

If I change the content type it works for that format just not csv.

theking963
  • 2,035
  • 6
  • 25
  • 40
  • 7
    $_FILES["file"]["type"] should never be relied upon for file type verification. also, it doesn't seem that there could be a real way to verify that a file is actually a csv file. – dqhendricks Jul 11 '11 at 18:13
  • http://os-code-web.blogspot.com/2011/04/15-top-php-coding-tutorials-tips-and.html – Jagan Chennai Jul 11 '11 at 18:32
  • 2
    I always validate the content of the incoming file rather than relying on the MIME type. – Rafe Jul 11 '11 at 19:41
  • Only trusted users will be using this site so content validation is something I don't need right now. I just want to make sure they don't upload some other file by mistake. When it is required I will branch out and do a content validation. – theking963 Jul 11 '11 at 20:17

7 Answers7

82

the mime type might not be text/csv some systems can read/save them different. (for example sometimes IE sends .csv files as application/vnd.ms-excel) so you best bet would be to build an array of allowed values and test against that, then find all possible values to test against.

$mimes = array('application/vnd.ms-excel','text/plain','text/csv','text/tsv');
if(in_array($_FILES['file']['type'],$mimes)){
  // do something
} else {
  die("Sorry, mime type not allowed");
}

if you wished you could add a further check if mime is returned as text/plain you could run a preg_match to make sure it has enough commas in it to be a csv.

Czechnology
  • 14,253
  • 9
  • 58
  • 83
Alan Cole
  • 1,665
  • 12
  • 13
  • 8
    I've had to add "application/octet-stream" to the array in order to validate my csv file (exported from GMail contacts) – Marco Panichi Oct 24 '13 at 11:29
  • 3
    You should always check the content, this method could easily fail when a file is actually a csv but has some strange mime type like application/x-msdownload. CSV can be application/x-msdownload, but XLS can also, so this is bad. – Mfoo Jan 06 '14 at 15:31
  • Take a look at this post http://stackoverflow.com/questions/2450345/how-to-validate-csv-file – Mfoo Jan 06 '14 at 15:40
  • 7
    -1. This code is wrong. It depends on what the user's browser thinks is the correct MIME type of a file name ending in .csv. Also, if the user renames a .jpeg to end in .csv, this code will still allow it as valid. For a quick sanity check as per the asker's comment (Ie. that the user didn't accidentally select the wrong file), it is far simpler to check the file name extension. To see if the CSV file is valid for your application, attempt to process the CSV file as per your application's rules; if it fails, it's not valid. – Ashley Ross Jul 26 '15 at 09:59
  • This code would not work if you rename a `txt` file as a `csv` and then upload the file – Rahul Gupta Feb 05 '18 at 12:55
39

There are a lot of possible MIME types for CSV files, depending on the user's OS and browser version.

This is how I currently validate the MIME types of my CSV files:

$csv_mimetypes = array(
    'text/csv',
    'text/plain',
    'application/csv',
    'text/comma-separated-values',
    'application/excel',
    'application/vnd.ms-excel',
    'application/vnd.msexcel',
    'text/anytext',
    'application/octet-stream',
    'application/txt',
);

if (in_array($_FILES['upload']['type'], $csv_mimetypes)) {
    // possible CSV file
    // could also check for file content at this point
}
ukliviu
  • 3,028
  • 1
  • 21
  • 30
  • 3
    `text/plain` would also allow a .txt file upload – Slimshadddyyy Jun 26 '15 at 06:31
  • 6
    -1. This code is wrong. It depends on what the user's browser thinks is the correct MIME type of a file name ending in .csv. Also, if the user renames a .jpeg to end in .csv, this code will still allow it as valid. To see if the CSV file is valid for your application, attempt to process the CSV file as per your application's rules; if it fails, it's not valid. – Ashley Ross Jul 26 '15 at 10:00
  • 1
    Old thread, but wanted to add one spreadsheet mime from OpenOffice. 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' – vanarie Jan 23 '17 at 15:27
8

You can't always rely on MIME type..

According to: http://filext.com/file-extension/CSV

text/comma-separated-values, text/csv, application/csv, application/excel, application/vnd.ms-excel, application/vnd.msexcel, text/anytext

There are various MIME types for CSV.

Your probably best of checking extension, again not very reliable, but for your application it may be fine.

$info = pathinfo($_FILES['uploadedfile']['tmp_name']);

if($info['extension'] == 'csv'){
 // Good to go
}

Code untested.

Eddie
  • 12,021
  • 3
  • 23
  • 30
  • 5
    I would think you would check againsts `$_FILES['uploadedfile']['name']` vs. `tmp_name` as tmp_name is the temporary file name on the server. At least in my case, the tmp_name does not include the original file extension. – JJ. Oct 22 '13 at 18:54
  • $extension = pathinfo($_FILES['csvFileRep']['name'], \PATHINFO_EXTENSION); – Vipul Sep 20 '16 at 20:01
7

As you are worried about user upload other file by mistake, I would suggest you to use accept=".csv" in <input> tag. It will show only csv files in browser when the user uploads the file. If you have found some better solution then please let me know as I am also trying to do same and in the same condition - 'trusted users but trying to avoid mistake'

Bhavesh Garg
  • 91
  • 1
  • 3
5

So I ran into this today.

Was attempting to validate an uploaded CSV file's MIME type by looking at $_FILES['upload_file']['type'], but for certain users on various browsers (and not necessarily the same browsers between said users; for instance it worked fine for me in FF but for another user it didn't work on FF) the $_FILES['upload_file']['type'] was coming up as "application/vnd.ms-excel" instead of the expected "text/csv" or "text/plain".

So I resorted to using the (IMHO) much more reliable finfo_* functions something like this:

$acceptable_mime_types = array('text/plain', 'text/csv', 'text/comma-separated-values');

if (!empty($_FILES) && array_key_exists('upload_file', $_FILES) && $_FILES['upload_file']['error'] == UPLOAD_ERR_OK) {
    $tmpf = $_FILES['upload_file']['tmp_name'];

    // Make sure $tmpf is kosher, then:

    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mime_type = finfo_file($finfo, $tmpf);

    if (!in_array($mime_type, $acceptable_mime_types)) {
        // Unacceptable mime type.
    }
}
Garvin
  • 374
  • 4
  • 7
3

Mime type option is not best option for validating CSV file. I used this code this worked well in all browser

$type = explode(".",$_FILES['file']['name']);
if(strtolower(end($type)) == 'csv'){

}
else
{

}
Vaibhav Shahu
  • 364
  • 4
  • 14
-3

simple use "accept" and "required" in and avoiding so much typical and unwanted coding.

  • how about your server-side logic to check the user input ? or maybe you don't do backend validation at all ? – erwan Jan 11 '18 at 13:28