HTML5 File Upload – Fortschrittanzeige (Progressbar)
Mit HTML5 ist es nun ohne weiteres möglich einen Dateiupload mit Fortschrittsanzeige zu realisieren. In diesem Artikel möchte ich darauf eingehen und euch die neuen Techniken vorstellen.
Uploaden mit HTML5
Mit frühren Version vor HTML5 war es nicht möglich Datein via Javascript (AJAX) hochzuladen bzw. nur über Umwege. Dies hat sich nun zum Glück geändert. Möglich macht dies das XMLHttpRequest Objekt in Version „Level 2“.
Folgende neue Eigenschaften enthält diese Spezifikation:
- Hochladen und Herrunterladen von Byte-Stream- File, Blob und FormData Objekten
- Fortschritt-Event (Up / Dow)
- CROS (Cross Origin Resource Sharing)
File Objekt
Um nun eine Datei mit dem XMLHttpRequest Objekt hochladen zu können, benötigen wir noch ein File Objekt. Welches Teil der neuen FileAPI von HTML5 ist. Über das File Objekt können z.B. Dateiname, Dateigröße und Datei-Mime Type abgefragt werden. Das File Objekt kann z.B. aus einem FileList Objekt eines input Elementes entnommen werden. Die Eigenschaft heißt „files“.
FormData Objekt
Um nun das XMLHttpRequest Objekt mit Formular Daten (POST Daten) zufüllen, benötigt man noch ein FormData Objekt, welches dem XMLHttpRequest Objekt in der Methode „send“ mitgegeben wird. FormData enthält die eigentlich zu übertragenden Informationen. In unserem Beispiel das File Objekt
Beispiel
Ich möchte hier ein ganz simples Beispiel zeigen um die vorigen Punkte gut zu erklären, so das man die Thematik gut versteht. Daher habe ich auf CSS und sonstigen Schnickschnack verzichtet.
Als erstes brauchen wir ein HTML5 Grundgerüst. Dies sieht bei mir ganz schlicht und einfach aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <!doctype html> <html> <head> <meta charset="utf-8"> <title>File-Upload mit Fortschrittanzeige</title> </head> <body> <script type="text/javascript"> </script> <form action="" method="post" enctype="multipart/form-data"> <input name="file" type="file" id="fileA" onchange="fileChange();"/> <input name="upload" value="Upload" type="button" onclick="uploadFile();" /> <input name="abort" value="Abbrechen" type="button" onclick="uploadAbort();" /> </form> <div> <div id="fileName"></div> <div id="fileSize"></div> <div id="fileType"></div> <progress id="progress" style="margin-top:10px"></progress> <span id="prozent"></span> </div> </body> </html> |
Funktion: fileChange
Jetzt kommen wir zum Javascript Code. Als erstes schreiben wir uns eine Funktion fileChange(). Diese wird immer dann aufgerufen, sobald eine neue Datei ausgewählt wurde (onchange=“fileChange();“ im Input Element).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function fileChange() { //FileList Objekt aus dem Input Element mit der ID "fileA" var fileList = document.getElementById("fileA").files; //File Objekt (erstes Element der FileList) var file = fileList[0]; //File Objekt nicht vorhanden = keine Datei ausgewählt oder vom Browser nicht unterstützt if(!file) return; document.getElementById("fileName").innerHTML = 'Dateiname: ' + file.name; document.getElementById("fileSize").innerHTML = 'Dateigröße: ' + file.size + ' B'; document.getElementById("fileType").innerHTML = 'Dateitype: ' + file.type; document.getElementById("progress").value = 0; document.getElementById("prozent").innerHTML = "0%"; } |
Diese Funktion macht nichts weiteres als den Dateinamen, Dateigröße und Dateityp der ausgewählten Datei zurückzugeben und die Progressbar auf 0 zurücksetzten.
Zeile 4: Mit document.getElemntById(„fileA“).files wird das FileList Objekt zurückgegeben. Dies enthählt eine Liste mit File Objekten, abhängig davon wieviele Dateien vom Benutzer ausgewählt wurden.
Funktion: uploadFile
Als nächstes brauchen wir unsere eigentliche Upload Funktion. Ich nenne sie uploadFile()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | var client = null; function uploadFile() { //Wieder unser File Objekt var file = document.getElementById("fileA").files[0]; //FormData Objekt erzeugen var formData = new FormData(); //XMLHttpRequest Objekt erzeugen client = new XMLHttpRequest(); var prog = document.getElementById("progress"); if(!file) return; prog.value = 0; prog.max = 100; //Fügt dem formData Objekt unser File Objekt hinzu formData.append("datei", file); client.onerror = function(e) { alert("onError"); }; client.onload = function(e) { document.getElementById("prozent").innerHTML = "100%"; prog.value = prog.max; }; client.upload.onprogress = function(e) { var p = Math.round(100 / e.total * e.loaded); document.getElementById("progress").value = p; document.getElementById("prozent").innerHTML = p + "%"; }; client.onabort = function(e) { alert("Upload abgebrochen"); }; client.open("POST", "upload.php"); client.send(formData); } |
Zeile 1: Die Variable „client“ enthält das XMLHttpRequest Objekt, um später den Upload abbrechen zu können wird diese Variable Global deklariert.
Zeile 21: Hier wird das FormData Objekt mit Daten gefüllt. In unserem Fall das File Objekt, welches hochgeladen werden soll. „Datei“ ist dabei der Name, der dann z.B. mit PHP über die super Globale Variable $_FILE ausgelesen werden kann ($_FILE[‚datei‘]).
Zeile 23-38: Dem XMLHttpRequest Objekt werden noch 4 Event Funktionen hinzugefügt, onerror wird aufgerufen, wenn ein Fehler aufgetreten ist, onload wird aufgerufen, wenn der Upload erfolgreich beendet wurde, onabort wird aufgerufen, wenn der Upload abgebrochen wurde und onprogress wird im Prozess aufgerufen, d.h. wärend des hochladens. Dort kann man dann die geladenen Bytes (e.loaded) und die noch zu ladenten Bytes abfragen (e.total). Zu beachten ist, dass dieses Event nicht am XMLHttpRequest Objekt registriert wird, sondern an der Eigenschaft/Attribut „upload“ ( XMLHttpRequestUpload Objekt). Wenn ihr die Funktion/ Event vom Objekt XMLHttpRequest nehmt, erhaltet ihr keine Werte.
Zeile 43: Die Methode send() sendet den Inhalt vom FormData Objekt an unsere uploaded.php Datei, die wir in Zeile 34 mit der Methode open festgelegt habe.
Funktion: uploadAbort
Als letztes kommt noch eine Funktion hinzu, um den Upload später abbrechen zu können.
1 2 3 4 5 | function uploadAbort() { if(client instanceof XMLHttpRequest) //Briecht die aktuelle Übertragung ab client.abort(); } |
PHP Skript
Das PHP Skript könnt dann so aussehen:
1 2 3 4 5 6 | <?php if (isset($_FILES['datei'])) { move_uploaded_file($_FILES['datei']['tmp_name'], '/pfad_zur_zieldatei/'.basename($_FILES['datei']['name'])); } ?> |
Das wars eigentlich schon. Zum Abschluss noch mal das ganze Skript:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | <!doctype html> <html> <head> <meta charset="utf-8"> <title>File-Upload mit Fortschrittanzeige</title> </head> <body> <script type="text/javascript"> function fileChange() { //FileList Objekt aus dem Input Element mit der ID "fileA" var fileList = document.getElementById("fileA").files; //File Objekt (erstes Element der FileList) var file = fileList[0]; //File Objekt nicht vorhanden = keine Datei ausgewählt oder vom Browser nicht unterstützt if(!file) return; document.getElementById("fileName").innerHTML = 'Dateiname: ' + file.name; document.getElementById("fileSize").innerHTML = 'Dateigröße: ' + file.size + ' B'; document.getElementById("fileType").innerHTML = 'Dateitype: ' + file.type; document.getElementById("progress").value = 0; document.getElementById("prozent").innerHTML = "0%"; } var client = null; function uploadFile() { //Wieder unser File Objekt var file = document.getElementById("fileA").files[0]; //FormData Objekt erzeugen var formData = new FormData(); //XMLHttpRequest Objekt erzeugen client = new XMLHttpRequest(); var prog = document.getElementById("progress"); if(!file) return; prog.value = 0; prog.max = 100; //Fügt dem formData Objekt unser File Objekt hinzu formData.append("datei", file); client.onerror = function(e) { alert("onError"); }; client.onload = function(e) { document.getElementById("prozent").innerHTML = "100%"; prog.value = prog.max; }; client.upload.onprogress = function(e) { var p = Math.round(100 / e.total * e.loaded); document.getElementById("progress").value = p; document.getElementById("prozent").innerHTML = p + "%"; }; client.onabort = function(e) { alert("Upload abgebrochen"); }; client.open("POST", "upload.php"); client.send(formData); } function uploadAbort() { if(client instanceof XMLHttpRequest) client.abort(); } </script> <form action="" method="post" enctype="multipart/form-data"> <input name="file" type="file" id="fileA" onchange="fileChange();"/> <input name="upload" value="Upload" type="button" onclick="uploadFile();" /> <input name="abort" value="Abbrechen" type="button" onclick="uploadAbort();" /> </form> <div> <div id="fileName"></div> <div id="fileSize"></div> <div id="fileType"></div> <progress id="progress" style="margin-top:10px"></progress> <span id="prozent"></span> </div> </body> </html> |
Download:
Ich hoffe euch hat der Artikel gefallen. Bei Fragen oder Kritik stehe ich euch wie immer gern zur Seite.
Schlagwörter: HTML, html5, Upload
Ley sagt
am 20. Juli 2012 @ 12:30
Toller Beitrag!
Eine wirklich gute Anleitung. HTML5 bietet wirklich tolle neue Möglichkeiten.
Stephan sagt
am 26. Juli 2012 @ 12:09
Sehr guter Artikel! Einziger Wermutstropfen ist mal wieder der IE, der die HTML5 File API aktuell leider noch nicht unterstützt, so dass man wohl oder übel eine Fallback-Funktionalität für den IE bereitstellen stellen muss.
Hans-Holger Miebach sagt
am 3. September 2012 @ 11:25
Ich habe das obige ganze Skript kopiert und versucht, es auszuführen. Das funktioniert in FireFox Version 13 anscheinend nicht. Das PHP-Programm upload.php wird nicht aufgerufen.
admin sagt
am 11. September 2012 @ 10:37
Hey,
ich habe es eben noch mal mit allen gängigen Browser getestet, bei mir ohne Probleme.
Bitte beachte das, dass ganze auf einem „PHP-Server“ laufen muss. Sonst kann die upload.php Datei nicht ausgeführt werden. Zum Testen empfehle ich XAMPP für Windows.
Wichtig ist außerdem noch das du in der upload.php den Pfad bei move_uploaded_file() richtig setzt. Dieser muss ein Pfad + Dateiname sein, sonst klappt das ganze nicht.
Also z.B. move_uploaded_file($_FILES[‚datei‘][‚tmp_name‘], ‚H:\temp\\‘.$_FILES[‚datei‘][’name‘]);
Hans-Holger Miebach sagt
am 13. September 2012 @ 21:09
Vielen Dank für Ihre Antwort. Haben Sie die obige URL ausprobiert? Da soll beim Aufrufen von upload.php die echo-Nachricht erscheinen, die ich eben eingebaut habe. Bei mir klappt es nicht. PHP-Server ist 1und1-Server. Dort wurden andere PHP-Skripte erfolgreich ausgeführt.
admin sagt
am 14. September 2012 @ 09:20
Hey,
Ihren Link hab ich gar nicht gesehen, ich habs mir jetzt aber angeschaut.
Die upload.php Datei wird korrekt aufgerufen aber das upload.php Skript gibt eine PHP Warnung zurück:
Warning: move_uploaded_file(/Xmie) [function.move-uploaded-file]: failed to open stream: Permission denied in /***/htdocs/upload.php on line 14
Warning: move_uploaded_file() [function.move-uploaded-file]: Unable to move ‚/tmp/php***‘ to ‚/Xmie‘ in /***/htdocs/upload.php on line 14
Dieser Fehler bedeutet, dass der Ordner „Xmie“ nicht die richtigen Schreibrechte besitzt. Daher müssen Sie mit Hilfe z.B. eines FTP-Clients die Schreibrechte (chmod) auf 777 stellen. Danach sollte es funktionieren.
Kurz noch zum Thema echo-Nachricht. Die Ausgabe des PHP-Skriptes kann nur mit Addons wie Firebug oder Live HTTP Headers ausgelesen werden. Da im Javascript Code die Rückgabe des upload.php Skriptes nicht bearbeitet wird.
Wenn Sie es aber dennoch möchten, müssen Sie die Javascript Funktion um folgendes erweitern:
client.onreadystatechange = function() {
if(this.readyState == this.DONE && this.status == 200)
{
var ausgabe = document.getElementById(„testAusgabe“);
ausgabe.innerHTML = this.responseText;
}
};
Dieser Schnipsel kommt in die Funktion uploadFile() zwischen (müsste Zeile 63-64 sein):
client.open(„POST“, „upload.php“);
…
client.send(formData);
Des Weiteren muss noch eine Div Container für die Ausgabe eingebaut werden. Diesen habe ich ganz an das Ende gesetzt vor dem Schließen des body-Elements.
Das div-Element könnte so aussehen:
Ich hoffe ich konnte Ihnen weiterhelfen.
LG
Julius.
Jerry sagt
am 22. November 2012 @ 12:29
Hallo,
schönes Skript, … aber der letzte Schnipsel (zur Ausgabe der php-Datei) scheint nicht zu funktionieren.
LG,
Jerry
admin sagt
am 24. November 2012 @ 13:49
Ich hoffe du meinst jetzt den letzten Schnipsel aus dem Artikel.
Dieser Code dient nicht zu Ausgabe der Datei, sondern zum Speichern der Datei in den angegebenen Pfad + Dateiname.
Beachte aber bitte das, dass Verzeichnis schreibrechte besitzt.
LG
Julius
martin sagt
am 15. Dezember 2012 @ 22:43
ne feine sache!!!, alles läuft unter opera perfekt,
bekomme allerdings im firefox immer die fehlermeldung von
client.onerror = function(e) {
alert(„onError“);
};
die datei wird aber trotzdem hochgeladen, nur der fortschrittsbalken zeigt nichts an.
Ralph sagt
am 5. Februar 2013 @ 15:05
Sehr schönes Tutorial, hat einwandfrei funktioniert! 😉
Ein Frage hätte ich noch, ich würde gerne wie bei dem Beispiel „PHP 5.4 Datei Upload“ einen „Abbrechen“ Button einfügen, dort wurde es über $SESSION[‚param‘][‚cancel_true‘] = true gemacht, wie breche ich nun einen laufenden Upload-Prozess mit HTML5 File Upload ab? Danke!
admin sagt
am 8. Februar 2013 @ 16:15
@Martin
Mh, bei mir Funktioniert alles perfekt im Firefox. Mit welcher Version hast du es getestet?
@Ralph
Danke für den Hinweis. Ich habe den Artikel aktualisiert und ein Abbruch-Button hinzugefügt.
Um einen Upload abzubrechen musst du nur die Methode abort() vom XMLHttpRequest Objekt aufrufen.
LG
Julius
xenix sagt
am 19. Februar 2013 @ 11:03
wie sieht es den bei dem geschriebenen Quellcode mit dem copyright aus??
darf man es weiterverwenden bzw einsetzen?
Alex sagt
am 5. Mai 2013 @ 00:36
Hi,
find ich n sehr cooles Skript! Auch wenn ich ein absoluter Javascript-Legasteniker bin, hab ich das zum laufen gebracht.
Ich bräuchte das ganze aber auch um mehrere Dateien hochzuladen. Wie genau stell ich das an?
Gruß
markus sagt
am 15. Mai 2013 @ 15:22
Hi,
diese Beschreibung ist auf jeden Fall Prima.
martin sagt
am 15. Dezember 2012 @ 22:43
ne feine sache!!!, alles läuft unter opera perfekt,
bekomme allerdings im firefox immer die fehlermeldung von
client.onerror = function(e) {
alert(“onError”);
};
die datei wird aber trotzdem hochgeladen, nur der fortschrittsbalken zeigt nichts an.
Wenn im HTML Code bei dem Upload Button type=“button“ zu type=“submit“ getauscht wird, ensteht dieses Problem. Ich möchte auf meiner nach dem Upload eine url mit POST-Variablen aufrufen. Ist das auch irgendwie möglich? Ich habe mit javaskript leider nicht sooo viel Erfahrung.
Beste Grüße
Markus
Shady sagt
am 21. Mai 2013 @ 21:42
Vielen Dank; sehr gut erklärt und auf das wesentliche beschränkt.
Kashuda sagt
am 9. Juni 2013 @ 17:07
Cooles Tutorial. Danke.
Wie könnte man sich das Ergebnis, also die Ausgabe des PHP Skriptes, nach erfolgreichem Upload anzeigen lassen?
Mein Upload Skript hat bisher die hochgeladenen Dateien weiterverarbeitet und dem Nutzer dann einige Infos angezeigt. Diese Infos würde ich in dieses Skript gerne einbauen.
Ich nehme an, dass ich direkt hinter client.send(formData); so etwas noch einfügen könnte – aber wie?
BrainBaze sagt
am 6. August 2013 @ 23:38
Hallo,
danke für dieses coole Tutorial.
Kannst du mir sagen wie man einstellt das nur bestimmte Dateien hochgeladen werden können.
Sagen wir zum Beispiel eine *.gbx.
LG
Benny
Chris sagt
am 2. Januar 2014 @ 15:08
Exzellentes Tutorial ! Es ist schon verblüffend daß dein kleines Script crossbrowsersafe (alle modernen) das tut, was andere jQuery-plugins in 10.000 Zeilen machen. Sehr geil, Dicker Dank dafür!
bormolino sagt
am 2. April 2014 @ 11:43
Tolles Skript!
Praktisch wäre ein Multi-File-Upload, mit dem sich mehrere Dateien gleichzeitig hochladen lassen, das hat HTML5 ja auch.
Ira sagt
am 19. Mai 2014 @ 19:17
Hallo
das Script ist ganz toll,
leider habe ich es nicht hinbekommen,
mit dem empfohlenen Codeschnipsel [client.onreadystatechange = function() {
if(this.readyState == this.DONE && this.status == 200)
{
var ausgabe = document.getElementById(“testAusgabe”);
ausgabe.innerHTML = this.responseText;
}
};
Dieser Schnipsel kommt in die Funktion uploadFile() zwischen (müsste Zeile 63-64 sein):
client.open(“POST”, “upload.php”);
…
client.send(formData);]
und dem
eine Rückantwort der (von mir modifizierten upload.php zu bekommen) es ging dann gar nichts mehr.
Vllt. könnte mir jemand auch bei dem Umbenennen der Dateinamen helfen, mein Ansatz ist dieser:
(bin allerdings kein php-Experte, sorry vorab)
/Datenbank abfragen
$db = mysqli_connect(„localhost“, „Benutzername“, „Passwort“, „Datenbankname“);
if(!$db)
{
exit(„Verbindungsfehler: „.mysqli_connect_error());
}
// Spalte KundenID aus Tabelle Kundenliste mit Kundenname, wenn dieser so vorhanden
// evtl. Variablen anpassen wenn in Datenbank anders benannt
$abfrage = „SELECT kundenid FROM kundenliste WHERE kundenname=’$kundenname'“;
$ergebnis = mysqli_query($db, $abfrage);
while($row = mysqli_fetch_object($ergebnis, MYSQL_ASSOC))
if (mysql_num_rows ($result) == 0)
{
echo „Sie sind nicht angemeldet! Bitte anmelden!“;
}
if (mysql_num_rows ($result) > 0)
{
echo $row->KundenID;
// Datei umbenennen
rename(„datei“,“kundenid“);
}
else
{
// Datei umbenennen
rename(„datei“,“neuer_name“);
}
das habe ich in die upload.php unter dem bisherigen Code des Beispiels hier
danke bestens für Antworten
Ira sagt
am 19. Mai 2014 @ 19:20
Korrektur zu meinem Beitrag: hinter „und dem“ und vor „eine Rückantwort“ stand der div-Container als html, wird wohl nicht dargestellt
Tbias sagt
am 11. Dezember 2014 @ 18:38
Hallo Wo kann ich denn die Dateien die ich hochgeladen hab, dann wieder Downloaden?
holger sagt
am 23. Januar 2015 @ 13:48
wie kann man die Funktion für mehr Bilder erweitern?
Das Problem ist, man musst warten, bis das vorrige Bild auf den Server ist.
man kann zwar in einer While schleife:
document.getElementById(„prozent_“+i).innerHTML == „100%“;
abfragen, aber das erzeigt eine CPU-last von 100%
ich habe die Funktion auf IE11/FF35/Chrome getestet, alles gut, wie es auf Safari und Android aus schaut,
kann ja mal jemand testen.
Oscar sagt
am 17. August 2015 @ 14:59
Super Script!
Perfekt für nginx-Server.
Aber kann mir jemand das Skript so umformen das es für mehrere Dateien geht, also als „multiple“-File
Maximilianus sagt
am 11. Oktober 2015 @ 19:13
Sehr hilfreich, danke!
Tom sagt
am 25. Januar 2016 @ 23:14
Ich bräuchte auch einen Lösungsansatz für Multiple Uploads. Bis jetzt kann ich nur mehrere Dateien auswählen aber hochladen tut es nur eine.
Heinrich sagt
am 24. Februar 2016 @ 17:35
Ganz nice, einziges Manko nach dem upload verbleibt er im stage 100% und geht nicht wieder in den Ursprung zurück, somit können eventuell vorgesehene Ereignisse nach erfolgtem upload nicht triggern.
Abgesehen davon empfehle ich die Vermeidung von Umlauten in Sourcecode jedweder Art.
Mike Lerondres sagt
am 2. Dezember 2016 @ 22:22
Was ist wenn ich weitere Variablen wie eine Beschreibung zu einem Bild per mit übergeben möchte.
zB:
Wie übergibt man dies?
Patrick sagt
am 29. Januar 2017 @ 15:07
Hallo
super Skript
Läuft auf meinem Webserver bei 1und1 super
Doch auf meinem Raspbeery Pi3 mit Apache2 läuft es nicht
was fehlt mir hier noch
Bitte um Hilfe, danke
gruß Patrick
Mika sagt
am 25. Mai 2018 @ 11:36
Das Skript ist schon mal sehr hilfreich! Nun habe ich nur noch das Problem dass ich das Bild komprimiert hochladen möchte :/
Gibt es dafür eine Funktion die man hier einbinden kann?
Vincent sagt
am 12. Mai 2020 @ 16:34
8 Jahre später funktionniert immer noch. Danke hierfür.
Kleine Verbesserung: Eine Status-Meldung, dass die Datei hochgeladen wurde, habe ich einfach so ergänzt:
eine unter den anderen im Formular;
im Skript folgende ergänzung bei:
client.onload = function(e) {
document.getElementById(„prozent“).innerHTML = „100%“;
prog.value = prog.max;
document.getElementById(„Ausgabe“).innerHTML = „Die Datei wurde erfolgreich hochgeladen!“;
};