Drag and Drop Upload files using Ajax

Posted on Saturday October 06, 2012 / by Eric Potvin

Remember when we use to choose a file by clicking on "browse ..."? Then we had to repeat if we need to upload multiple files.

Well, hopefully you want to change that painful process to a modern way and here's a simple solution that will help you.

Here's some benefits using this technique:

HTML

First of all, let's create a simple HTML and put the fancy "drag and drop" area.

<!DOCTYPE html>
<html>
 <head>
 <title>Drag & Drop Upload</title>
 <meta charset="utf-8" />
 <script src="jquery-1.7.1.min.js"></script>
 <script src="upload.js"></script>
 <link rel="stylesheet" href="upload.css">
</head>
<body>

<h1>Drop file below</h1>

<div id="error"></div>

<section id="uploadBox">
	Drop files here!
</section>

<section id="uploadStatus">
 <div id="progressWrapper">
  <div id="progressBar"></div>
  <div id="progressValue">0%</span>
 </div>
</section>

</body>
</html>

CSS

Now, let's make it pretty

.active {
  background: #ddd;
}
section#uploadStatus {
  display: none;
  margin: 20px 0;
}
#error {
  background: #ffbaba;
  border: 1px solid;
  color: red;
  display: none;
  font: bold 12px verdana;
  margin: 15px 0px;
  padding: 5px;
  width: 400px;  
}
#progressWrapper {
  background: #ddd;
  -webkit-border-radius: 10px;
  border-radius: 10px; 
  padding: 3px;
  position: relative;
  width: 400px;
}

#progressWrapper #progressBar {
  background-color: #61abed;
  border-radius: 10px;
  height: 20px;
  position: relative;
  width: 0%;
}
#progressWrapper #progressValue{
  font: bold 12px verdana;
  position: absolute;
  top: 5px;
  left: 50%;
}
section#uploadBox {
  border: 2px dashed #707070;
  color: #6E6E6E;  
  height: 70px;
  padding-top: 50px;
  text-align: center;
  width: 400px;
}

Javascript/jQuery

Now, let's have the javascript code that will do all the work for you.

var maxFileSize = 1048576; //Kb

$(document).ready(function() {
  if (typeof FormData == "undefined") {
    $('#error').html('Unable to drop files').fadeIn('fast');
    $('#uploadBox').hide();
  }
  jQuery.event.props.push('dataTransfer');

  $('#uploadBox')
    .bind('dragenter', function(e) {
      $(this).addClass("active");
      e.stopPropagation();
      e.preventDefault();
    })
    .bind('dragleave', function(e) {
      $(this).removeClass("active");
      e.stopPropagation();
      e.preventDefault();
    })
    .bind('dragover', function(e) {
      e.stopPropagation();
      e.preventDefault();
    })
    .bind('drop', function(e) {
      $(this).removeClass("active");
      e.stopPropagation();
      e.preventDefault();
      var files = e.dataTransfer.files;

      var imagetype = /image.*/;

      /* Multiple Uploads */
      var xhr, provider;
      var formData = new FormData();
      var numberFiles = files.length;
      for(i = 0; i < numberFiles; ++i) {
        if (!files[i].type.match(imagetype)) {
          // display some message
          continue;
        }
        if (files[i].size > maxFileSize) {
          // display some message
          continue;
        } 
        formData.append('uploadedFile[]', files[i]);
      }
      $('#error').html('').fadeOut(0);

      $.ajax({
        cache: false,
        contentType: false,
        data: formData,
        processData: false,
        url: 'upload.php',
        type: 'POST',
        xhr: function() {
          xhr = jQuery.ajaxSettings.xhr();
          if (xhr.upload) {
            $('#uploadStatus').show();
            xhr.upload.addEventListener('progress', function (e) {
              var p = parseInt(e.loaded/e.total*100);
              $('#progressBar').css({'width':p+'%'});
              $('#progressValue').html(p+'%');
            }, false);
          }
          return xhr;
        },
        beforeSend: function() {
          $('#progressBar').css({'width':'0%'});
          $('#progressValue').html('0%');
        }, 
        success: function(output) {
          // good to go
        },
        error: function() {
        },
      });
    });
});

Then on your PHP file, you will have to process them and move then to the desired folder. The structure looks like this:

Array (
  [uploadedFile] => Array (
    [name] => Array (
      [0] => wallpaper1.jpg
      [1] => fog-wallpaper1920x1080.jpg
    )
    [type] => Array (
      [0] => image/jpeg
      [1] => image/jpeg
    )
    [tmp_name] => Array (
      [0] => /tmp/phpAX0VFl
      [1] => /tmp/phpMusPc0
    )
    [error] => Array (
      [0] => 0
      [1] => 0
    )
    [size] => Array (
      [0] => 651673
      [1] => 482223
    )
  )
)

PHP

<?php
define('UPLOAD_DIR', '/tmp/test/');

foreach ($_FILES['uploadedFile']['name'] as $key => $value)
{
  if ($_FILES['uploadedFile']['error'][$key] == UPLOAD_ERR_OK) {
    $result = move_uploaded_file($_FILES['uploadedFile']['tmp_name'][$key], UPLOAD_DIR . '/' . $_FILES['uploadedFile']['name'][$key]);
    // do what ever you need!
  }
}