Skip to content

Kapitel 13: Datei-Upload und Bildverarbeitung

13.1 Datei-Upload-Formular

Grundlegende Upload-Formular-Struktur

html
<!-- upload_formular.html -->
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <title>Datei-Upload</title>
</head>
<body>
    <h2>Datei-Upload</h2>
    <!-- Wichtig: enctype="multipart/form-data" muss gesetzt sein! -->
    <form method="post" action="upload_verarbeiten.php" enctype="multipart/form-data">
        <label>Datei auswählen:<br>
            <input type="file" name="datei" required>
        </label><br><br>
        
        <label>Maximale Dateigröße: 5MB<br>
            <input type="hidden" name="MAX_FILE_SIZE" value="5242880">
        </label><br><br>
        
        <button type="submit">Hochladen</button>
    </form>
</body>
</html>

Wichtige Hinweise:

  1. method="post" muss verwendet werden (GET hat Limit)
  2. enctype="multipart/form-data" muss gesetzt sein (sonst funktioniert Upload nicht!)
  3. MAX_FILE_SIZE (optional) kann die Dateigröße vorab begrenzen

13.2 $_FILES verwenden (Upload-Informationen erhalten)

Die $_FILES Superglobal-Variable

Wenn eine Datei hochgeladen wird, stehen die Informationen in $_FILES zur Verfügung.

php
<?php
    // upload_verarbeiten.php
    echo "<pre>";
    print_r($_FILES);
    echo "</pre>";
    
    /*
    Ausgabe-Beispiel:
    Array
    (
        [datei] => Array
            (
                [name] => meins_bild.jpg          // Originaldateiname
                [type] => image/jpeg               // MIME-Typ
                [tmp_name] => C:\xampp\tmp\php123.tmp  // Temporärer Pfad
                [error] => 0                      // Fehlercode (0 = kein Fehler)
                [size] => 204800                  // Dateigröße in Bytes
            )
    )
    */
?>

$_FILES Felder erklärt

FeldBeschreibung
nameOriginaldateiname (wie auf dem Computer des Benutzers)
typeMIME-Typ der Datei (z.B. image/jpeg, application/pdf)
tmp_nameTemporärer Pfad, wohin PHP die Datei während des Uploads speichert
errorFehlercode (0 = kein Fehler, siehe unten)
sizeDateigröße in Bytes

Fehlercodes bei $_FILES

FehlercodeKonstanteBeschreibung
0UPLOAD_ERR_OKKein Fehler, Upload erfolgreich
1UPLOAD_ERR_INI_SIZEDatei größer als upload_max_filesize in php.ini
2UPLOAD_ERR_FORM_SIZEDatei größer als MAX_FILE_SIZE im Formular
3UPLOAD_ERR_PARTIALDatei nur teilweise hochgeladen
4UPLOAD_ERR_NO_FILEKeine Datei hochgeladen
6UPLOAD_ERR_NO_TMP_DIRKein temporäres Verzeichnis
7UPLOAD_ERR_CANT_WRITEFehler beim Schreiben auf Datenträger
8UPLOAD_ERR_EXTENSIONEine PHP-Erweiterung hat den Upload gestoppt

13.3 Upload-Validierung (Größe, Typ, Umbenennen)

Upload-Validierung durchführen

php
<?php
    // upload_verarbeiten.php
    header('Content-Type: text/html; charset=utf-8');
    
    // Prüfen, ob Datei hochgeladen wurde
    if (!isset($_FILES['datei']) || $_FILES['datei']['error'] !== 0) {
        die("Fehler beim Upload: " . uploadFehlerMeldung($_FILES['datei']['error']));
    }
    
    $datei = $_FILES['datei'];
    
    // 1. Dateigröße prüfen (max. 5MB)
    $max_groesse = 5 * 1024 * 1024;  // 5MB in Bytes
    if ($datei['size'] > $max_groesse) {
        die("Datei ist zu groß! Maximale Größe: 5MB");
    }
    
    // 2. Dateityp prüfen (nur Bilder erlaubt)
    $erlaubte_typen = ['image/jpeg', 'image/png', 'image/gif'];
    if (!in_array($datei['type'], $erlaubte_typen)) {
        die("Nur JPG, PNG und GIF sind erlaubt!");
    }
    
    // 3. Dateiendung prüfen
    $erlaubte_endungen = ['jpg', 'jpeg', 'png', 'gif'];
    $dateiname = $datei['name'];
    $dateiendung = strtolower(pathinfo($dateiname, PATHINFO_EXTENSION));
    
    if (!in_array($dateiendung, $erlaubte_endungen)) {
        die("Ungültige Dateiendung!");
    }
    
    // 4. Datei umbenennen (Sicherheit!)
    $neuer_dateiname = uniqid() . '_' . time() . '.' . $dateiendung;
    
    // 5. Zielverzeichnis prüfen/erstellen
    $ziel_verzeichnis = 'uploads/';
    if (!is_dir($ziel_verzeichnis)) {
        mkdir($ziel_verzeichnis, 0755, true);
    }
    
    // 6. Datei verschieben (von temporärem Pfad zum Ziel)
    $ziel_pfad = $ziel_verzeichnis . $neuer_dateiname;
    
    if (move_uploaded_file($datei['tmp_name'], $ziel_pfad)) {
        echo "Datei erfolgreich hochgeladen!<br>";
        echo "Dateiname: " . htmlspecialchars($neuer_dateiname) . "<br>";
        echo "Pfad: " . htmlspecialchars($ziel_pfad) . "<br>";
        echo "<img src='" . $ziel_pfad . "' width='300'>";
    } else {
        echo "Fehler beim Verschieben der Datei!";
    }
    
    // Hilfsfunktion für Fehlermeldungen
    function uploadFehlerMeldung($fehlercode) {
        switch ($fehlercode) {
            case UPLOAD_ERR_INI_SIZE:
                return "Datei überschreitet upload_max_filesize in php.ini";
            case UPLOAD_ERR_FORM_SIZE:
                return "Datei überschreitet MAX_FILE_SIZE im Formular";
            case UPLOAD_ERR_PARTIAL:
                return "Datei nur teilweise hochgeladen";
            case UPLOAD_ERR_NO_FILE:
                return "Keine Datei hochgeladen";
            case UPLOAD_ERR_NO_TMP_DIR:
                return "Kein temporäres Verzeichnis";
            case UPLOAD_ERR_CANT_WRITE:
                return "Fehler beim Schreiben";
            case UPLOAD_ERR_EXTENSION:
                return "Upload durch PHP-Erweiterung gestoppt";
            default:
                return "Unbekannter Fehler";
        }
    }
?>

Sicherheitsmaßnahmen beim Datei-Upload

  1. Dateinamen ändern (um Überschreibungen und Code-Ausführung zu verhindern)
  2. Dateityp prüfen (nicht nur auf Dateiendung vertrauen!)
  3. Dateigröße begrenzen (Speicherplatz schützen)
  4. Upload-Verzeichnis außerhalb des Webroots (wenn möglich)
  5. .htaccess im Upload-Verzeichnis (um Ausführung von PHP-Dateien zu verhindern)
apache
# .htaccess im Upload-Verzeichnis
deny from all
<FilesMatch "\.(jpg|jpeg|png|gif)$">
    allow from all
</FilesMatch>

13.4 Profilbild-Upload

Praxisbeispiel: Profilbild-Upload

php
<?php
    // profilbild_upload.php
    session_start();
    header('Content-Type: text/html; charset=utf-8');
    
    // Benutzer muss eingeloggt sein (Session-Prüfung)
    if (!isset($_SESSION['eingeloggt']) || $_SESSION['eingeloggt'] !== true) {
        die("Bitte erst einloggen!");
    }
    
    $benutzer_id = $_SESSION['benutzer_id'];
    
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        // Upload-Validierung (wie in 13.3)
        if (!isset($_FILES['profilbild']) || $_FILES['profilbild']['error'] !== 0) {
            $fehler = "Bitte wählen Sie ein Bild aus.";
        } else {
            $datei = $_FILES['profilbild'];
            
            // Größe prüfen (max. 2MB)
            if ($datei['size'] > 2 * 1024 * 1024) {
                $fehler = "Bild ist zu groß! Maximale Größe: 2MB";
            }
            
            // Typ prüfen
            $erlaubte_typen = ['image/jpeg', 'image/png', 'image/gif'];
            if (!in_array($datei['type'], $erlaubte_typen)) {
                $fehler = "Nur JPG, PNG und GIF sind erlaubt!";
            }
            
            // Endung prüfen
            $dateiendung = strtolower(pathinfo($datei['name'], PATHINFO_EXTENSION));
            $erlaubte_endungen = ['jpg', 'jpeg', 'png', 'gif'];
            if (!in_array($dateiendung, $erlaubte_endungen)) {
                $fehler = "Ungültige Dateiendung!";
            }
            
            // Wenn keine Fehler: Upload durchführen
            if (!isset($fehler)) {
                // Altes Profilbild löschen (aus Datenbank abfragen)
                // ...
                
                // Neues Bild speichern
                $neuer_dateiname = 'profil_' . $benutzer_id . '_' . time() . '.' . $dateiendung;
                $ziel_pfad = 'uploads/profilbilder/' . $neuer_dateiname;
                
                if (move_uploaded_file($datei['tmp_name'], $ziel_pfad)) {
                    // Dateipfad in Datenbank speichern
                    // $sql = "UPDATE benutzer SET profilbild = ? WHERE id = ?";
                    // ...
                    
                    $erfolg = "Profilbild erfolgreich hochgeladen!";
                } else {
                    $fehler = "Fehler beim Speichern der Datei!";
                }
            }
        }
    }
?>

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <title>Profilbild hochladen</title>
</head>
<body>
    <h2>Profilbild hochladen</h2>
    
    <?php if (isset($fehler)): ?>
        <p style="color: red;"><?php echo $fehler; ?></p>
    <?php endif; ?>
    
    <?php if (isset($erfolg)): ?>
        <p style="color: green;"><?php echo $erfolg; ?></p>
    <?php endif; ?>
    
    <form method="post" action="" enctype="multipart/form-data">
        <label>Profilbild auswählen (max. 2MB):<br>
            <input type="file" name="profilbild" accept="image/*" required>
        </label><br><br>
        
        <button type="submit">Hochladen</button>
    </form>
    
    <p><a href="profil.php">Zurück zum Profil</a></p>
</body>
</html>

13.5 Bildbearbeitung (Thumbnail-Erstellung)

GD-Bibliothek verwenden

PHP hat eine eingebaute GD-Bibliothek für Bildbearbeitung.

php
<?php
    // thumbnail_erstellen.php
    
    // Funktion zum Erstellen eines Thumbnails
    function erstelleThumbnail($quelldatei, $zieldatei, $max_breite = 200, $max_hoehe = 200) {
        // 1. Bildinformationen abrufen
        $bild_info = getimagesize($quelldatei);
        $breite = $bild_info[0];
        $hoehe = $bild_info[1];
        $typ = $bild_info[2];
        
        // 2. Quellbild laden (je nach Typ)
        switch ($typ) {
            case IMAGETYPE_JPEG:
                $quelb_bild = imagecreatefromjpeg($quelldatei);
                break;
            case IMAGETYPE_PNG:
                $quelb_bild = imagecreatefrompng($quelldatei);
                break;
            case IMAGETYPE_GIF:
                $quelb_bild = imagecreatefromgif($quelldatei);
                break;
            default:
                return false;
        }
        
        // 3. Neue Größe berechnen (Seitenverhältnis beibehalten)
        $seitenverhaeltnis = $breite / $hoehe;
        
        if ($breite > $hoehe) {
            $neue_breite = $max_breite;
            $neue_hoehe = $max_breite / $seitenverhaeltnis;
        } else {
            $neue_hoehe = $max_hoehe;
            $neue_breite = $max_hoehe * $seitenverhaeltnis;
        }
        
        // 4. Neues (leeres) Bild erstellen
        $neues_bild = imagecreatetruecolor($neue_breite, $neue_hoehe);
        
        // 5. Transparenz für PNG/GIF beibehalten
        if ($typ == IMAGETYPE_PNG || $typ == IMAGETYPE_GIF) {
            imagecolortransparent($neues_bild, imagecolorallocatealpha($neues_bild, 0, 0, 0, 127));
            imagealphablending($neues_bild, false);
            imagesavealpha($neues_bild, true);
        }
        
        // 6. Bild skalieren (resizen)
        imagecopyresampled(
            $neues_bild, $quelb_bild,
            0, 0, 0, 0,
            $neue_breite, $neue_hoehe, $breite, $hoehe
        );
        
        // 7. Thumbnail speichern
        switch ($typ) {
            case IMAGETYPE_JPEG:
                imagejpeg($neues_bild, $zieldatei, 90);  // 90 = Qualität (0-100)
                break;
            case IMAGETYPE_PNG:
                imagepng($neues_bild, $zieldatei);
                break;
            case IMAGETYPE_GIF:
                imagegif($neues_bild, $zieldatei);
                break;
        }
        
        // 8. Speicher freigeben
        imagedestroy($quelb_bild);
        imagedestroy($neues_bild);
        
        return true;
    }
    
    // Beispielverwendung:
    if (isset($_FILES['datei']) && $_FILES['datei']['error'] === 0) {
        $quelldatei = $_FILES['datei']['tmp_name'];
        $zieldatei = 'uploads/thumbnails/' . uniqid() . '.jpg';
        
        if (erstelleThumbnail($quelldatei, $zieldatei, 200, 200)) {
            echo "Thumbnail erfolgreich erstellt!<br>";
            echo "<img src='" . $zieldatei . "'>";
        } else {
            echo "Fehler beim Erstellen des Thumbnails!";
        }
    }
?>

Bildbearbeitung mit Imagick (Alternative zur GD-Bibliothek)

Imagick ist leistungsfähiger, aber nicht standardmäßig in PHP installiert.

php
<?php
    // Erfordert: Imagick-Erweiterung installiert
    
    function erstelleThumbnailImagick($quelldatei, $zieldatei, $max_breite = 200, $max_hoehe = 200) {
        try {
            // Bild laden
            $bild = new Imagick($quelldatei);
            
            // Seitenverhältnis beibehalten
            $bild->thumbnailImage($max_breite, $max_hoehe, true);
            
            // Thumbnail speichern
            $bild->writeImage($zieldatei);
            
            // Speicher freigeben
            $bild->clear();
            $bild->destroy();
            
            return true;
        } catch (Exception $e) {
            return false;
        }
    }
?>

Zusammenfassung

In diesem Kapitel haben Sie:

  • ✅ Datei-Upload-Formulare erstellt (enctype="multipart/form-data")
  • $_FILES Superglobal-Variable verwendet (Upload-Informationen)
  • ✅ Upload-Validierung durchgeführt (Größe, Typ, Endung, Umbenennen)
  • ✅ Profilbild-Upload implementiert
  • ✅ Bildbearbeitung und Thumbnail-Erstellung gelernt (GD-Bibliothek)

Nächstes Kapitel: Wir werden Praxisprojekte erstellen (Gästebuch, Login-System, Warenkorb).


Übungsaufgaben:

  1. Erstellen Sie ein Upload-Formular für Bilder (mit Validierung)
  2. Implementieren Sie eine Profilbild-Upload-Funktion
  3. Erstellen Sie automatisch Thumbnails für hochgeladene Bilder
  4. Erstellen Sie eine Galerie, die alle hochgeladenen Bilder anzeigt

Häufige Fehler:

  • enctype="multipart/form-data" vergessen → Upload funktioniert nicht!
  • $_FILES statt $_POST verwenden → Upload-Dateien sind in $_FILES!
  • ❌ Dateinamen nicht ändern → Sicherheitsrisiko (Code-Ausführung)!
  • move_uploaded_file() vergessen → Datei bleibt im temporären Verzeichnis!

Frei für alle Anfänger