Anzeige
Tutorialbeschreibung

File-Upload via PHP

File-Upload via PHP

Schritt 1: Das Formular

Zuerst benötigen wir ein HTML-Formular, mit dem wir eine Datei von unserer Festplatte auswählen können, die dann an den Server geschickt wird.

Dazu legen wir uns die Datei "index.php" an und parallel dazu den Ordner "uploads" an, in den dann die hochgeladenen Dateien kommen sollen.

Fangen wir also mit einfachem HTML an:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de">
 <head>
 <title>File-Upload</title>
 <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/>
 </head>
 <body>
 <h1>Dateiupload mit PHP</h1>
 <form name="upload" action="index.php" method="post" enctype="multipart/form-data">
 <label for="myfile">Datei:</label>
 <input type="file" name="myfile" id="myfile" />
 <input type="submit" value="Hochladen" />
 </form>
 </body>
</html>

In dem HTML-Body haben wir ein Formular mit dem Namen "upload". Dessen Werte werden per POST an die Datei "index.php" (also an sich selbst) geschickt.

Wichtig ist das Attribut enctype mit dem Wert multipart/form-data. Wenn ihr das weglasst, dann werden eure Dateien nicht an den Server geschickt.

Nun fügen wir zwei input-Felder zum Formular hinzu: Das erste ist unser Datei-Feld mit dem Label "Datei:". Es ist vom Typ file und trägt den Namen myfile.
Zum Absenden des Formulars brauchen wir noch einen submit-Button mit dem Text "Hochladen".

Das Ganze sollte im Browser dann so aussehen:

Bilder




 

Schritt 2: Die Upload-Logik und Validierung

Jetzt kommen wir zum PHP-Teil unseres Codes, in dem wir auch validieren wollen, dass die Datei nicht zu groß ist und evtl. nur ein bestimmter Dateityp ist. Validierung ist immer wichtig, wenn Daten vom Benutzer an den Server geschickt werden, und sollte mit paranoidem Fanatismus verfolgt werden.

Wir werden unsere index.php nun um wunderbar einfaches PHP erweitern, aber vorher noch ein paar Infos, denn wir wollen ja nicht nur Code kopieren, sondern auch kapieren.

Wenn Dateien an den Server geschickt werden, so landet jegliche Information darüber in dem Array $_FILES, so wie Formulardaten per post im $_POST-Array und per get im $_GET-Array landen.

Der $_FILES-Array sollte (wenn man ihn sich mit der php-Funktion print_r ausgibt) so aussehen:
Array
(
 [myfile] => Array
 (
 [name] => Tulips.jpg
 [type] => image/jpeg
 [tmp_name] => C:xampp	mpphp9438.tmp
 [error] => 0
 [size] => 620888
 )

)

Für jedes files-Feld in eurem Formular bekommt ihr in dem $_FILES-Array einen Eintrag mit dem Namen eures Feldes. Bei uns im Formular heißt das Input-Feld "myfile" weswegen auch der Eintrag im Array "myfile" heißt.

Dieser Eintrag ist wieder ein Array mit folgenden Werten:

name = Name der Ursprungsdatei auf eurer Festplatte
type =MIME-Type der Datei (in unserem Fall ein jpeg)
tmp_name =Pfad zur Datei auf dem Server (da es hier lokal läuft, ist das der absolute Pfad zum temporären Verzeichnis meines Apache-Servers (xampp) ). Auf eurem Server kann das so aussehen /usr/www/htdocs/somesite/...
error =0 bedeutet kein Fehler; ansonsten Werte zwischen 1 und 4, deren Bedeutung ihr hier nachlesen könnt.
size = Dateigröße


Da wir nun wissen, ob unsere Datei hochgeladen wurde und wo sie auf unserem Server zu finden ist, müssen wir nur noch validieren und die Datei verschieben. Kommen wir nun also endlich zum Code, den wir ganz oben in unserer index.php einfügen:

<?php
$allowedFileSize = 1024*1024*5; //5 MB
$uploadFolder = dirname(__FILE__) . '/uploads/';
if (!empty($_FILES['myfile'])) { // wurde das Formular überhaupt abgeschickt
 
 if ($_FILES['myfile']['error'] === 0) { //kein Fehler beim Upload

 if (!file_exists($uploadFolder . $_FILES['myfile']['name'])) { //eine Datei mit dem Namen existiert noch nicht
 
 if ($_FILES['myfile']['size'] < $allowedFileSize) { // ist die Datei klein genug

 if (preg_match('/.(jpe?g|gif|png|zip)$/i',$_FILES['myfile']['name'])) { // hat die Datei eine der folgenden Endungen (jpg, jpeg, gif, png, zip)

 //keine fehler, dann verschiebe die Datei in meinen uploads-Ordner
 if (is_uploaded_file($_FILES['myfile']['tmp_name'])) {
 if (move_uploaded_file($_FILES['myfile']['tmp_name'], $uploadFolder . $_FILES['myfile']['name'])) {
 $success = 'Die Datei wurde hochgeladen';
 } else {
 $error = 'Fehler beim Verschieben der Datei.';
 }
 } else {
 $error = 'Die Datei wurde nicht mittels HTTP-POST hochgeladen.';
 }

 } else {
 $error = 'Es sind nur folgende Dateiendungen erlaubt: jpg, jpeg, gif, png, zip';
 }

 } else {
 $error = 'Die Datei überschreitet die vom PHP-Script zugelassene Dateigröße.';
 }
 } else {
 $error = 'Eine Datei mit diesem Namen existiert schon.';
 }

 } else {
 switch($_FILES['myfile']['error']){
 case 1: // UPLOAD_ERR_INI_SIZE
 $error = 'Die Datei überschreitet die vom Server zugelassene Dateigröße.';
 break;
 case 2: // UPLOAD_ERR_FORM_SIZE
 $error = 'Die Datei überschreitet die vom Formular zugelassene Dateigröße.';
 break;
 case 3: // UPLOAD_ERR_PARTIAL
 $error = 'Die Datei wurde nur teilweise hochgeladen.';
 break;
 case 4: // UPLOAD_ERR_NO_FILE
 $error = 'Es wurde keine Datei hochgeladen.';
 break;
 }
 
 }
}
?>

Zuerst setzen wir die zwei Variablen $allowedFileSize und $uploadFolder. Die erlaubte Dateigröße ist hier 5MB. Der Uploadfolder liegt neben der index.php, weswegen wir mit der Funktion dirname den Pfad zur aktuellen Datei (__FILE__) auslesen und das "/uploads/" dranhängen. Somit haben wir eine absolute Angabe, wo auf unserem Server das Upload-Verzeichnis zu finden ist. Das Verzeichnis muss vom Server beschreibbar sein (chmod: 755 oder 777).

Jetzt kommen wir zur Validierung, die im Wesentlichen aus vielen if-else Konstrukten besteht, in denen wir prüfen und evtl. einen Fehler in unsere Fehlervariable $error speichern.

Als Erstes prüfen wir, ob das Formular überhaupt abgeschickt wurde, da wir sonst nichts tun müssen. Anschließend, ob der Upload einen Fehler hatte oder erfolgreich war. Wenn er nicht erfolgreich war, geben wir für jeden Error-Code eine eigene Fehlermeldung aus. Wenn ihr das Skript live verwendet, dann solltet ihr darauf achten, dem Besucher nicht den exakten Fehler zu sagen, da es Sicherheitslücken offenbaren könnte. Da wäre ein allgemeiner Fehler "Upload fehlgeschlagen" wohl die bessere Lösung. Hier aber ist ein exakter Fehler erwünscht, da wir wissen wollen, was genau schiefgelaufen ist. Jetzt prüfen wir, ob eine Datei mit demselben Namen schon im Upload-Ordner liegt, da sie sonst überschrieben würde, und danach, ob die Dateigröße nicht unser Limit überschreitet.

Wenn ihr euch noch nie mit regular expressions beschäftigt habt, ist das kein Problem. Früher oder später werdet ihr dieses mächtige Tool lieben und fürchten lernen. Man kann sich mit regular expressions viel erleichtern, aber auch viel Zeit damit totschlagen ;)

Was wir hier machen, ist, zu schauen, ob die Datei auf .jpg, .jpeg, .gif oder .zip endet (case-insensitive).

Der eigentliche Kern des Dateiuploads (neben dem Formular) besteht aus den zwei PHP-Funktionen is_uploaded_file und move_uploaded_file. Zuerst schauen wir, ob es sich überhaupt um eine Datei handelt, die per HTTP-POST hochgeladen wurde, und dann verschieben wir sie in unseren Upload-Ordner. Es ist darauf zu achten, dass die Destination, also der zweite Parameter der Funktion, nicht nur ein Pfad zu dem Ordner ist, sondern auf einen Dateinamen enden muss, was in unserem Fall der ursprüngliche Name der Datei auf der Festplatte ist. Hier könnte man Dateien aber auch umbenennen, indem man einfach einen anderen Dateinamen angibt. Sollte die Datei in dem Ordner schon existieren, so wird diese kommentarlos von PHP überschrieben. Man sollte also Vorsicht walten lassen.


Schritt 3: Ausgabe der Fehler

Was jetzt noch fehlt, ist die Ausgabe unserer Fehlervariablen $error oder des Erfolges $success. Dazu müssen wir unser in Schritt 1 geschriebenes HTML noch ein bisschen erweitern. Nach der h1-Überschrift fügen wir folgenden Code ein:
<?php if (isset($error) && !empty($error)): ?>
 <p><strong>Fehler: </strong><?= $error; ?></p>
<?php endif; ?>
<?php if (isset($success) && !empty($success)): ?>
 <p><strong><?= $success; ?></strong></p>
<?php endif; ?>

Sobald die Fehlervariable gesetzt und nicht leer ist, wird der Fehler ausgegeben. Dasselbe gilt für die Erfolgsvariable. Das war es dann auch schon. Eure Dateien liegen in dem Upload-Ordner und können verwendet werden.

Ich hoffe, ihr habt alles verstanden und könnt nun endlich euren Traum vom Dateiupload realisieren.

Grüße, uracil

Kommentare
Achtung: Du kannst den Inhalt erst nach dem Login kommentieren.
Portrait von wahke
  • 26.12.2010 - 01:02

super einfach genial

Portrait von quester_max
  • 14.11.2010 - 15:02

sehr informative und hats weiter gebracht danke schon

Portrait von lomonosoff
  • 27.10.2010 - 13:45

Sehr gutes Tutorial. Alles gut erklärt, sehr deutlich und verständlich. Danke.

Portrait von Susan99
  • 25.10.2010 - 18:39

Danke. Ein gutes Tutorial, gut nachvollziehbar.
MfG Susan

Portrait von CrysKey
  • 23.10.2010 - 15:22

Ganz brauchbar, mit einigen Ergänzungen!

Portrait von sokie
  • 22.10.2010 - 23:35

das Script sollte nicht so eingesetzt werden, wenn nicht überprüft wird, was die Dateien beinhalten. Nur die Endung überprüfen reicht nicht. Es würden sich auch dateien mit code hochladen lassen.

Portrait von uracil
  • 27.10.2010 - 17:08

Jupp, das stimmt :)
Man sollte eher den MIME Type im FILES Array überprüfen. Ich wollte nur das Tut nicht zu komplex machen.

Portrait von EnricoS
  • 22.10.2010 - 14:23

Zwei Sachen würde ich noch ergänzen:
1. Die maximale Ausführungszeit von Skripten via ini_set setzten, da dein Skript je nach Konfigruation und Bandbreite abgebrochen werden könnte.
2. Fehlerhafte Daten (zu groß, falscher Dateityp) solltest du sofort löschen und nicht einfach auf dem Server liegen lassen. Du verlässt dich andernfalls zu sehr auf den Server, dass er dir die Arbeit abnimmt. Wenn er das nicht tut könnte dein Webspace bei Zeiten voll sein.

An sonsten ein ganz nettes, simples Skript wie überall im Netz zu finden.

Portrait von uracil
  • 22.10.2010 - 14:28

Jap, da hast du recht. Wobei der Server temp Ordner - wenn mich nicht alles täuscht - eh die alten Dateien rausschmeißt, oder?

Portrait von carlos18182
  • 22.10.2010 - 09:25

Vielen Dank, das habe ich gesucht.

Portrait von tzoumaz
  • 22.10.2010 - 08:13

Du schreibst, man soll auch alles verstehen. Bin jetzt nicht so der Php-Freak, aber Du hast Datei, Durchsuchen und Hochladen in deinem Formular. Wo wird denn Durchsuchen behandelt? Oder ist das nicht erforderich

Portrait von uracil
  • 22.10.2010 - 14:26

Der "Durchsuchen" Button ist ein Standardfeld, dass zu dem input type="file" gehört. Soweit ich weis kann man das nicht ändern.
Siehe: http://de.selfhtml.org/html/formulare/datei_upload.htm

Portrait von B00mer
  • 22.10.2010 - 07:57

Danke! Kann ich sicherlich mal brauchen.

Portrait von xxchucki
  • 24.10.2010 - 15:12

Ah das mit dem $Files habe ich übersehen^^...

Portrait von xxchucki
  • 21.10.2010 - 19:11

Ich habe etwas kritik :
1.)
Der HTML Code :



File-Upload



Dateiupload mit PHP
upload</a>" action="index.php" method="post" enctype="multipart/form-data">
Datei:

Hochladen</a>" />



Der Form Name ist völlig unsinnig und total unnötig. Das hättest du in ein Wort fassen können. Der Submit Value ist genauso schwachsinnig und hättest du auch in ein Wort fassen können..
Die Labels sind optional und verlängern auch nur den Code und machen alles schwerer...

2.)
Zu der Datei :
Wie ich es verstanden habe, hast du alles in eine Datei geschrieben... Jetzt ist dabei der Fehler, dass man Fehler kriegen wird wenn du den PHP Code nach oben schreibst... Die ganzen Variablen sind nähmlich undeklariert bevor du auf Submit gedrückt hast.
Ich hätte das mit einer Unterseite gemacht also ungefähr so :
index.php?upload=true
Und dann im PHP Teil :
$seite = $_GET["upload"];
If (isset($seite)) {
//PHP CODE
}

Ich gebe dir 1 Punkt für den HTML, 4 Punkte für den PHP und 2 Punkte zur Funktion... Macht 7/3 : 2 Punkte

Portrait von uracil
  • 21.10.2010 - 19:30

Mit dem name-Attribut hast du recht. man kann es weg lassen, sollte aber kein "Fehler" sein im sinne des Markups, genauso wie das value-Attribut des submit Buttons. Ich hab da gerne etwas anders stehen als "Absenden" und im Sinne eines Tutorials habe ich es der Vollständigkeit halber mit reingenommen. Zu deinem Punkt der Labels habe ich nur ein Schlagwort zu sagen: Barrierefreiheit. Labels machen zwar den Code länger, erleichtern aber vielen Menschen den Umgang mit Formularen und machen definitiv nichts schwerer.

Zum PHP: Ja ich habe alles in eine Datei geschrieben, und nein man wird keinen Fehler bekommen, sondern höchstens ein Warning. Doch selbst das wird man nicht zu Gesicht bekommen, da a) sich der komplette Überprüfungscode innerhalb der Bedinung "!empty($_FILES['myfile'])" liegt. Das FILES Array ist immer gesetzt, weswegen es keinen Fehler gibt. Bei der Ausgabe der Fehler (was tatsächlich die einzigen Variablen sind die nicht gesetzt sind wenn man das Formular abgesendet hat) wird überprüft ob diese gesetzt sind "isset($var)". Ergo: Kein Fehler und deine eher unschöne Lösung mit der GET Variablen kann man sich sparen.

Ich hoffe ich konnte dir helfen meinen Code zu verstehen (Da ich immer mit error_reporting(E_ALL) arbeite und das Skript überprüft habe kann ich dir versichern, dass es keine Fehler wirft).

Grüße!

Portrait von mros
  • 21.10.2010 - 19:00

Super - kann ich gut gebrauchen - DANKE

Portrait von Fidelis_jpg
  • 21.10.2010 - 16:46

Cool, das habe ich schon immer mal gesucht, vor allem als Tutorial! Werde ich mir gleich mal durchlesen!
Vielen Dank!

x
×
×