Upload von Dateien auf den Webserver mit PHP programmieren

Es kommt öfters vor, dass man einen Upload von Dateien auf den eigenen Webserver erlauben möchte ? wenigsten von bestimmten Arten von Dateien, bzw. nur für ausgewählte Benutzer. Diese Funktionalität ist über ein PHP Programm sehr einfach realisierbar.

Der erste Schritt ist ein kleines Formular, um überhaupt eine Datei auswählen zu können.

Formular erstellen für Dateiupload

Unser PHP-Programm bekommt als Dateiname „dateiupload.php“.

Im ersten Schritt wird das Formular erstellt. Das geschieht mit ganz normalem HTML. Wichtig beim HTML-Tag <form> ist enctype="multipart/form-data"

HTML-Quellcode: für Formular
<form name="uploadformular" enctype="multipart/form-data" action="dateiupload.php" method="post" >
Datei: <input type="file" name="uploaddatei" size="60" maxlength="255" >
<input type="Submit" name="submit" value="Datei hochladen">
</form>

Jetzt kann das Formular bereits aufgerufen werden, aber es geschieht noch nichts. Wir müssen nun in unserem PHP-Programm vorneweg abfragen, ob das Formular abgesendet wurde und ein Upload vorliegt.

Wichtig am Formular ist der Formularname (name="uploadformular") ? darüber können wir nun auf die hochgeladene Datei zugreifen. Es werden uns alle Informationen in einem Array mit diesem Namen geliefert.

<?php
echo "<pre>";
print_r ( $_FILES );
echo "</pre>";
/* hier kommt nun das Formular ? am Ende !! */
?>
<form ?
 

Und Inhalt des Arrays $_FILES ist nach Hochladen einer Datei dann beispielsweise:

Array
(
    [uploaddatei] => Array
        (
            [name] => kaffeepause.png
            [type] => image/png
            [tmp_name] => /tmp/phplP3DM3
            [error] => 0
            [size] => 90109
        )
)

Die einzelnen Bedeutungen sind:

name ? ursprünglicher Dateiname (muss unter Umständen wegen Sonderzeichen etc. geändert werden)

type ? um welche Art von Datei es sich handelt (im Beispiel ist es ein PNG-Bild)

tmp_name ? das System lädt vor der endgültigen Verarbeitung die Datei in ein temporäres Verzeichnis, um die Datei zum Speichern bereitzustellen

error ? ob ein Fehler beim Hochladen passiert ist

size ? welche Dateigröße die Datei in Byte hat

Somit können wir nun abfragen, ob eine Datei durch ein HTML-Formular hochgeladen wurde und diese Datei weiterverarbeiten.

<?php
echo "<pre>";
print_r ($_FILES );
echo "</pre>";
if ( ($_FILES['uploaddatei']['name']  <> "")
{
    // Datei wurde durch HTML-Formular hochgeladen
    // und kann nun weiterverarbeitet werden
}
/* hier kommt nun das Formular ? am Ende !! */
?>
<form ?
 

Bevor wir eine Kontrolle auf die Dateityp und Dateiname machen, schauen wir uns das Wichtigste an: das Speichern der Datei, damit wir damit später arbeiten können.

Damit das alles ein wenig ordentlicher bleibt, legen wir ein Unterverzeichnis an, in dem dann die hochgeladenen Dateien „enden“. Das Unterverzeichnis bekommt den Namen „hochgeladenes“

Die PHP-Funktion für uploads über das Webformular (teilweise sieht man auch „copy“, was genauso aufgebaut ist und funktioniert.)

    move_uploaded_file(
         $_FILES['uploaddatei']['tmp_name'] ,
         'hochgeladenes/'. $_FILES['uploaddatei']['name']);
 

Der PHP-Befehl “move_uploaded_file” erwartet 2 Angaben ? wo liegt und wie nennt sich die hochgeladene Datei (das steckt in $_FILES['uploaddatei']['tmp_name'] ) und als zweites, wohin die Datei geladen werden soll und wie soll diese sich dann nennen. Der Befehl kann natürlich in einer Zeile untergebracht werden, aber hier der Übersicht wegen in 3 Zeilen.

Insgesamt hat unser PHP-Programm zum Hochladen von Dateien (ohne Kontrolle von Dateityp und Kontrolle von Dateiname) also folgenden Aufbau:

<?php
echo "<pre>";
echo "FILES:<br />";
print_r ($_FILES );
echo "</pre>";
if ( $_FILES['uploaddatei']['name']  <> "" )
{
    // Datei wurde durch HTML-Formular hochgeladen
    // und kann nun weiterverarbeitet werden
    move_uploaded_file (
         $_FILES['uploaddatei']['tmp_name'] ,
         'hochgeladenes/'. $_FILES['uploaddatei']['name'] );
 
    echo "<p>Hochladen war erfolgreich: ";
    echo '<a href="hochgeladenes/'. $_FILES['uploaddatei']['name'] .'">';
    echo 'hochgeladenes/'. $_FILES['uploaddatei']['name'];
    echo '</a>';
}
?>
 
<form name="uploadformular" enctype="multipart/form-data" action="dateiupload.php" method="post" >
Datei: <input type="file" name="uploaddatei" size="60" maxlength="255" >
<input type="Submit" name="submit" value="Datei hochladen">
</form>
 

Bis hierher für das Verständnis der Funktion. Wichtig ist nun Sicherheit reinzubringen!!! Also weiterlesen und machen!

Sicherheit vor dem Upload unerwünschten Dateien

Problem an der Geschichte ist, dass nun jeder Dateien auf den Webserver hochladen kann und somit natürlich auch ausführbare PHP-Programme einschleusen kann um so den Zugriff auf alle Dateien zu erlangen. Daher muss je nach Anwendung des Upload-Programmes entweder diese nur für zugriffsberechtigte Leute freigegeben werden oder (oft auch und) nur bestimmte, gewünschte Dateitypen zugelassen werden.

Upload einschränken auf bestimmte Dateitypen

Es gibt verschiedene Möglichkeiten für die Kontrolle nach dem Dateityp. Eine wäre direkt über den type, der uns ja zur Verfügung steht in dem Array von $_FILES

Eine einfache Möglichkeit ohne reguläre Ausdrücke ist z.B. die Kontrolle, ob in einem Array ein bestimmter Wert vorkommt. Das geschieht über die PHP_Funktion in_array (http://www.php.net/manual/de/function.in-array.php )

Und falls nicht in Array enthalten, wird quasi die hochgeladene Datei verworfen. Hochgeladen wird diese so oder so (höchstens man prüft im Vorfeld über JavaScript).

Unser Beispiel sieht also ergänzt wie folgt aus:

<?php
echo "<pre>";
echo "FILES:<br />";
print_r ($_FILES );
echo "</pre>";
if ( $_FILES['uploaddatei']['name']  <> "" )
{
    // Datei wurde durch HTML-Formular hochgeladen
    // und kann nun weiterverarbeitet werden
 
    // Kontrolle, ob Dateityp zulässig ist
    $zugelassenedateitypen = array("image/png", "image/jpeg", "image/gif");
 
    if ( ! in_array( $_FILES['uploaddatei']['type'] , $zugelassenedateitypen ))
    {
        echo "<p>Dateitype ist NICHT zugelassen</p>";
    }
    else
    {
        move_uploaded_file (
             $_FILES['uploaddatei']['tmp_name'] ,
             'hochgeladenes/'. $_FILES['uploaddatei']['name'] );
 
        echo "<p>Hochladen war erfolgreich: ";
        echo '<a href="hochgeladenes/'. $_FILES['uploaddatei']['name'] .'">';
        echo 'hochgeladenes/'. $_FILES['uploaddatei']['name'];
        echo '</a>';
    }
}
?>
 
<form name="uploadformular" enctype="multipart/form-data" action="dateiupload.php" method="post" >
Datei: <input type="file" name="uploaddatei" size="60" maxlength="255" >
<input type="Submit" name="submit" value="Datei hochladen">
</form>
 

zulässige Dateinamen erzeugen über PHP

Und nun sollte zur Sicherheit der Dateiname bereinigt werden. Dateinamen unter Betriebssystemen sind sehr oft nicht kompatibel zu Dateinamen, die man für Webanwendungen benötigt. Leerzeichen, Umlaute und sonstige Sonderzeichen sind nicht wirklich geschickt. Also ersetzen wir diese und bereinigen den Dateinamen.

Hierfür eine Funktion selbstgestrickt (bisher noch nichts gefunden, was mir gefällt ? wenn jemand Vorschläge hat, nur her damit)

function dateiname_bereinigen($dateiname)
{
    // erwünschte Zeichen erhalten bzw. umschreiben
    // aus allen ä wird ae, ü -> ue, ß -> ss (je nach Sprache mehr Aufwand)
    // und sonst noch ein paar Dinge (ist schätzungsweise mein persönlicher Geschmack ;)
    $dateiname = strtolower ( $dateiname );
    $dateiname = str_replace ('"', "-", $dateiname );
    $dateiname = str_replace ("'", "-", $dateiname );
    $dateiname = str_replace ("*", "-", $dateiname );
    $dateiname = str_replace ("ß", "ss", $dateiname );
    $dateiname = str_replace ("ß", "ss", $dateiname );
    $dateiname = str_replace ("ä", "ae", $dateiname );
    $dateiname = str_replace ("ä", "ae", $dateiname );
    $dateiname = str_replace ("ö", "oe", $dateiname );
    $dateiname = str_replace ("ö", "oe", $dateiname );
    $dateiname = str_replace ("ü", "ue", $dateiname );
    $dateiname = str_replace ("ü", "ue", $dateiname );
    $dateiname = str_replace ("Ä", "ae", $dateiname );
    $dateiname = str_replace ("Ö", "oe", $dateiname );
    $dateiname = str_replace ("Ü", "ue", $dateiname );
    $dateiname = htmlentities ( $dateiname );
    $dateiname = str_replace ("&", "und", $dateiname );
    $dateiname = str_replace ("+", "und", $dateiname );
    $dateiname = str_replace ("(", "-", $dateiname );
    $dateiname = str_replace (")", "-", $dateiname );
    $dateiname = str_replace (" ", "-", $dateiname );
    $dateiname = str_replace ("\'", "-", $dateiname );
    $dateiname = str_replace ("/", "-", $dateiname );
    $dateiname = str_replace ("?", "-", $dateiname );
    $dateiname = str_replace ("!", "-", $dateiname );
    $dateiname = str_replace (":", "-", $dateiname );
    $dateiname = str_replace (";", "-", $dateiname );
    $dateiname = str_replace (",", "-", $dateiname );
    $dateiname = str_replace ("--", "-", $dateiname );
 
    // und nun jagen wir noch die Heilfunktion darüber
    $dateiname = filter_var($dateiname, FILTER_SANITIZE_URL);
    return ($dateiname);
}
 

Diese Funktion wird noch am entsprechenden Aufruf für den Dateinamen eingebunden ? jetzt komplett:

<?php
/*
echo "<pre>";
echo "FILES:<br />";
print_r ($_FILES );
echo "</pre>";
*/
if ( $_FILES['uploaddatei']['name']  <> "" )
{
    // Datei wurde durch HTML-Formular hochgeladen
    // und kann nun weiterverarbeitet werden
 
    // Kontrolle, ob Dateityp zulässig ist
    $zugelassenedateitypen = array("image/png", "image/jpeg", "image/gif");
 
    if ( ! in_array( $_FILES['uploaddatei']['type'] , $zugelassenedateitypen ))
    {
        echo "<p>Dateitype ist NICHT zugelassen</p>";
    }
    else
    {
        // Test ob Dateiname in Ordnung
        $_FILES['uploaddatei']['name'] = dateiname_bereinigen($_FILES['uploaddatei']['name']);
 
        if ( $_FILES['uploaddatei']['name'] <> '' )
        {
            move_uploaded_file (
                 $_FILES['uploaddatei']['tmp_name'] ,
                 'hochgeladenes/'. $_FILES['uploaddatei']['name'] );
 
            echo "<p>Hochladen war erfolgreich: ";
            echo '<a href="hochgeladenes/'. $_FILES['uploaddatei']['name'] .'">';
            echo 'hochgeladenes/'. $_FILES['uploaddatei']['name'];
            echo '</a>';
        }
        else
        {
            echo "<p>Dateiname ist nicht zulässig</p>";
        }
    }
}
 
function dateiname_bereinigen($dateiname)
{
    // erwünschte Zeichen erhalten bzw. umschreiben
    // aus allen ä wird ae, ü -> ue, ß -> ss (je nach Sprache mehr Aufwand)
    // und sonst noch ein paar Dinge (ist schätzungsweise mein persönlicher Geschmach ;)
    $dateiname = strtolower ( $dateiname );
    $dateiname = str_replace ('"', "-", $dateiname );
    $dateiname = str_replace ("'", "-", $dateiname );
    $dateiname = str_replace ("*", "-", $dateiname );
    $dateiname = str_replace ("ß", "ss", $dateiname );
    $dateiname = str_replace ("ß", "ss", $dateiname );
    $dateiname = str_replace ("ä", "ae", $dateiname );
    $dateiname = str_replace ("ä", "ae", $dateiname );
    $dateiname = str_replace ("ö", "oe", $dateiname );
    $dateiname = str_replace ("ö", "oe", $dateiname );
    $dateiname = str_replace ("ü", "ue", $dateiname );
    $dateiname = str_replace ("ü", "ue", $dateiname );
    $dateiname = str_replace ("Ä", "ae", $dateiname );
    $dateiname = str_replace ("Ö", "oe", $dateiname );
    $dateiname = str_replace ("Ü", "ue", $dateiname );
    $dateiname = htmlentities ( $dateiname );
    $dateiname = str_replace ("&", "und", $dateiname );
    $dateiname = str_replace ("+", "und", $dateiname );
    $dateiname = str_replace ("(", "-", $dateiname );
    $dateiname = str_replace (")", "-", $dateiname );
    $dateiname = str_replace (" ", "-", $dateiname );
    $dateiname = str_replace ("\'", "-", $dateiname );
    $dateiname = str_replace ("/", "-", $dateiname );
    $dateiname = str_replace ("?", "-", $dateiname );
    $dateiname = str_replace ("!", "-", $dateiname );
    $dateiname = str_replace (":", "-", $dateiname );
    $dateiname = str_replace (";", "-", $dateiname );
    $dateiname = str_replace (",", "-", $dateiname );
    $dateiname = str_replace ("--", "-", $dateiname );
 
    // und nun jagen wir noch die Heilfunktion darüber
    $dateiname = filter_var($dateiname, FILTER_SANITIZE_URL);
    return ($dateiname);
}
?>
 
<form name="uploadformular" enctype="multipart/form-data" action="dateiupload.php" method="post" >
Datei: <input type="file" name="uploaddatei" size="60" maxlength="255" >
<input type="Submit" name="submit" value="Datei hochladen">
</form>
 

Die Funktion dateiname_bereinigen sollte noch hübscher werden ? aber auf die Schnelle :) ? Vorschläge sind willkommen.

Probleme bei Upload von Dateien über PHP

Auf jedem Server ist eine bestimmte Zeitspanne eingestellt, die ein PHP-Programm ausgeführt werden darf. Benötigt das PHP-Programm länger als die voreingestellte Zeitspanne, schießt der Server das PHP-Programm ab, mit der Annahme, dass das PHP-Programm „abgestürzt“ ist bzw. sich in einer unendlichen Schleife befindet. Das kann je nach der Servereinstellung nach 60 Sekunden sein. Die Voreinstellung bei den meisten Servern sind 60 Sekunden.

Problem bei den Uploads ist nun, dass das Programm den Upload abwarten muss, was bei einer Kombination von großer Datei und langsamer Internetverbindung durchaus länger als die voreingestellte Zeit dauern kann. Also da nicht wundern, wenn es anscheinend nicht funktioniert. Hierbei hilft, die Ausführungszeit von PHP-Programmen in der Apache-Einstellung zu ändern. Da einfach mal in der php.ini nach dem Eintrag „max_execution_time = 60“ suchen. Die 60 sind nur ein Beispiel für 60 Sekunden zulässige Ausführungszeit. Bei einigen Providern kann die Einstellung verändert werden, bei anderen nicht.