File Upload

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

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.

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.

Beachte: Beim Absenden des Formulars wird zwar die gewählte Datei auf den Server übertragen, jedoch nur in einem temporären Verzeichnis gespeichert. Am Ende des Requests wird sie wieder verworfen. Es bedarf serverseitig eines Scriptes (PHP, Node.js, JSP, …), um die Datei nach dem Upload dauerhaft in ein anderes Verzeichnis auf dem Server abzulegen. Die serverseitige Perspektive wird im Folge-Kapitel PHP/Tutorials/File Upload behandelt.

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.

Upload von Text-Dateien ansehen …
<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.

Beachte: Da die accept-Angabe nur eine Komfortfunktion für den Anwender ist und im Dateiauswahldialog überschrieben werden kann, muss serverseitig zwingend überprüft werden, ob die hochgeladene Datei den erwarteten MIME-Typ hat.

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

mehrere Dateien hochladen
<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:

"screenshot eines File-Upload-Elements in Chrome 109"

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.

Anzeige der ausgewählten Dateien ansehen …
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.

Dateiupload mit Thumbnails ansehen …
        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 …

Dieses wird dann mit appendChild in die Liste eingehängt.

Beachte: Textdateien werden nicht dargestellt.

Auswahl mit Drag und Drop

Einfacher als die Suche mit der browsereigenen Dateiauswahl ist das ziehen der gewünschten Dateien mit Drag & Drop

alternative Auswahl mit Drag &Drop ansehen …
      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.

Kamera aktivieren und Foto übertragen
  <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)
Beispiel
  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.

Beachte: Das DataView-Objekt ist so mächtig, dass man hiermit einen voll funktionsfähigen Hex-Editor im Browser erstellen kann. Daher sollte der Gebrauch des ArrayBuffer- und des DataView-Objekts mit Vorsicht genossen werden.

Siehe auch

  • PHP/File Upload

    sehr ausführlicher Artikel mit dem Schwerpunkt Sicherheit

Weblinks

  1. W3C: File API
  2. MDN: File API