smart | Webentwicklung
Alles rund um HTML5, PHP, WordPress & Co.

AJAX: Datei-Upload mit XHR2 und FormData

17. April 2013
Stephan
AJAX: Datei-Upload mit XHR2 und FormData

In der Vergangenheit war der Upload von Dateien mittels AJAX, konkreter gesagt mit XMLHttpRequest Level 1, immer recht mühselig. Deswegen wurden hierfür oft irgendwelche versteckten iFrame-Hacks und Plugins verwendet.

Mit XHR2 bzw. XMLHttpRequest Level 2 und der neuen FormData-Klasse gibt es nun jedoch eine sehr einfache Möglichkeit Dateien bzw. generell ganze Formulare inklusive Dateien zum Server hochzuladen.

In diesem Artikel zeige ich euch ein simples Beispiel für einen AJAX-basierten Datei-Upload mittels XHR2 und FormData.

HTML-Grundgerüst

Zuallererst erstellen wir uns eine HTML-Datei mit folgendem Inhalt:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
<head>
<meta charset="utf-8" />
<title>Datei-Upload mit XHR2 und FormData</title>
<script type="text/javascript" src="jquery-1.9.0.min.js"></script>
<script type="text/javascript">
    // hier kommt gleich unser JavaScript-Code hin
</script>
</head>
<body>
<form action="upload.php" method="post">
    <input id="author" type="text" name="author" />
    <input id="file" type="file" name="file" />
    <input id="upload" type="button" name="upload" value="Upload" />
</form>
</body>
</html>

Auf der Seite ist nichts weiter als ein Formular zur Eingabe eines Autornamen und der Angabe einer Datei, die hochgeladen werden soll.

Code zum Erfassen der Formular-Events

Als nächstes fügen wir JavaScript-Code zum binden und verarbeiten einiger Formular-Events ein. Zum einen möchten wir auf das change-Event des Datei-Eingabefelds reagieren. Zum anderen möchten wir sobald das click-Event des Upload-Buttons ausgelöst wird, die Datei bzw. das Formular per XHR2 absenden.

Dazu fügen wir nun folgenden Code hinzu:

var authorInput;
var fileInput;
var uploadButton;
var file;

$(document).ready(function()
{
    init();
});

function init()
{
    authorInput = $('#author');
    fileInput = $('#file');
    uploadButton = $('#upload');
    file = null;

    fileInput.bind('change', function()
    {
        file = this.files[0];
    });

    uploadButton.bind('click', function()
    {
        if(authorInput.val() && file !== null)
        {
            upload();
        }
    });
}

Der Code ist denke ich selbsterklärend, aber falls Fragen sind schreibt einfach ein Kommentar.

Code zum Datei-Upload mit XHR2 und FormData

Als letztes müssen wir nun die upload-Funktion implementieren. Dazu verwenden wir diesen Code:

function upload()
{
    var xhr = new XMLHttpRequest();
    xhr.open('post', 'my-upload.php', true);

    xhr.onload = function()
    {
        console.log('Upload erfolgreich beendet!');
    };

    xhr.upload.onprogress = function(event)
    {
        if(event.lengthComputable)
        {
            var currentProgress = (event.loaded / event.total) * 100;

            console.log('Aktueller Upload-Status: ' + currentProgress + '%');
        }
    };

    var formData = new FormData($('form').get(0));

    xhr.send(formData);
}

Hierzu nun einige Erklärungen:

Zeile 3
Als erstes erzeugen wir uns ein XMLHttpRequest-Objekt.

Zeile 4
Angabe, dass es sich bei dem abzusendenen Request um einen asynchronen (hierfür steht der dritte Parameter auf true) POST-Request handelt und dieser an die URL my-upload.php gesendet werden soll.

Zeile 6 – 9
Im Vergleich zum XHR Level 1 müssen wir uns nicht mehr mit dem onreadystatechange-Event rumplagen. Hierfür besteht nun die Möglichkeit einen onload-Event-Handler zu definieren, der ausgelöst wird wenn der Request erfolgreich gesendet und die entsprechende Antwort vom Server erhalten wurde.

Zeile 11 – 19
Auch die Möglichkeit zur Angabe des onprogress-Event-Handler ist neu. Hierdurch lässt sich der aktuelle Fortschritt des Uploads ermitteln.

Zeile 21
Es wird ein FormData-Objekt erzeugt und das Formular, dessen Daten versendet werden sollen, mit übergeben.

Zeile 23
Abschließend senden wir den AJAX-Request mittels send und übergeben das FormData-Objekt.

Eine gute Einführung zu XHR2 und dessen Neuerungen findest du im Artikel „Introduction to XMLHttpRequest Level 2“ von Opera und zu FormData im Artikel „Using FormData Objects“ von Mozilla.

FormData ohne Formular nutzen

Das tolle an FormData ist, dass es auch unabhängig von einem Formular verwendet werden kann und dynamisch Key-Value-Werte übergeben werden können:

var formData = new FormData();
formData.append('name', authorInput.val());
formData.append('file', file);

jQuery für den Upload verwenden

Natürlich können wir den AJAX-Request aber auch mit jQuery realisieren:

$.ajax(
{
    url: 'my-upload.php',
    type: 'post',
    data: formData,
    processData: false,
    contentType: false,
    success: function() 
    {
        console.log('Upload erfolgreich beendet!');
    }
});

Leider unterstützt jQuery bisher onprogress noch nicht (jedenfalls habe ich dazu auf die Schnelle nichts gefunden), weshalb der Fortschritt des Uploads bei dieser Variante nicht ermittelt werden kann.

Daten auf Serverseite mit PHP verarbeiten

Um zu sehen, dass die Daten auch korrekt gesendet werden, könnt ihr euch eine my-upload.php-Datei mit folgendem Inhalt anlegen:

var_dump($_FILES);
var_dump($_REQUEST);

Als Ergebnis solltet ihr in der Antwort des Servers (z.B. mit Firebug einzusehen) in etwa Folgendes sehen:

array(1) {
  ["file"]=>
  array(5) {
    ["name"]=>
    string(18) "master-thesis.pdf"
    ["type"]=>
    string(15) "application/pdf"
    ["tmp_name"]=>
    string(27) "C:\Windows\Temp\phpEA57.tmp"
    ["error"]=>
    int(0)
    ["size"]=>
    int(1969536)
  }
}
array(1) {
  ["name"]=>
  string(4) "Stephan"
}

Browser-Unterstützung

Einen Überblick über die aktuelle Browser-Unterstützung findet ihr wie immer auf caniuse.com.

Einen genauen Überblick, welcher Browser welche XHR2-Funktionen unterstützt, findet ihr zudem bei Mozilla.

Fazit

Der AJAX-Upload von Dateien ist dank XHR2 und FormData wirklich einfach umzusetzen.

Schade ist, dass FormData nicht innerhalb von HTML5 Web Workers genutzt werden kann. Demnächst zeige ich euch aber, wie ihr euch einfach selbst eine FormData-Klasse für den Einsatz innerhalb von Web Workers erstellen könnt.

Ach fast hätte ich es vergessen, eine gute Anlaufstelle für weitere XHR2-Beispiele ist HTML5Rocks: Neue Tricks für XMLHttpRequest2

Wie findet ihr die Möglichkeit mit XHR2 und FormData Dateien hochzuladen? Habt ihr euch schon näher mit XHR2 beschäftigt?

Kommentare  
0 Kommentare vorhanden
0 Trackbacks/Pingbacks vorhanden
Du bist herzlich eingeladen auch ein Kommentar zu hinterlassen!
Kommentar schreiben

Vielen Dank für dein Kommentar!