![]() |
Dateiupload und Überprüfung mit PHP |
|
| |
| E-Mail: | |
|---|---|
| Homepage-URL: |
Bei Fragen zu diesem Beitrag bitte den Autor des Beitrags kontaktieren!
Irgendwann kommt man in die Notwendigkeit, den User eine Datei auf den Server übertragen zu lassen. Eben einen File-Upload zu realisieren. Mit PHP geht das relativ einfach, wobei man aber die Sicherheit nicht außer acht lassen sollte.
Dieser Artikel versucht, die Grundlagen zum File-Upload und die notwendigen Funktionen zum Überprüfen der Daten zu vermitteln.
Frühere Versionen dieses Artikels haben sich auf die Konfigurationseinstellung register_globals=on verlassen. PHP empfiehlt, diese Option abzuschalten und wird so auch auf vielen Webservern betrieben.
Aus HTML-Sicht sieht ein File-Upload etwa so wie im folgenden Beispiel aus.
<form enctype="multipart/form-data" action="<?php echo htmlspecialchars ($_SERVER['PHP_SELF']); ?>" method="post"> <input type="hidden" name="max_file_size" value="1000"> file senden: <input name="thefile" type="file"> <input type="submit" value="senden"> </form>
| Code | Bedeutung |
|---|---|
enctype="multipart/form-data" |
Der enctype ist sehr wichtig, ohne ihn funktioniert kein File-Upload. (wenn die method="post" ist und kein enctype gesetzt ist, lautet er standardmäßig application/x-www-form-urlencoded) |
action="<?php echo htmlspecialchars ($_SERVER['PHP_SELF']); ?>" |
Die PHP-Variable $_SERVER['PHP_SELF'] enthält den Namen (+ evtl. Pfad) des aktuellen Dokumentes. Selbstverständlich kann auch ein eigener Name angegeben werden. Sollte wie hier $_SERVER['PHP_SELF'] verwendet werden, so muss auf jeden Fall htmlspecialchars angewendet werden, da die Variable unter bestimmten Umständen mit Daten von der Clientseite gefüllt werden kann und daher nicht vertrauenswürdig ist! |
<input type="hidden" name="max_file_size" value="1000"> |
Dieses Input-Feld teilt dem Browser mit, wie groß ein File maximal sein darf. Aber da dieser Wert von der Clientseite kommt, sollte man nicht zu stark darauf vertrauen! |
<input name="thefile" type="file"> |
Mit diesen Formularfeld wird schließlich der "Dateisystem - Auswahl - Button" angezeigt, mit dem der User ein File von seiner lokalen Festplatte auswählen kann. |
Im allgemeinen macht es wenig Sinn, das Formular und die PHP-Seite als getrennte Seite zu handhaben.
Folgende Struktur hat sich bewährt:
<html> <!-- Der Kopf der HTML seite inkl evt. layout //--> <?php if(isset($_POST['submit']) && $_POST['submit']=="Senden"){ // Das Formular wurde gesendet }else{ // Das Formular muss angezeigt werden ?> <!-- Das Formular //--> <?php } ?>
PHP stellt uns freundlicherweise einige Variablen zur Verfügung, die uns das Arbeiten mit dem File des Users erleichtern.
Beachten Sie hierbei, dass normale Formularfelder des Dateiabsendeformulars in $_POST landen, während alle Dateiuploadfelder in das Array $_FILES geschrieben werden. Das Array enthält diverse Dateiinformationen in den Feldern des Arrays:
| Variable | Bedeutung |
|---|---|
$_FILES['thefile']['tmp_name'] |
Pfad und Name der temporären Datei, wie sie im Filesystem des Servers zu finden ist (meistens in der Form /tmp/php234lksdaflk) - diese Datei wird am Skriptende wieder gelöscht. |
$_FILES['thefile']['name'] |
Der Name der Datei, wie sie auf dem Clientsystem genannt wurde. Eventuelle Verzeichnisangaben werden nicht mitgesendet. |
$_FILES['thefile']['size'] |
Die Größe der Datei in Bytes |
$_FILES['thefile']['type'] |
Der Mime-Type der Datei, wie der Client sie lieferte (z.B. image/gif). |
Die hochgeladene Datei ist nur solange "existent" wie das Skript läuft. Das heißt, um das File auch für spätere Zugriffe haltbar zu machen, muß es kopiert bzw. verschoben werden.
Normalerweise kann das File überall dorthin kopiert werden wo der Apache-Prozeß Schreibrechte besitzt. Ist allerdings der Safe_Mode aktiv, kann man das File nur in Verzeichnisse schreiben, welche die selbe UID wie der Apache Prozess haben.
Das schönste Upload-Skript nützt nichts, wenn man nicht weiß, um welche Art von Datei es sich handelt.
Ich verwende normalerweise je nach erwartetem Filetype zwei verschiedene Wege der Dateiüberprüfung:
Wenn es sich um Bilder in den Format *.jpg oder *.gif handelt, verwende ich normalerweise die Funktion getimagesize(), die einen Array mit Informationen zurückliefert. Wenn man beispielsweise notiert: $size=getimagesize($_FILES['thefile']['tmp_name']);, dann hat man anschließend folgende Informationen:
$size[0] = Breite der Grafik,
$size[1] = Höhe der Grafik,
$size[2] = Typ der Grafik (wobei: 1 = GIF, 2 = JPG, 3 = PNG, 4 = SWF),
$size[3] = Breite und Höhe der Grafik als String "width=[...] height=[...]".
Siehe dazu auch:
Funktionsbeschreibung getimagesize() auf php.net
Eine allgemeinere Überprüng ist mittels der von PHP erstellten Variable $_FILES['thefile']['type'] möglich. Dort speichert PHP den vom Browser übermittelten Mime-Type der Datei. Aber verlassen Sie sich nicht blind auf diese Angabe - da der Browser den Mime-Typ ermittelt, kann dieser sich auch irren - oder die Angabe wird sogar absichtlich manipuliert.
Eine Überprüfung, ob es sich bei dem hochgeladenen File um ein Word-Dokument handelt, könnte z.B. so aussehen:
<?php if(isset($_FILES['thefile']['tmp_name']) && $_FILES['thefile']['type']=="application/msword"){
// weiter mit der Verarbeitung }else{ if(isset($_FILES['thefile']['tmp_name'])){ die("Dieses File ist kein MS-Word Dokument sondern hat den Mime-Type ".$_FILES['thefile']['type']); }else{ die("Kein File übertragen") // man muss hier nicht zwingenderweise abbrechen, // das File kann auch freiwillig übermittelt worden sein, // je nach Anforderung } } ?>
Wir überprüfen damit, ob ein File übertragen wurde. Wird kein File übertragen, existiert $_FILES['thefile']['tmp_name'] nicht. Desweiteren überprüfen wir, ob das File den richtigen Filetyp hat.
Man könnte auch noch überprüfen, ob das File eine festgeschrieben Größe nicht überschreitet, aber in unserem Beispiel ist das nicht notwendig. (der Vollständigkeit halber:if($_FILES['thefile']['size']>1000000){})
Nachdem wir uns jetzt sicher sind, daß das File ein Word-Dokument ist und unseren Ansprüchen genügt, kopieren wir es an eine andere Stelle, um es auch nach dem Ende des Skriptes zur Verfügung zu haben.
<?php
if(!move_uploaded_file($_FILES['thefile']['tmp_name'],"/pfad/zum/neuen/direktory/name.endung")){ // Ups, es passierte ein Fehler beim Kopieren } ?>
Weitere Informationen zum Behandeln von File-Uploads mit PHP sind im PHP-Handbuch zu finden: