Tigerman55
Tigerman55

Reputation: 231

How to Upload Previewed File to PHP from JS

I'm working on a project where I'm trying to allow for a user to upload an xlsx file (not preview) for processing by dragging it into a box. I want it to work something like smallpdf's does. I've got the ability to get the filename from the user along with what I think is a binary string using this group of files:

if(window.FileReader) { 
 var drop; 
 addEventHandler(window, 'load', function() {
    var status = document.getElementById('status');
    drop   = document.getElementById('drop');
    var list   = document.getElementById('list');

    function cancel(e) {
      if (e.preventDefault) { e.preventDefault(); }
      return false;
    }

    // Tells the browser that we *can* drop on this target
    addEventHandler(drop, 'dragover', cancel);
    addEventHandler(drop, 'dragenter', cancel);

addEventHandler(drop, 'drop', function (e) {
  e = e || window.event; // get window.event if e argument missing (in IE)   
  if (e.preventDefault) { e.preventDefault(); } // stops the browser from redirecting off to the image.

  var dt    = e.dataTransfer;
  var files = dt.files;
  for (var i=0; i<files.length; i++) {
    var file = files[i];
    var reader = new FileReader();

    //attach event handlers here...

    reader.readAsDataURL(file);
addEventHandler(reader, 'loadend', function(e, file) {
    var bin           = this.result; 
    var newFile       = document.createElement('div');
    newFile.innerHTML = 'Loaded : '+file.name+' size '+file.size+' B';
    list.appendChild(newFile);  
    var fileNumber = list.getElementsByTagName('div').length;
    status.innerHTML = fileNumber < files.length 
                     ? 'Loaded 100% of file '+fileNumber+' of '+files.length+'...' 
                     : 'Done loading. processed '+fileNumber+' files.';

    var img = document.createElement("img"); 
    img.file = file;   
    img.src = bin;
    list.appendChild(img);
}.bindToEventHandler(file));
  }
  return false;
});
Function.prototype.bindToEventHandler = function bindToEventHandler() {
  var handler = this;
  var boundParameters = Array.prototype.slice.call(arguments);
  //create closure
  return function(e) {
      e = e || window.event; // get window.event if e argument missing (in IE)   
      boundParameters.unshift(e);
      handler.apply(this, boundParameters);
  }
};
  });
} else { 
  document.getElementById('status').innerHTML = 'Your browser does not support the HTML5 FileReader.';
}
function addEventHandler(obj, evt, handler) {
    if(obj.addEventListener) {
        // W3C method
        obj.addEventListener(evt, handler, false);
    } else if(obj.attachEvent) {
        // IE method.
        obj.attachEvent('on'+evt, handler);
    } else {
        // Old school method.
        obj['on'+evt] = handler;
    }
}

Also, the HTML within the body of my webpage is written up as shown below.

<div id="file-container">
  <div id="status">Drag the files from a folder to the selection area below ...</div>
  <div id="drop">Drop Spreadsheet here</div>
  <div id="list"></div>
</div><!--eod #file-container-->

As you can see, I'm not actually using a form. Do I absolutely have to use a form to send a file to PHP? If yes, are there other options?

I just am not sure how to transfer the file from my JavaScript code to my actual PHP to process the file. Any help would be appreciated. I've done a ton of research, to no avail. If you think another way of doing this would be better, I'm open to suggestions.

Upvotes: 0

Views: 127

Answers (2)

Manuel Stofer
Manuel Stofer

Reputation: 36

I'm the developer of smallpdf. We upload the files directly in the request body, without multipart/form-data. There is also no need to use the FileReader API. XMLHttpRequests send method accepts a File/Blob etc as argument.

A simplified version of our upload looks like this:

function upload(file) {
  var req = new XMLHttpRequest();

  req.addEventListener('load', function () {
    console.log(req.statusCode, req.responseText);
  }.bind(this));


  req.upload.addEventListener('progress', function (ev) {
    console.log('progress', ev.loaded / file.size * 100);
  }.bind(this));

  req.upload.addEventListener('error', errorHandler);
  req.addEventListener('error', errorHandler);

  req.open('POST', '/upload/url', true);
  req.setRequestHeader('Content-Type', file.type);

  // Posts the file in the request body
  req.send(file);
}

function errorHandler(error)  {
  console.log(error)
}

You can use something like this to get droped files or use the files of an input field.

var dropElement = document.body;

function cancel(ev) {
  ev.preventDefault();
}
// cancel dragover event
dropElement.addEventListener('dragover', cancel);

// listen for drop events
dropElement.addEventListener('drop', function (ev) {
  cancel(ev);
  var files = [].slice.call(ev.dataTransfer.files);
  files.forEach(upload);
});

Upvotes: 2

William J.
William J.

Reputation: 1584

Try doing something like this after you have read the file:

  var fileContents = new FormData();
  fileContents.append('file', bin);
  $.ajax({
    url :  "processFile.php",
    type: 'POST',
    data: fileContents,
    contentType: false,
    processData: false,
    success: function(data) {
      alert("File sent sucessfully");
    },    
    error: function() {
      alert("Something went wrong");
    }
  });

Upvotes: 0

Related Questions