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.

html5_file_upload

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:

Zeigen »

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:

HTML5 File Upload

Ich hoffe euch hat der Artikel gefallen. Bei Fragen oder Kritik stehe ich euch wie immer gern zur Seite.

Schlagwörter: , ,

29 Kommentare bisher »

  1. Ley sagt

    am 20. Juli 2012 @ 12:30

    Toller Beitrag!

    Eine wirklich gute Anleitung. HTML5 bietet wirklich tolle neue Möglichkeiten.

  2. 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.

  3. 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.

  4. 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‘]);

  5. 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.

  6. 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.

  7. 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

  8. 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

  9. 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.

  10. 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!

  11. 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

  12. 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?

  13. 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ß

  14. 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

  15. Shady sagt

    am 21. Mai 2013 @ 21:42

    Vielen Dank; sehr gut erklärt und auf das wesentliche beschränkt.

  16. 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?

  17. 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

  18. 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!

  19. 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.

  20. 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

  21. 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

  22. Tbias sagt

    am 11. Dezember 2014 @ 18:38

    Hallo Wo kann ich denn die Dateien die ich hochgeladen hab, dann wieder Downloaden?

  23. 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.

  24. 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

  25. Maximilianus sagt

    am 11. Oktober 2015 @ 19:13

    Sehr hilfreich, danke!

  26. 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.

  27. 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.

  28. 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?

  29. 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

Komentar RSS · TrackBack URI

Hinterlasse einen Kommentar

Name: (erforderlich)

eMail: (erforderlich)

Website:

Kommentar: