Development and Managed Hosting
ANEXIA
SEP
12
2018

Trainee-Howto: Upload images from clipboard

Written on September 12, 2018 by Dennis Schaffer

Now I am already over 1 year in the apprenticeship as a software developer at Anexia. When I started here in March 2017, I could just create a simple page with HTML and CSS and I knew what Swift and Java was. Since that time I have been able to gain a lot of know-how. But most of all I use Javascript and PHP.

Recently, however, I encountered a small problem. I should make a small change on the already existing Link-Shortener of Anexia, anx.io. This page is not only used to shorten a long link, you can also upload pictures from your PC to which a link is displayed after clicking on the upload button. If you use this link, the image you used will be displayed.

I got the task that the user can use the function to simply insert an image from his clipboard with “stgr+v” or an image via drag&drop. To accomplish this, ZeroClipboard was used earlier, but for me this was out of the question, because I wanted to use a pure Javascript solution.

Here I present you a small project with the source code to try it out for yourself.

 

Clipboard

For my solution, jQuery is included first, I just do that in the header:

<script src="https://code.jquery.com/jquery-latest.min.js"</script>

To send the later uploaded picture with a post-request I first create a form tag and underneath a submit button to send it.

<form action="/upload.php" method="POST">
    <button type="submit" id="upload">Upload</button>
</form>

Next I create an input field, which I set to hidden.

<input type="hidden" id="base64_file_form"/>

The type is intentionally set to “hidden” and an eventlistener is placed on the page that listens to the key combination “ctrl+v” (‘paste’). The image will be converted to base64 and saved to the input field.

document.getElementById("base64_file_form").value = evt.target.result;
document.getElementById("base64_file_form").setAttribute('name', 'base64_file');

Base64 is a method for encoding 8-bit binary data (e.g. executable files or images) into a character string consisting only of ASCII characters. So you can e.g. send the image as a Post Request and save it in your database.

Then I insert a div into my HTML file, in which the user can see the image he has inserted immediately for verification. That’s why I give the div a certain size so that we can see the picture afterwards.

<div id="picture"></div>

<style>
   #picture {
      background-size: contain;
      background-repeat: no-repeat;
      max-height: 150px;
   }
</style>

On this div the base64 string is set as background image in the script.

document.getElementById("picture").style.backgroundImage = "url('"+evt.target.result+"')";

 

Drag & Drop

For the Drag & Drop function I create a div, which I call the “dropzone”, because an image is drawn into this area. Also this one gets a certain width and a certain height and I give the div a dotted border, so the drop zone in which the image is drawn is clearer.

<div id="dropzone">
    <input type="hidden" id="dropy"/>
</div>

<style>
#dropzone {
     width: 200px;
     height: 100px;
     border: 1px dashed #000000;
}
</style>

In the dropzone I nested an input field, in which the base64 string is written as above. So you can also fire a Post Request here.

window.addEventListener("load", function() {
  $("#dropzone")
    .bind("dragover", function(e) {
      $(this).addClass("dragover");
      return false;
    })
    .bind("dragleave", function(e) {
      $(this).removeClass("dragover");
      e.stopPropagation();
      e.preventDefault();
      return false;
    })
    .bind("drop", function(e) {
      $(this).removeClass("dragover");
      e.stopPropagation();
      e.preventDefault();
      readImages(e);
      return false;
    });

  $(document.body)
    .bind("dragover", function(e) {
      return false;
    })
    .bind("drop", function(e) {
      e.stopPropagation();
      e.preventDefault();
      return false;
    });
});

It is important to set an event listener to this function as well. This is how the function is called when an image is dragged in.

Again the background of the id=”picture” is set for control.

function readImage(file, event) {
  document.getElementById("dropy").value = event.target.result;
  document.getElementById("base64_image").style.backgroundImage = "url('"+event.target.result+"')";
  document.getElementById("dropzone").setAttribute('name', 'base64_file');
}

function readImages(event) {
  var files = event.originalEvent.dataTransfer.files;
  $.each( files, function(index, file){
    var fileReader = new FileReader();
    fileReader.onload = (function(file) {
      return readImage(file, event);
    }
  })(file);
  fileReader.readAsDataURL(file);
  return found = true;
  });
}

 

 

Tip

It is important to note that a user cannot upload code or other files, these could contain unwanted code and cause damage to the application.

A secure upload for images can look like this:

//checking the file extension
$allowed_extensions = array('png', 'jpg', 'jpeg', 'gif');
if(!in_array($extension, $allowed_extensions)) {
 die();
}
 
//checking the file size
$max_size = 500*1024; //500 KB
if($_FILES['datei']['size'] > $max_size) {
 die();
}

It checks that an image file is really uploaded and also checks the size of the image to exclude files that are too large.

You could also query this in the frontend, but an attacker could manipulate the JavaScript code to upload other file formats anyway. That’s why it makes more sense to perform the check in the backend (server side). To be on the safe side, it can also be explicitly stated that the folder in which the uploads land has no executable rights.

Fazit

A year like that goes by really fast, and even though the project “Upload pictures to Link Shortener” might be a piece of cake for any trained developer, I’m still surprised to be able to “code” it so easily. My self a year ago would be thrilled by the skills I acquired in this relatively short time.

By the way, Anexia always trains young people as software developers, and I think it’s worth applying: joinourrevolution.net