61

When I use XMLHttpRequest, a file is correctly uploaded using FormData. However, when I switch to jQuery.ajax, my code breaks.

This is the working original code:

function uploadFile(blobFile, fileName) {
    var fd = new FormData();
    fd.append("fileToUpload", blobFile);
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "upload.php", true);
    xhr.send(fd);
}

Here is my unsuccessful jQuery.ajax attempt:

function uploadFile(blobFile, fileName) {
    var fd = new FormData();
    fd.append("fileToUpload", blobFile);
    var xm = $.ajax({
        url: "upload.php",
        type: "POST",
        data: fd,
    });
}

What am I doing wrong? How can I get the file to be uploaded correctly, using AJAX?

Rob W
  • 341,306
  • 83
  • 791
  • 678
Harts
  • 4,023
  • 9
  • 54
  • 93

2 Answers2

173

You have to add processData:false,contentType:false to your method, so that jQuery does not alter the headers or data (which breaks your current code).

function uploadFile(blobFile, fileName) {
    var fd = new FormData();
    fd.append("fileToUpload", blobFile);

    $.ajax({
       url: "upload.php",
       type: "POST",
       data: fd,
       processData: false,
       contentType: false,
       success: function(response) {
           // .. do something
       },
       error: function(jqXHR, textStatus, errorMessage) {
           console.log(errorMessage); // Optional
       }
    });
}  
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • 7
    I'd upvote this 1000 times if i could. Out of all the other answers to this question on SO, this one worked the best and is the simplest. thanks. – sqram Dec 03 '12 at 19:16
  • 6
    Warning: FormData is not supported in IE until version 10. – Scott D. Strader Oct 15 '13 at 15:48
  • 6
    In this answer (and question), what is `blobFile`? Is it an input.val()? –  Jul 16 '14 at 20:29
  • 10
    @tmyie It is a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) or [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) object, e.g. for `` it is `document.getElementById('filechooser').files[0]` (provided that the user has selected a file). (in jQuery, `$('#filechooser')[0].files[0]`) – Rob W Jul 16 '14 at 20:39
  • @ScottD.Strader f$%#@ IE 9 and 8, they are only stopping the progress... :D – ncubica Nov 19 '14 at 01:25
  • Please, and if I want to send another data too, like string fields, how this should word? – MarceloBarbosa Feb 10 '15 at 14:50
  • 3
    @MarceloBarbosa `fd.append('field_name', 'string_field_value');` - see https://developer.mozilla.org/en-US/docs/Web/API/FormData – Rob W Feb 10 '15 at 14:57
  • lets say you have successfully send the file through ajax how would you retrieve it in the php file if for example like this how can you get this in the upload.php?how can you insert it? – Brownman Revival Apr 14 '15 at 07:15
  • @HogRider `$_FILES['fileToUpload']`, as usual. This is not different from a normal form submission. – Rob W Apr 14 '15 at 07:50
  • @RobW, do you know how to set in the "fd" the Content-Type (image/jpeg) ? Thanks. – OrMoush May 11 '15 at 13:40
  • @Or9400 The fd's content type? I guess that you meant setting the MIME-type of the file? You can change the MIME-type of a `File` using the [`Blob` constructor](https://developer.mozilla.org/en-US/docs/Web/API/Blob). For example, if you want to force the `image/jpeg` MIME-type for the file in the example, use `blobFile = new Blob([blobFile],{type:'image/jpeg'});` before `fd.append`. – Rob W May 11 '15 at 13:43
  • 1
    @RobW, It's was like this, my problem was the order of the S3 fields. ' fd.append('acl', 'public-read-write'); fd.append('key', fileName); fd.append('Content-Type', file.type); fd.append("file", file); ' Thanks. – OrMoush May 11 '15 at 14:51
  • Is there any way to change MIME type of filies while sending files to server in ajax call? – Jaimin Dave Oct 26 '16 at 12:12
  • 1
    @Jaimin The Blob constructor takes a "type" parameter that specifies the MIME-type. See my content above from 11 May 2015. – Rob W Oct 26 '16 at 18:02
  • I have a problem when the file is bigger than 10MB. Does any one know why? – NIDIA RAMIREZ Jan 11 '19 at 23:07
  • can you check your answer cause I don't see where the parameter `fileName` is applicable inside the function. Maybe a bug or a typo? – João Pimentel Ferreira Jun 10 '20 at 23:29
  • @JoãoPimentelFerreira `fileName` came from the code snippet in the original question. If you want to preserve the file name, use `fd.append("fileToUpload", blobFile, fileName);`. – Rob W Jun 14 '20 at 17:00
  • @RobW just saying that the function as it is written it's not clear, cause that parameter is redundant. I would edit it to introduce that line of code you just referred – João Pimentel Ferreira Jun 15 '20 at 08:52
0

If you are uploading from a HTML5 form that includes an input fo type file you can just use querySelector and FormData and it works.

In case of php it will give you all files in the $_FILE and all other inputs in the $_POST array.

JS/jQuery:

function safeFormWithFile()
{
  var fd = new FormData(document.querySelector('#myFormName'));

  $.ajax({
        url:'/catchFormData.php',
        method:'POST',
        data:fd,
        processData: false,
        contentType: false,
        success:function(data){
          console.log(data);
        }
  });
}

HTML:

<form id="myFormName">
  <input id="myImage" name="myImage" type="file">
  <input id="myCaption" name="myCaption" type="text">
</form>
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Max
  • 2,561
  • 1
  • 24
  • 29