115
var fd = new FormData();
fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
var xhr = new XMLHttpRequest();
xhr.open("POST", "uph.php");
xhr.send(fd);

uph.php:

var_dump($_FILES['fileToUpload']);

This works, but obviously for the files[0] only. How to get this working for chosen file?

I tried removing the [0], but it didn't work.

Alexis Pigeon
  • 7,223
  • 11
  • 38
  • 44
jaanisk
  • 1,151
  • 2
  • 7
  • 4

15 Answers15

126

You have to get the files length to append in JS and then send it via AJAX request as below

//JavaScript 
var ins = document.getElementById('fileToUpload').files.length;
for (var x = 0; x < ins; x++) {
    fd.append("fileToUpload[]", document.getElementById('fileToUpload').files[x]);
}

//PHP
$count = count($_FILES['fileToUpload']['name']);
for ($i = 0; $i < $count; $i++) {
    echo 'Name: '.$_FILES['fileToUpload']['name'][$i].'<br/>';
}
T30
  • 10,276
  • 6
  • 47
  • 57
Rowan San
  • 1,299
  • 1
  • 8
  • 8
  • 1
    Didn't work for me. I guess it depends on how your multipart form will handled server sided. –  Dec 13 '15 at 01:35
  • 31
    [According to MDN `As with regular form data, you can append multiple values with the same name. For example (and being compatible with PHP's naming conventions by adding [] to the name):`. See Example 3](https://developer.mozilla.org/en-US/docs/Web/API/FormData/append) @Phoenix – 0xcaff Nov 25 '16 at 07:04
  • only returns one file – Žilvinas Jan 28 '19 at 21:07
  • 1
    `fileToUpload[]` is wrong, should be `fileToUpload` – Houssem Badri Nov 23 '20 at 17:40
  • @HoussemBadri in my case `fileToUpload` doesn't work. it should be `fileToUpload[]` as suggested in the answer. Your comment cost me an hour to find out what's going on. – Andre W. May 26 '21 at 15:02
  • @UXAndre sorry for that but, I commented based on my real case – Houssem Badri May 26 '21 at 16:59
90

The way to go with javascript:

var data = new FormData();

$.each($("input[type='file']")[0].files, function(i, file) {
    data.append('file', file);
});

$.ajax({
    type: 'POST',
    url: '/your/url',
    cache: false,
    contentType: false,
    processData: false,
    data : data,
    success: function(result){
        console.log(result);
    },
    error: function(err){
        console.log(err);
    }
})

If you call data.append('file', file) multiple times your request will contain an array of your files.

From MDN web docs:

"The append() method of the FormData interface appends a new value onto an existing key inside a FormData object, or adds the key if it does not already exist. The difference between FormData.set and append() is that if the specified key already exists, FormData.set will overwrite all existing values with the new one, whereas append() will append the new value onto the end of the existing set of values."

Myself using node.js and multipart handler middleware multer get the data as follows:

router.post('/trip/save', upload.array('file', 10), function(req, res){
    // Your array of files is in req.files
}
Diego Osornio
  • 695
  • 1
  • 9
  • 19
Flaudre
  • 2,107
  • 25
  • 42
  • 23
    `...If you call data.append('file', file) multiple times your request will contain an array of your files...` Saved me hours of despair, especially because I felt the name should be `file[]`, but using just `file` and calling multiple times worked, thanks! – bourgeois247 Jul 16 '17 at 18:42
  • 2
    Dude you are a legend have been searching for this from morning thanks allot man – Kannan T Oct 08 '17 at 17:04
  • 4
    I tried you example, but when I var_dumped it, it always return the last image of the set. I changed: `data.append('file', file)` to `data.append('file', i)`, that worked for me. – Jeroen Bellemans Oct 23 '17 at 09:10
  • 1
    and you are officially my hero – WtFudgE Jun 14 '18 at 01:19
  • 1
    This line is the most important bit of information `If you call data.append('file', file) multiple times your request will contain an array of your files.` Thanks a lot. Saved me hours of my time. – LearnToLive Feb 08 '19 at 11:51
  • 1
    Setting the `FormData` to use the key `files` is what worked for me rather than making it appear as an array such as `files[]` – djneely Feb 15 '19 at 14:06
  • 1
    For folks using django who're looking to send such a request to your views. You might want to use `file_field` instead of `file` for consistency with where django's native forms put file data. eg. `data.append('file_field', file)`, so in your view you'd continue to use `request.FILES.getlist('file_field')` like before. – evantkchong Jun 27 '20 at 16:23
  • 1
    not working for me. had to do data.append('file[]', file); – M K Garwa Oct 20 '20 at 18:33
27

You just have to use fileToUpload[] instead of fileToUpload :

fd.append("fileToUpload[]", document.getElementById('fileToUpload').files[0]);

And it will return an array with multiple names, sizes, etc...

kamal pal
  • 4,119
  • 5
  • 24
  • 39
Vincent Kelleher
  • 472
  • 2
  • 6
  • 11
20

This worked for me:

let formData = new FormData()
formData.append('files', file1)
formData.append('files', file2)
Clézio Santos
  • 417
  • 5
  • 4
10

This one worked for me

//Javascript part
//file_input is a file input id
var formData = new FormData();
var filesLength=document.getElementById('file_input').files.length;
for(var i=0;i<filesLength;i++){
 formData.append("file[]", document.getElementById('file_input').files[i]);
}
$.ajax({
   url: 'upload.php',
   type: 'POST',
   data: formData,
   contentType: false,
   cache: false,
   processData: false,
   success: function (html) {
   
  }
});

<?php
//PHP part
$file_names = $_FILES["file"]["name"];
for ($i = 0; $i < count($file_names); $i++) {
   $file_name=$file_names[$i];
   $extension = end(explode(".", $file_name));
   $original_file_name = pathinfo($file_name, PATHINFO_FILENAME);
   $file_url = $original_file_name . "-" . date("YmdHis") . "." . $extension;
 move_uploaded_file($_FILES["file"]["tmp_name"][$i], $absolute_destination . $file_url);
}
NINSIIMA WILBER
  • 131
  • 1
  • 5
6

Adding [] when appending to fd works, but if you prefer to have your data grouped by file then I'd suggest doing it this way:

var files= document.getElementById('inpFile').files
var fd = new FormData()

for (let i = 0; i < files.length; i++) {
  fd.append(i, files[i])
}

Now your data will be sent grouped by file instead of grouped by attribute.

Rens
  • 163
  • 3
  • 8
4

This worked fine !

var fd = new FormData();

$('input[type="file"]').on('change', function (e) {
    [].forEach.call(this.files, function (file) {
        fd.append('filename[]', file);
    });
});

$.ajax({
    url: '/url/to/post/on',
    method: 'post',
    data: fd,
    contentType: false,
    processData: false,
    success: function (response) {
        console.log(response)
    },
    error: function (err) {
        console.log(err);
    }
});
4

This worked for me

var ins = $('.file').map(function () {
    return this.files;
}).get();

for (var x = 0; x < ins; x++) {
    formData.append("file", ins[x][0]);
}
Khoa Nguyen
  • 1,349
  • 7
  • 20
Ch Usman
  • 371
  • 2
  • 7
3

I worked that such as:

var images = document.getElementById('fileupload').files;
var formData = new FormData();
for(i=0; i<images.length; i++) {
     formData.append('files', images[i]);
}
2

If you are instantiating the FormData object already passing the form as a constructor parameter, the input file's name attribute must contain the square brackets.

HTML:

<form id="myForm" method="POST" action="url" enctype="multipart/form-data">
<input class="form-control form-control-lg" type="file" name="photos[]" multiple />

JS:

var formData = new FormData(document.getElementById('myForm'));
console.log(formData.getAll('photos[]'));

That worked for me!

Écio Silva
  • 116
  • 1
  • 4
2

If we have input in our html:

<input id="my-input" type="file" mutliple /> // multiple attribute to select and upload multiple files

We can get files from that input and send it to server with pure js script:

const myInput = document.getElementById('my-input') // getting our input

myInput.addEventListener('change', (event) => { // listening for file uploads
    const files = event.target.files // getting our files after upload
    const formData = new FormData() // create formData

    for (const file of files) {
        formData.append('files', file) // appending every file to formdata
    }

    const URL = 'http://server.com:3000'
    const response = fetch(URL, {
       method: 'POST',
       data: formData // sending our formdata in body of post request
    })

    return response.json() 
}

It worked perfect for me

P.S.: I used multer in backend (node.js + express), added to file upload route

upload.array("files", 10)
  • First argument is a property name of our files (in formdata)
  • Second argument is max file size
Selim
  • 161
  • 1
  • 5
1

I found this work for me!

var fd = new FormData();
$.each($('.modal-banner [type=file]'), function(index, file) {
  fd.append('item[]', $('input[type=file]')[index].files[0]);
});

$.ajax({
  type: 'POST',
  url: 'your/path/', 
  data: fd,
  dataType: 'json',
  contentType: false,
  processData: false,
  cache: false,
  success: function (response) {
    console.log(response);
  },
  error: function(err){
    console.log(err);
  }
}).done(function() {
  // do something....
});
return false;
1

To upload multiple files with angular form data, make sure you have this in your component.html

Upload Documents

                <div class="row">


                  <div class="col-md-4">
                     &nbsp; <small class="text-center">  Driver  Photo</small>
                    <div class="form-group">
                      <input  (change)="onFileSelected($event, 'profilepic')"  type="file" class="form-control" >
                    </div>
                  </div>

                  <div class="col-md-4">
                     &nbsp; <small> Driver ID</small>
                    <div class="form-group">
                      <input  (change)="onFileSelected($event, 'id')"  type="file" class="form-control" >
                    </div>
                  </div>

                  <div class="col-md-4">
                    &nbsp; <small>Driving Permit</small>
                    <div class="form-group">
                      <input type="file"  (change)="onFileSelected($event, 'drivingpermit')" class="form-control"  />
                    </div>
                  </div>
                </div>



                <div class="row">
                    <div class="col-md-6">
                       &nbsp; <small>Car Registration</small>
                      <div class="form-group">
                        <div class="input-group mb-4">
                            <input class="form-control" 
                (change)="onFileSelected($event, 'carregistration')" type="file"> <br>
                        </div>
                      </div>
                    </div>

                    <div class="col-md-6">
                        <small id="li"> Car Insurance</small>
                      <div class="form-group">
                        <div class="input-group mb-4">
                          <input class="form-control" (change)="onFileSelected($event, 

                         'insurancedocs')"   type="file">
                        </div>
                      </div>
                    </div>

                  </div>


                <div style="align-items:c" class="modal-footer">
                    <button type="button" class="btn btn-secondary" data- 
                  dismiss="modal">Close</button>
                    <button class="btn btn-primary"  (click)="uploadFiles()">Upload 
                  Files</button>
                  </div>
              </form>

In your componenet.ts file declare array selected files like this

selectedFiles = [];

// array of selected files

onFileSelected(event, type) {
    this.selectedFiles.push({ type, file: event.target.files[0] });
  }

//in the upload files method, append your form data like this

uploadFiles() {
    const formData = new FormData(); 

    this.selectedFiles.forEach(file => {
      formData.append(file.type, file.file, file.file.name); 
    });
    formData.append("driverid", this.driverid);

    this.driverService.uploadDriverDetails(formData).subscribe(
      res => {
        console.log(res); 

      },
      error => console.log(error.message)
    );
  }

NOTE: I hope this solution works for you friends

Banny
  • 93
  • 1
  • 6
0

Here is the Vanilla JavaScript solution for this issue -

First, we'll use Array.prototype.forEach() method, as

document.querySelectorAll('input[type=file]') returns an array like object.

Then we'll use the Function.prototype.call() method to assign each element in the array-like object to the this value in the .forEach method.

HTML

<form id="myForm">

    <input type="file" name="myFile" id="myFile_1">
    <input type="file" name="myFile" id="myFile_2">
    <input type="file" name="myFile" id="myFile_3">

    <button type="button" onclick="saveData()">Save</button>

</form>

JavaScript

 function saveData(){
     var data = new FormData(document.getElementById("myForm"));
     var inputs = document.querySelectorAll('input[type=file]');

     Array.prototype.forEach.call(inputs[0].files, function(index){
        data.append('files', index);
     });
     console.log(data.getAll("myFile"));
}

You can view the working example of the same HERE

Bappi Das
  • 11
  • 5
0

Create a FormData object

const formData: any = new FormData();

And append to the same keyName

photos.forEach((_photoInfo: { localUri: string, file: File }) => {
    formData.append("file", _photoInfo.file);
});

and send it to server

// angular code
this.http.post(url, formData)

this will automatically create an array of object under file

if you are using nodejs

const files :File[] = req.files ? req.files.file : null;
Sunil Garg
  • 12,670
  • 19
  • 110
  • 153