File Upload
Eine der häufigsten Aufgaben im Webdesign ist das Senden von Formulareingaben. Oft will man jedoch nicht nur Daten, sondern ganze Dateien wie Bilder, PDFs oder Text-Dokumente hochladen.
Dieses Tutorial zeigt, wie man ein Eingabeformular für den Datei Upload erstellt und welche browserseitigen Sicherheitsvorkehrungen dabei beachtet werden müssen.
Inhaltsverzeichnis
input type="file"
Mithilfe des Formularelements input type="file" kann der Anwender eine Datei von seinem lokalen Rechner zusammen mit dem Formular übertragen (Upload). Durch das Attribut type="file"
erstellt der Browser automatisch ein Eingabefeld für den Pfad zur Datei und einen Button mit dessen Hilfe eine lokale Datei ausgewählt werden kann. Die Größe des Eingabefeldes kann wie üblich mit dem size-Attribut festgelegt werden.
Dieses Element funktioniert nur mit der POST
-Methode und nicht mit GET
. Außerdem muss im Formular das enctype="multipart/form-data"-Attribut notiert werden, da sonst nur der Name und nicht die Datei selbst übertragen wird.
accept
Mithilfe des accept-Attributs kann angegeben werden, welche Dateitypen für den Upload vorgesehen sind. Eine durch Komma getrennte Liste von Dateitypangaben kann der Browser dafür nutzen Dateien, aus denen der Anwender im Dateidialog auswählen kann, vorzufiltern. Der Anwender kann diese Filterung jedoch übergehen.
Als Dateityp kannst du auf Computern, die Extensions benutzen, eine File Extension (.txt
, .png
, .exe
) verwenden, eine MIME-Typangabe (text/plain
) oder eine MIME-Typ Sammelangabe ("audio/*). Die im Beispiel verwendete Angabe text/*
ist hingegen zwiespältig zu sehen: Die HTML Spezifikation nennt ausdrücklich nur audio, video und image als gültige Typen für Sammelangaben. Es kann also sein, dass der Browser diese accept-Angabe ignoriert und dem Anwender einfach alle Dateien anbietet.
<form method="post" enctype="multipart/form-data">
<label>Wählen Sie eine Textdatei (*.txt, *.html usw.) von Ihrem Rechner aus.
<input name="datei" type="file" size="50" accept="text/*">
</label>
<button>… und ab geht die Post!</button>
</form>
Hier ist die Breite des Eingabefeldes auf 50 Zeichen festgelegt und es sind alle Textdateien erlaubt. Zusätzlich sei noch erwähnt, dass es sinnvoll ist einen Submit-Button hinzuzufügen, da diverse Browser neueren Datums ein unmittelbares Ausführen über das Textfeld mit dem Dateipfad der gewählten Datei der Aktion nicht mehr zulassen.
Information: Kann ich Datei-Upload-Formulare vorbelegen?
Aus Sicherheitsgründen ist das Vorbelegen dieses Formularelements mithilfe des value
-Attributs nicht möglich.
mehrere Dateien auf einmal hochladen
Mit dem booleschen Attribut multiple kann eine Mehrfachauswahl zugelassen werden, sodass anschließend mehrere Dateien vom Browser an den Server übermittelt werden. Damit die verwendete serverseitige Script-Sprache mit mehreren Dateien zu diesem input
-Feld umgehen kann, ist es unter Umständen notwendig einen geeigneten Namen im name
-Attribut zu notieren (PHP benötigt z. B. ein eckiges Klammernpaar wie name="datei[]"
, damit nicht nur die letzte übertragene Datei erkannt wird).
<form action="manage_uploads.php" method="post" enctype="multipart/form-data">
<label>Wählen Sie die hochzuladenden Dateien von Ihrem Rechner aus:
<input name="datei[]" type="file" multiple>
</label>
<button>hochladen</button>
</form>
Der empfangende Webserver kann aus z. B. Sicherheitsgründen ein Limit für die Anzahl und die Datenmenge der zu empfangenden Dateien haben. Als HTML-Frontend-Designer hat man darauf keinen Einfluss und selbst als Programmierer der serverseitigen Programmlogik gibt es unter Umständen keine Möglichkeit diese Einstellungen des Servers zu ändern. In solchen Fällen benötigt man eine Lösung, bei der vom Browser die Datenmenge in passend kleinen Teilen übertragen wird, um sie dann auf der Serverseite wieder zusammen zu setzen.
→ PHP/Tutorials/File Upload
Multiupload per JavaScript unterstützen
File API
Mit JavaScript und der HTML5 File API kannst du nun deine HTML-Formulare durch weitere Funktionen erweitern, die dem Benutzer der Seite mehr Komfort bieten.[1][2]
Interessant ist hierbei vor allem, dass die APIs die Möglichkeit bieten den Uploadfortschritt zu verfolgen, Thumbnails (Miniaturansichten) der Dateien anzuzeigen, sowie der Einsatz von Drag and Drop. Letzteres ist sehr bequem um Dateien vom Desktop oder aus Ordnern direkt in die Webanwendung zu ziehen, in die die Datei geladen werden soll.
Multi Upload von Dateien
Das Eingabefeld besteht eigentlich aus mehreren im Shadow DOM versteckten Elementen:
Bei der Auswahl einer Datei wird deren Name im versteckten span-Element angezeigt. Bei mehreren ausgewählten Dateien erscheint aber nur die Anzahl. Um dem Benutzer die Namen, MIME-Typen und auch die Dateigröße anzuzeigen, erweitern wir unser Code-Snippet aus dem letzten Abschnitt.
document.getElementById('dateien').addEventListener('change', dateiauswahlGeändert);
function dateiauswahlGeändert(filesChangedEvent) {
// Verweis auf das ul-Element, das die Liste der ausgewählten Dateien aufnimmt.
// Eventuellen alten Inhalt beseitigen
const dateiliste = document.getElementById('dateiListe');
dateiliste.innerHTML = '';
// Iteratorschleife, die alle Elemente im files-Array des input-Elements (event.target)
// durchlaufen. Pro Datei den Namen, den Typ und die Größe in einem li-Element
// eintragen und ans Ende der Liste anfügen
for (const file of filesChangedEvent.target.files) {
dateiliste.insertAdjacentHTML('beforeend',
`<li><strong>${file.name}</strong> (${file.type || 'n/a'}) - ${file.size} bytes</li>`);
}
}
Sobald im Formular etwas geändert wird, feuert das change-Event und ruft die Funktion dateiauswahlGeändert()
auf.
Sie durchläuft das FileList-Objekt des input-Elements. Eine FileList gehört zu den iterierbaren Datensammlungen, wir können deshalb die for...of-Schleife verwenden. Vor der Schleife beschaffen wir uns noch das <ul
-Element, das im HTML darauf wartet, die Liste der ausgewählten Dateien darzustellen.
In der Schleife nutzen wir die insertAdjacentHTML-Methode, die jedes HTML Element anbietet, um HTML-Fragmente in seinem Umfeld zu ergänzen. Die Variante beforeend
fügt das übergebene HTML an das Ende des bestehenden Inhalts an.
Hinzugefügt wird ein <li
-Element für die Dateiliste, in dem der Dateiname (durch <strong
hervorgehoben), der MIME-Typ der Datei und ihre Größe eingetragen werden. Auf eine weitere Formatierung verzichten wir der Einfachheit halber. Natürlich könnten Sie auch eine Tabelle erzeugen.
Auswahl mit Bildvorschau
Noch übersichtlicher ist das Anzeigen kleiner Vorschaubilder - sogenannter Thumbnails.
if (file.type.startsWith('image/')) {
const thumbnailURL = URL.createObjectURL(file);
const listItem = document.createElement('li');
const imgElement = document.createElement('img');
imgElement.src = thumbnailURL;
imgElement.alt = file.name;
imgElement.onload = () => URL.revokeObjectURL(imgElement.src);
listItem.appendChild(imgElement);
thumbnailListe.appendChild(listItem);
}
In diesem Beispiel werden von den hochzuladenden Bildern Vorschaubilder erstellt (Thumbnailing), die dann im Ausgabefeld output-Element angezeigt werden.
Dabei wird zuerst mit file.type.startsWith() überprüft, ob der Beginn des MimeType-Strings mit image
beginnt.
Falls ja, wird mit …
- Document/createElement() ein neues li und ein img-Element erzeugt.
- mit
imgElement.src
erhält es die über createObjectURL ermittelte URL - und den file.name als alt-Text.
Dieses wird dann mit appendChild in die Liste eingehängt.
Auswahl mit Drag und Drop
Einfacher als die Suche mit der browsereigenen Dateiauswahl ist das ziehen der gewünschten Dateien mit Drag & Drop
const dropZone = document.getElementById('dropZone');
// Drag and Drop event listeners
dropZone.addEventListener('dragenter', preventDefaults, false);
dropZone.addEventListener('dragover', preventDefaults, false);
dropZone.addEventListener('dragleave', preventDefaults, false);
dropZone.addEventListener('drop', handleDrop, false);
dropZone.addEventListener('dragenter', () => dropZone.classList.add('dragover'), false);
dropZone.addEventListener('dragleave', () => dropZone.classList.remove('dragover'), false);
dropZone.addEventListener('drop', () => dropZone.classList.remove('dragover'), false);
});
function preventDefaults(event) {
event.preventDefault();
event.stopPropagation();
}
// Handle files dropped into the drop zone
function handleDrop(e) {
preventDefaults(e);
const dt = e.dataTransfer;
const files = dt.files;
dateiauswahlGeändert({ target: { files } });
}
Hier können Sie Bilder und Dateien aus Ihrem Betriebssystem bequem mit der Maus (Drag & Drop) ziehen und im div mit der id dropzone
ablegen.
Anschließend wird die ausgewählte Datei wie in den oberen Beispielen mit einigen Eigenschaften aufgelistet.
SELFie erzeugen und hochladen
Mit dem capture-Attribut kann künftig festgelegt werden, dass keine Datei vom Gerät übertragen, sondern eine neue Mediendatei aufgenommen werden soll. Mit Hilfe des zusätzlichen accept-Attributs wird festlegt, ob es sich um eine Ton-, Bild- oder Videoaufnahme handeln soll.
<label for="imageFile">Lade Dein Foto zur Authenifizierung hoch:</label>
<input type="file" id="imageFile" capture="user" accept="image/*" >
(billiger) Hex-Viewer im Browser
ToDo (weitere ToDos)
ist dieses Snippet sinnvoll?
Traut euch und entscheidet! --Matthias Scharwies (Diskussion) 09:59, 21. Jan. 2023 (CET) function dateiauswahl(evt) {
var dateien = evt.target.files; // FileList object
// Auslesen der gespeicherten Dateien durch Schleife
for (var i = 0, f; f = dateien[i]; i++) {
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
// Bytedaten übernehmen
var byteBlock = e.target.result; // ArrayBuffer Objekt
// ein Objekt um den Byteblock auszulesen
var dataViewer = new DataView(byteBlock);
var hexView = "";
// Hex-Werte übernehmen
for (var j = 0; j < f.size; j++) {
hexView += parseInt(dataViewer.getUint8(j), 16) + " ";
}
// Das Leerzeichen am Ende entfernen
hexView = hexView.substr(0,hexView.length-1);
// erzeuge "Thumbnails"
var vorschau = document.createElement('p');
vorschau.className = 'thumb';
vorschau.src = hexView
vorschau.title = theFile.name;
document.getElementById('list').insertBefore(vorschau, null);
};
})(f);
// Datei als ByteArray auslesen auslesen.
reader.readAsArrayBuffer(f);
}
}
// Auf neue Auswahl reagieren und gegebenenfalls Funktion dateiauswahl neu ausführen.
document.getElementById('files').addEventListener('change', dateiauswahl, false);
Hiermit können die Hexwerte jeder beliebigen Datei ausgelesen werden.
Siehe auch
- PHP/File Upload
sehr ausführlicher Artikel mit dem Schwerpunkt Sicherheit
Weblinks
- html5rocks: Reading files in JavaScript using the File APIs
- hexed.it: HexEditor
- MDN: FileReader
- MDN: ArrayBuffer
- MDN: DataView