0

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.

3
  • Have you considered using AJAX to send the file to your PHP script? Commented Feb 16, 2015 at 20:45
  • @WilliamJanoti, no I have not. Could you write up a quick reply explaining how this could be done in this particular instance or possibly recommending some articles? I'm familiar with jQuery's .ajax() function already, I just have never used it for file uploads or working with information such as what I've written above. Commented Feb 16, 2015 at 20:47
  • stackoverflow.com/questions/24168040/… Commented Feb 16, 2015 at 21:15

2 Answers 2

2

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);
});
Sign up to request clarification or add additional context in comments.

4 Comments

If i remember right i think you can read the request body from php by opening stdin. <?php $stdin = fopen('php://stdin', 'r'); ?>
Hi Manuel! Thanks so much for the help, I'm really fond of your development. Anyways, for some reason when I try to echo/print_r the $stdin variable or process it, I'm receiving an undefined error in the console. Do you have any idea why this could be happening? Thanks again.
I was able to get it to work using "file_get_contents('php://input');". Thanks. :)
Thank you! :) file_get_contents should work, but I would avoid buffering the complete file in memory if you need support for large files.
0

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");
    }
  });

2 Comments

William, I've actually developed my HTML without a form. Check out the edited version of my question for more info. This is what is making the process tricky. I don't think you fully understand how my code is working.
Have you tried the code above? It should work regardless of having a form.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.