Sending multipart/formdata with jQuery.ajax

ajax, file-upload, form-data, jquery, multipartform-data

Solution

Starting with Safari 5/Firefox 4, it’s easiest to use the `FormData` class:

var data = new FormData();
jQuery.each(jQuery('#file')[0].files, function(i, file) {
    data.append('file-'+i, file);
});

So now you have a `FormData` object, ready to be sent along with the XMLHttpRequest.

jQuery.ajax({
    url: 'php/upload.php',
    data: data,
    cache: false,
    contentType: false,
    processData: false,
    method: 'POST',
    type: 'POST', // For jQuery < 1.9
    success: function(data){
        alert(data);
    }
});

It’s imperative that you set the `contentType` option to `false`, forcing jQuery not to add a `Content-Type` header for you, otherwise, the boundary string will be missing from it. Also, you must leave the `processData` flag set to false, otherwise, jQuery will try to convert your `FormData` into a string, which will fail.

You may now retrieve the file in PHP using:

$_FILES['file-0']

(There is only one file, `file-0`, unless you specified the `multiple` attribute on your file input, in which case, the numbers will increment with each file.)

Using the FormData emulation for older browsers

var opts = {
    url: 'php/upload.php',
    data: data,
    cache: false,
    contentType: false,
    processData: false,
    method: 'POST',
    type: 'POST', // For jQuery < 1.9
    success: function(data){
        alert(data);
    }
};
if(data.fake) {
    // Make sure no text encoding stuff is done by xhr
    opts.xhr = function() { var xhr = jQuery.ajaxSettings.xhr(); xhr.send = xhr.sendAsBinary; return xhr; }
    opts.contentType = "multipart/form-data; boundary="+data.boundary;
    opts.data = data.toString();
}
jQuery.ajax(opts);

Create FormData from an existing form

Instead of manually iterating the files, the FormData object can also be created with the contents of an existing form object:

var data = new FormData(jQuery('form')[0]);

Use a PHP native array instead of a counter

Just name your file elements the same and end the name in brackets:

jQuery.each(jQuery('#file')[0].files, function(i, file) {
    data.append('file[]', file);
});

`$_FILES['file']` will then be an array containing the file upload fields for every file uploaded. I actually recommend this over my initial solution as it’s simpler to iterate over.

Problem

I've got a problem sending a file to a serverside PHP-script using jQuery's ajax function. It's possible to get the File-List with `$('#fileinput').attr('files')` but how is it possible to send this Data to the server? The resulting array (`$_POST`) on the server side php-script is 0 (`NULL`) when using the file-input. I know it is possible (though I didn't find any jQuery solutions until now, only Prototye code (http://webreflection.blogspot.com/2009/03/safari-4-multiple-upload-with-progress.html)). This seems to be relatively new, so please do not mention file upload would be impossible via XHR/Ajax, because it's definitely working. I need the functionality in Safari 5, FF and Chrome would be nice but are not essential. My code for now is: ``` $.ajax({ url: 'php/upload.php', data: $('#file').attr('files'), cache: false, contentType: 'multipart/form-data', processData: false, type: 'POST', success: function(data){ alert(data); } }); ```

Original source

Related problems