Search code examples
javascriptjqueryajaxmultipartform-dataform-data

FormData not sending appended file


I'm making a Javascript app for file uploading with Drag and Drop support - but I've hit a problem I've been stuck on for days.

It seems that 'dropped' files (in my case via jQuery, .on('drop', function(e){) files aren't actually being sent.

I've been browsing answer after answer on StackOverflow - PLEASE DON'T MARK AS DUPLICATE. THE DUPLICATES DO NOT HELP - I'm yet to find an aspect which I have not considered in my implementation. It's as if this solution is working for everyone else but me...

Don't believe me? FIDDLE HERE

(Disclaimer: obviously I have modified my solution to not use cross-domain requests, I am using an endpoint I found on Fiddle as a substitute, but it appears to present the same problem I have been experiencing - hopefully it is sufficient as the basis for this example)

The issue is that the upload completes immediately - apparently it is only sending the text data and not uploading the file itself. Reviewing the request payload I see the data is not present.

Screenshot of request headers. Where the file data is supposed to appear, the header is blank

Javascript

function uploadFile(file){
  console.log("uploadFile");
  var form = new FormData();
  form.append('file', file);
  form.append('hello', 'world');
  $.ajax({
    url: "/echo/js/?js=hello%20world!",
    type: "POST",
    data: form,
    processData: false,
    contentType: false,
    cache: false,
    success: function(data){
      alert("SUCCESS");
    }
  });
}
$(document).ready(function(){

  /* Disable default drag/drop browser behavior. */
  $("html").on('drop', function(e){e.preventDefault(); e.stopPropagation();});
  $("html").on('dragover', function(e){e.preventDefault(); e.stopPropagation();});
  $("html").on('dragenter', function(e){e.preventDefault(); e.stopPropagation();});
  $("html").on('dragleave', function(e){e.preventDefault(); e.stopPropagation();});

  $(".drop_area").on('drop', function(e){
    e.preventDefault(); 
    e.stopPropagation();
    var files = e.originalEvent.target.files || e.originalEvent.dataTransfer.files;
    console.log(files);
    for (var i = 0; i < files.length; i++) {
      uploadFile(files[i])
    }
  });
});

HTML

<div class='drop_area'>
Drop your file in this div.
</div>

CSS

.drop_area {
  border: 1px solid black;
  background: #ffffff;
  height: 300px;
  width: 50%;
  position: relative;
}

Solution

  • After seeing the blank request headers in Chrome, and based on the fast upload speed, I had assumed the files were not sending.

    However after adding code to my backend endpoint (via var_dump($_FILES['file']);), I see the following:

    array(5) {
      ["name"]=>
      string(14) "two-minute.mp4"
      ["type"]=>
      string(9) "video/mp4"
      ["tmp_name"]=>
      string(36) "/Applications/MAMP/tmp/php/phpXfCu0U"
      ["error"]=>
      int(0)
      ["size"]=>
      int(12904619)
    }
    

    The large size attribute appears to indicate quite a lot of data was availible from my upload. It was probably working the whole time. I'll look at this more tomorrow but for the moment the answer may be that:

    "It just looks like it's not working from your browser, but it actually is...".

    Partial credit to @Alisher Gafurov for convincing me to double-check the backend implementation to verify if the file was indeed not present.