SELFPHP

SELFPHP-Druckversion
Original Adresse dieser Seite:
http://www.selfphp.de/praxisbuch/praxisbuchseite.php?site=225&group=38
© 2001-2017 E-Mail SELFPHP OHG, info@selfphp.de
© 2005-2017 E-Mail PHP5 Praxisbuch - Matthias Kannengiesser, m.kannengiesser@selfphp.de


Datei-Upload via HTML-Formular


Sollten Sie Ihren Kunden die Pflege ihrer Daten überlassen, ist es in den meisten Fällen erforderlich, einen Datei-Upload bereitzustellen. Eine sinnvolle, wenn auch nicht immer effektive Alternative zum FTP-Zugriff ist der Upload von Dateien mithilfe von Formularen.


Aufbau des Formulars

Damit der Browser eine Datei vom Client zum Server überträgt, benötigen Sie ein <input>-Feld vom Typ file und das Attribut enctype="multipart/form-data" des <form>-Tags. Zusätzlich ist die Übertragungsmethode POST zwingend erforderlich, damit der Datei-Upload fehlerfrei durchgeführt werden kann. Es können sowohl Text- als auch Binärdaten hochgeladen werden.

Beispiel – Formular (up_form.html)
<html>
<head>
<title>Dateiupload</title>
</head>
<body>
<p><font face="Arial, Helvetica, sans-serif" size="6">Dateiupload via HTML </font></p>
<form method="post" action="upload.php" enctype="multipart/form-data">
  Datei:
  <input type="hidden" name="MAX_FILE_SIZE" value="100000">
  <input type="file" name="datei" size="40" maxlength="100000">
  <input type="submit" name="Submit" value="Senden">
</form>
</body>
</html>




Bild 4.10: HTML-Formular (up_form.html)

PHP stellt Ihnen die Möglichkeit zur Verfügung, über ein im Formular definiertes verstecktes Feld mit dem Namen MAX_FILE_SIZE die maximale Dateigröße festzulegen. Sollte eine größere Datei übertragen werden, so wird diese verworfen und ein Fehler ausgegeben. Sie sollten sich jedoch grundsätzlich nicht nur auf das versteckte Feld verlassen, sondern sollten serverseitig überprüfen, was tatsächlich übertragen wurde.


Informationen zur Datei

Bevor wir uns mit dem upload.php-Skript befassen, sollte ich Ihnen noch die Überprüfungsmöglichkeiten des Servers erläutern. Sobald eine Datei an den Server übertragen wird, wird automatisch das globale Array $_FILES erzeugt. In diesem assoziativen Array sind sämtliche Informationen zur Datei gespeichert.

Beispiel – Erfassen der $_FILES-Informationen

<html>
<head>
<title>Dateiupload</title>
</head>
<body>
<p><font face="Arial, Helvetica, sans-serif" size="6">Dateiupload via HTML </font></p>
<form method="post" action="<? echo $PHP_SELF ?>" enctype="multipart/form-data">
  Datei:
  <input type="hidden" name="MAX_FILE_SIZE" value="100000">
  <input type="file" name="datei" size="40" maxlength="100000">
  <input type="submit" name="Submit" value="Senden">
</form>
<?php

// Dateiinformationen (Ausgabe über Schleife)
if (isset($_FILES["datei"])) {
  foreach ($_FILES["datei"] as $key=>$element) {
    echo "[$key] => $element<br>";
  }
}
?>
</body>
</html>

Ausgabe
[name] => eingabe.zip
[type] => application/x-zip-compressed
[tmp_name] => C:\WINDOWS\TEMP\php7023.TMP
[error] => 0
[size] => 20764
{PSP}Hinter diesen fünf Elementen stecken folgende Details:

ElementSyntaxBedeutung
name$_FILES["datei"]["name"]Der ursprüngliche Dateiname auf der Clientmaschine. Der genaue Dateiname mit evtl. vorhandenen Laufwerksbuchstaben, Pfadseparatoren und anderen Sonderzeichen ist betriebssystemabhängig.
type$_FILES["datei"]["type"]Dieses Element enthält den MIME-Type der Datei, so wie er dem Server vom Browser übermittelt worden ist. Dieser Wert kann unter Umständen nicht richtig sein, je nach Einstellung des Browsers. Beim Ermitteln des Typs von hochgeladenen Grafiken sollte stattdessen die Funktion getimagesize() verwendet werden.
size$_FILES["datei"]["size"]Die Größe der hochgeladenen Datei in Byte.
tmp_name$_FILES["datei"]["tmp_name"]Dieses Element enthält den Namen der Datei in einem temporären Verzeichnis auf dem Server. Sie kann von dort mit einem move_uploaded_file()-Aufruf abgeholt werden. Das ist auch notwendig, da die Originaldatei am Ende des Skripts automatisch gelöscht wird.
error$_FILES["datei"]["error"]Dieses Element wurde mit PHP 4.2.0 eingeführt und enthält den Status des Datei-Uploads. Die möglichen Werte und dazugehörigen Konstanten finden Sie weiter unten.


Die wohl wichtigsten Informationen stecken in $_FILES["datei"]["size"], $_FILES["datei"]["type"] und $_FILES["datei"]["error"].
Mithilfe des Elemente $_FILES["datei"]["error"] können Sie kontrollieren, ob und welcher Fehler aufgetreten ist.

FehlerkonstanteWertBedeutung
UPLOAD_ERR_OK0Es liegt kein Fehler vor, die Datei wurde erfolgreich hochgeladen.
UPLOAD_ERR_INI_SIZE1Die hochgeladene Datei überschreitet die in der Anweisung upload_max_filesize in php.ini festgelegte Größe.
UPLOAD_ERR_FORM_SIZE2Die hochgeladene Datei überschreitet die in dem HTML-Formular mittels der Anweisung MAX_FILE_SIZE angegebene maximale Dateigröße.
UPLOAD_ERR_PARTIAL3Die Datei wurde nur teilweise hochgeladen.
UPLOAD_ERR_NO_FILE4Es wurde keine Datei zum Server übertragen, das Feld war leer.


Auch wenn kein Fehler aufgetreten ist, entbindet Sie dies nicht von der Aufgabe zu überprüfen, ob die Datei tatsächlich Ihren gewünschten Anforderungen entspricht. Grundsätzlich kann jede Benutzereingabe manipuliert sein, daher sollten Sie vor allem beim Datei-Upload möglichst auf Nummer sicher gehen.

Hinweis: Dateien, welche den Fehler UPLOAD_ERR_INI_SIZE oder UPLOAD_ERR_FORM_SIZE erzeugen, werden automatisch vom Server gelöscht.

Achtung: PHP 4-Versionen, die kleiner als PHP 4.1 sind, kennen das globale Array $_FILES nicht. Stattdessen können Sie auf das assoziative Array $HTTP_POST_FILES zurückgreifen.



Ablegen der Datei auf dem Server

Nun haben Sie es fast schon überstanden. Sobald eine Datei an den Server gesendet wurde, wird sie in einem temporären Verzeichnis unter einem temporären Namen gespeichert. Diese Datei wird jedoch automatisch gelöscht, wenn das verarbeitende Skript beendet ist. Sie müssen daher diese Datei zum endgültigen Ablageverzeichnis kopieren. Sie sollten sich nun der upload.php zuwenden, auf die im HTML-Formular für den Datei-Upload verwiesen wurde.

Beispiel – upload.php

<?php

// Prüfen des Arrays $_FILES
if (isset($_FILES["datei"])) {

// Upload-Status
if ($_FILES["datei"]["error"] == UPLOAD_ERR_OK) {

// Muster zur Überprüfung der im Dateinamen
// enthaltenen Zeichen (Optional)
$regExp = "/^[a-z_]([a-z0-9_-]*\.?[a-z0-9_-])*\.[a-z]{3,4}$/i";

// Dateiname und Dateigröße
if (preg_match($regExp,$_FILES["datei"]["name"]) && $_FILES["datei"]["size"] > 0 && $_FILES["datei"]["size"] < 100000) {

// Temporäre Datei in das Zielverzeichnis
// des Servers verschieben.
move_uploaded_file($_FILES["datei"]["tmp_name"],"shots/".$_FILES["datei"]["name"]);

// Redirect zur Erfolgsmeldung
header("Location: status.html");
}
else {
  echo "Fehler: Im Dateinamen oder Dateigrössen Limit!";
}
}
else {
  echo "Fehler: Während der Übertragung aufgetreten!";
}
}
else {
  echo "Fehler: Dateiupload fehlgeschlagen!";
}

?>
{PSP}Beispiel – status.html

<html>
<head>
<title>Dateiupload – Erfolgreich</title>
</head>
<body>
<p><font face="Arial, Helvetica, sans-serif" size="6">Upload: Erfolgreich</font></p>
<p><font face="Arial, Helvetica, sans-serif"><a href="up_form.html">[Zum Dateiupload]</a></font></p>
</body>
</html>

Eine sichere Funktion für Kopiervorgänge ist die Funktion move_uploaded_file(). Diese Funktion prüft, ob die angegebene Datei tatsächlich eine Uploaddatei ist, und verschiebt sie in das Zielverzeichnis. Dies können Sie der Codezeile aus dem Skript entnehmen:

move_uploaded_file($_FILES["datei"]["tmp_name"],"shots/".$_FILES["datei"]["name"]);

Mit dem ersten Argument wird der Dateiname der temporären Datei festgelegt und mit dem zweiten Argument legt man das Zielverzeichnis samt neuem Dateinamen fest. Im vorliegenden Fall entspricht der neue Dateiname dem ursprünglichen Dateinamen des Clientsystems.

Achtung: Die Funktion move_uploaded_file() ist lediglich für tatsächlich per Upload übertragene Dateien geeignet. Sollten Sie vorhaben, eine Datei des Dateisystems zu verschieben, so müssen Sie auf die Funktion copy() zurückgreifen und anschließend die Originaldatei entfernen.


Upload mehrerer Dateien

Das Auswählen mehrerer Dateien oder gar ganzer Verzeichnisse ist mit einem <input>-Feld nicht möglich. Auch das Vorgeben eines bestimmten Verzeichnisses oder vollständigen Pfads ist bei <input>-Feldern unterbunden, und zwar aus Sicherheitsgründen!



Bild 4.11: Datei-Upload via HTML



Bild 4.12: Gleich mehrere auf einen Streich

Mehrere Dateien lassen sich beispielsweise wie folgt übertragen:

Tipp: Ich empfehle Ihnen die gleiche Array-Sende-Syntax wie bei Auswahllisten mit Mehrfachauswahl und Checkboxen zu verwenden. Vergessen Sie nicht, die eckigen Klammen ([]) an den Namen des file <input>-Feldes anzuhängen, um in PHP ein Array mit den Dateiinformationen zu erhalten.

{PSP}Beispiel

<form action="multiupload.php" method="post" enctype="multipart/form-data">
  Dateien:<br>
  <input name="datei[]" type="file"><br>
  <input name="datei[]" type="file"><br>
  <input type="submit" value="Senden">
</form>

Wenn das obige Formular übermittelt ist, werden die Arrays $_FILES["datei"], $_FILES["datei"]["name"] und $_FILES["datei"]["size"] erzeugt. Der Name der ersten und zweiten Datei findet sich in diesem Beispiel unter:

$_FILES["datei"]["name"][0] // Erste Datei
$_FILES["datei"]["name"][1] // Zweite Datei

Diese Indizierung gilt auch für alle weiteren Dateiinformationen, wie $_FILES["datei"]["tmp_name"][0], $_FILES["datei"]["size"][0], $_FILES["datei"]["type"][0] und $_FILES["datei"]["error"][0].

Hier ein Beispiel, in dem eine HTML-Datei, ein PHP-Skript und ein Verzeichnis benötigt werden.

HTML-Datei (multiup_form.html)

<html>
<head>
<title>Dateiupload</title>
</head>
<body>
<p><font face="Arial, Helvetica, sans-serif" size="6">Dateiupload via HTML </font></p>
<form action="multiupload.php" method="post" enctype="multipart/form-data">
  Dateien:<br>
  <input type="hidden" name="MAX_FILE_SIZE" value="100000">
  <input name="datei[]" type="file" maxlength="100000"><br>
  <input name="datei[]" type="file" maxlength="100000"><br>
  <input name="datei[]" type="file" maxlength="100000"><br>
  <input type="submit" value="Senden">
</form>
</body>
</html>

PHP-Skript (muliupload.php)
<?

// Prüfen des Arrays $_FILES
if (isset($_FILES["datei"]))
{
  foreach ($_FILES["datei"] as $ids=>$dateieninfos)
  {
    if ($ids == "name")
    {
      foreach ($dateieninfos as $id=>$info)
      {
        // Upload-Status
        if ($_FILES["datei"]["error"][$id] == UPLOAD_ERR_OK)
        {
          // Muster zur Überprüfung der im Dateinamen
          // enthaltenen Zeichen (Optional)
          $regExp = "/^[a-z_]([a-z0-9_-]*\.?[a-z0-9_-])*\.[a-z]{3,4}$/i";

          // Dateiname und Dateigröße
          if (preg_match($regExp,$_FILES["datei"]["name"][$id]) && $_FILES["datei"]["size"][$id] > 0 && $_FILES["datei"]["size"][$id] < 100000)
          {
            // Temporäre Datei in das Zielverzeichnis
            // des Servers verschieben.
            move_uploaded_file($_FILES["datei"]["tmp_name"][$id],"shots/".$_FILES["datei"]["name"][$id]);

            // Erfolgsmeldung
            echo "<b>Datei " . $_FILES["datei"]["name"][$id] . "</b> – Erfolgreich angelegt!<br>\n";
          }
          else
          {
            echo "<b>Fehler bei " . $_FILES["datei"]["name"][$id] . "</b> – Im Dateinamen oder Dateigrössen Limit!<br>\n";
          }
        }
        else
        {
          echo "<b>Fehler bei " . $_FILES["datei"]["name"][$id] . "</b> – Während der Übertragung aufgetreten!<br>\n";
        }
      }
    }
  }
}
else
{
  echo "<b>Fehler</b> – Dateiupload fehlgeschlagen!";
}

?>
<a href="up_form.html">Weitere Dateienuploaden</a>