Nun befinde ich mich schon über 1 Jahr in der Lehre als Softwareentwickler bei Anexia. Als ich im März 2017 hier angefangen habe, konnte ich gerade so eine einfache Seite mit HTML und CSS erstellen und ich wusste was Swift und Java war. Seit dieser Zeit habe ich einiges an Know-how dazu gewinnen können. Am meisten nutze ich jedoch Javascript und PHP.
Neulich stieß ich allerdings auf ein kleines Problem. Ich sollte auf der dem bereits bestehenden Link-Shortener der Anexia, anx.io, eine kleine Änderung vornehmen. Diese Seite wird nicht nur dazu genutzt, einen langen Link zu kürzen, man kann auch Bilder von seinem PC hochladen zu denen nach Klick auf den Upload-Button auch ein Link ausgegeben wird. Benutzt man diesen Link, wird das Bild angezeigt, das man verwendet hatte.
Ich bekam die Aufgabe, dass der User die Funktion nutzen kann, einfach mit “stgr+v” ein Bild aus seinem Clipboard oder ein Bild via Drag&Drop einzufügen. Um das zu bewerkstelligen wurde früher ZeroClipboard verwendet, für mich kam das aber nicht in Frage, da ich ich eine reine Javascript-Lösung einsetzen wollte.
Hier stelle ich euch ein kleines Projekt mit dem Sourcecode zur Verfügung um es auch gleich selbst auszuprobieren.
Für meine Lösung wird zuerst jQuery eingebunden, ich mach das einfach im header:
<script src="https://code.jquery.com/jquery-latest.min.js"</script>
Um das später hochgeladene Bild mit einem Post-Request zu verschicken erstelle ich zuerst einen Form-Tag und darunter noch einen Submit-Button zum versenden
<form action="/upload.php" method="POST"> <button type="submit" id="upload">Upload</button> </form>
Darin erstelle ich als nächstes ein Input Feld, das ich auf hidden setze.
<input type="hidden" id="base64_file_form"/>
Der type wird absichtlich auf „hidden“ gesetzt und es wird ein eventlistener auf die Seite gesetzt, der auf die Tastenkombination „strg+v“ (‚paste‘) hört. Das Bild wird in base64 umgewandelt und ins Input Feld gespeichert.
document.getElementById("base64_file_form").value = evt.target.result; document.getElementById("base64_file_form").setAttribute('name', 'base64_file');
Base64 ist ein Verfahren zur Kodierung von 8-bit-Binärdaten (z.B. ausführbare Dateien oder Bilder) in eine Zeichenfolge, die nur aus ASCII-Zeichen besteht. So kann man das Bild z.B. als Post Request verschicken und in seine Datenbank speichern.
Danach füge ich in mein HTML-File noch ein div ein, in dem der User das Bild das er eingefügt hat sofort zur Überprüfung ansehen kann. Darum gebe ich dem Div eine bestimmte Größe, damit wir das Bild danach auch sehen.
<div id="picture"></div> <style> #picture { background-size: contain; background-repeat: no-repeat; max-height: 150px; } </style>
Auf dieses div wird in dem Script der base64 String als Background Image gesetzt.
document.getElementById("picture").style.backgroundImage = "url('"+evt.target.result+"')";
Für die Drag & Drop-Funktion erstelle ich ein Div. Dieses nenne ich die “dropzone”, da in diesem Bereich ein Bild hineingezogen wird. Auch dieses bekommt eine bestimmte Breite und eine bestimmte Höhe und ich gebe dem Div einen gestrichelten Rand, damit ist die Dropzone in der das Bild gezogen wird übersichtlicher.
<div id="dropzone"> <input type="hidden" id="dropy"/> </div> <style> #dropzone { width: 200px; height: 100px; border: 1px dashed #000000; } </style>
In die Dropzone verschachtelte ich noch ein Input Feld, in das auch wie oben der base64 String geschrieben wird. Somit kann man auch hier ein Post Request abfeuern.
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; }); });
Es ist wichtig, auch einen Event Listener auf diese Funktion zu setzen. So wird nämlich die Funktion aufgerufen wenn ein Bild hineingezogen wird.
Auch hier wird wieder der Background von der id=”picture” gesetzt für die Kontrolle.
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; }); }
Zu beachten bei solchen Aufgaben ist, dass ein User keinen Code bzw. andere Files hochladen kann, diese könnten unerwünschten Code beinhalten und Schaden an der Applikation anrichten.
Ein sicherer Upload für Bilder kann z.B. so aussehen:
//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(); }
Dabei wird überprüft, dass wirklich eine Bilddatei hochgeladen wird, außerdem wird auch die Größe des Bildes überprüft, um zu große Dateien auszuschließen.
Man könnte dies auch schon im Frontend abfragen, doch ein Angreifer könnte den JavaScript Code manipulieren um trotzdem andere Dateiformate hochladen. Darum macht es mehr Sinn die Überprüfung im Backend (serverseitig) durchzuführen. Um auf Nummer sicher zu gehen kann auch explizit angeben werden, das der Ordner in welchem die Uploads landen, keine ausführbaren Rechte besitzt.
So ein Jahr vergeht wirklich schnell, und auch wenn das Projekt “Bild Hochladen beim Link-Shortener” für jeden ausgelernten Entwickler vielleicht ein Kinderspiel ist, bin ich doch überrascht, das nun so locker “hinzucoden”. Mein Ich vor einem Jahr wäre begeistert von meinen in dieser verhältnismäßig kurzen Zeit erworbenen Fähigkeiten.
Anexia bildet übrigens immer wieder junge Leute als Softwareentwickler aus, und ich finde bewerben lohnt sich: joinourrevolution.net