Skip to content

Kapitel 9: Formulare und Benutzerinteraktion

9.1 Unterschied zwischen GET und POST

GET-Methode

php
<!-- formular_get.html -->
<!DOCTYPE html>
<html>
<head>
    <title>GET-Formular</title>
</head>
<body>
    <form method="get" action="verarbeite_get.php">
        <label>Name: <input type="text" name="name"></label><br>
        <label>Alter: <input type="number" name="alter"></label><br>
        <button type="submit">Senden</button>
    </form>
</body>
</html>

<?php
    // verarbeite_get.php
    // GET-Daten werden über URL übertragen
    $name = $_GET['name'] ?? 'Unbekannt';
    $alter = $_GET['alter'] ?? 0;
    
    echo "Name: " . $name . "<br>";
    echo "Alter: " . $alter . "<br>";
    // URL sieht so aus: verarbeite_get.php?name=Max&alter=25
?>

<!-- 
Vorteile von GET:
+ Daten sind in URL sichtbar (kann bookmarkt werden)
+ Einfach zu debuggen
+ Für Suchen, Filterung geeignet

Nachteile von GET:
- Daten in URL sichtbar (unsicher für Passwörter!)
- URL-Längenbegrenzung (ca. 2000 Zeichen)
- Nicht für grosse Datenmengen
-->

POST-Methode

php
<!-- formular_post.html -->
<form method="post" action="verarbeite_post.php">
    <label>Benutzername: <input type="text" name="benutzer"></label><br>
    <label>Passwort: <input type="password" name="passwort"></label><br>
    <button type="submit">Login</button>
</form>

<?php
    // verarbeite_post.php
    // POST-Daten werden im HTTP-Body übertragen
    $benutzer = $_POST['benutzer'] ?? '';
    $passwort = $_POST['passwort'] ?? '';
    
    echo "Benutzername: " . $benutzer . "<br>";
    // Passwort sollte NIEMALS ausgegeben werden!
    
    // In URL sieht man nichts: verarbeite_post.php
?>

<!-- 
Vorteile von POST:
+ Daten nicht in URL sichtbar (sicherer)
+ Keine URL-Längenbegrenzung
+ Für Login, Registrierung, grosse Daten geeignet

Nachteile von POST:
- Kann nicht bookmarkt werden
- Schwieriger zu debuggen
-->

Unterschied: GET vs. POST (Tabelle)

MerkmalGETPOST
DatenübertragungURL-ParameternHTTP-Body (versteckt)
SicherheitNiedrig (sichtbar in URL)Höher (nicht in URL)
DatenmengeBegrenzt (URL-Länge)Unbegrenzt
BookmarkbarJaNein
CachebarJaNein
AnwendungSuche, FilterungLogin, Registrierung, Upload
IdempotenzIdempotent (mehrmals ausführbar)Nicht idempotent

Empfehlung:

  • GET: Für Datenabfrage (Suche, Filterung)
  • POST: Für Dateneingabe (Login, Registrierung, Upload)

9.2 Formular mit method="get" / "post"

Formular-Erstellung (HTML)

html
<!-- formular.html -->
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <title>Kontaktformular</title>
</head>
<body>
    <h2>Kontaktformular</h2>
    <form method="post" action="verarbeite.php">
        <label>Name:<br>
            <input type="text" name="name" required>
        </label><br><br>
        
        <label>E-Mail:<br>
            <input type="email" name="email" required>
        </label><br><br>
        
        <label>Nachricht:<br>
            <textarea name="nachricht" rows="5" cols="30" required></textarea>
        </label><br><br>
        
        <label>Geschlecht:<br>
            <input type="radio" name="geschlecht" value="m"> Männlich
            <input type="radio" name="geschlecht" value="w"> Weiblich
            <input type="radio" name="geschlecht" value="d"> Divers
        </label><br><br>
        
        <label>Interessen:<br>
            <input type="checkbox" name="interessen[]" value="sport"> Sport
            <input type="checkbox" name="interessen[]" value="musik"> Musik
            <input type="checkbox" name="interessen[]" value="lesen"> Lesen
        </label><br><br>
        
        <label>Land:<br>
            <select name="land">
                <option value="de">Deutschland</option>
                <option value="at">Österreich</option>
                <option value="ch">Schweiz</option>
            </select>
        </label><br><br>
        
        <button type="submit">Senden</button>
        <button type="reset">Zurückseten</button>
    </form>
</body>
</html>

Formulardaten verarbeiten (PHP)

php
<?php
    // verarbeite.php
    header('Content-Type: text/html; charset=utf-8');
    
    // POST-Daten empfangen
    $name = $_POST['name'] ?? 'Unbekannt';
    $email = $_POST['email'] ?? '';
    $nachricht = $_POST['nachricht'] ?? '';
    $geschlecht = $_POST['geschlecht'] ?? '';
    $interessen = $_POST['interessen'] ?? [];  // Array!
    $land = $_POST['land'] ?? '';
    
    // Ausgabe
    echo "<h2>Vielen Dank für Ihre Nachricht!</h2>";
    echo "Name: " . htmlspecialchars($name) . "<br>";
    echo "E-Mail: " . htmlspecialchars($email) . "<br>";
    echo "Nachricht: " . nl2br(htmlspecialchars($nachricht)) . "<br>";
    echo "Geschlecht: " . htmlspecialchars($geschlecht) . "<br>";
    
    // Array ausgeben (Interessen)
    if (!empty($interessen)) {
        echo "Interessen: " . implode(", ", $interessen) . "<br>";
    }
    
    echo "Land: " . htmlspecialchars($land) . "<br>";
    
    // Weiterleitung (nach 3 Sekunden)
    header("refresh:3;url=formular.html");
    echo "<p>Sie werden in 3 Sekunden weitergeleitet...</p>";
?>

9.3 $_GET / $_POST / $_REQUEST Daten empfangen

Superglobals in PHP

php
<?php
    // $_GET: Daten aus URL-Parametern (methode="get")
    // URL: verarbeite.php?name=Max&alter=25
    $name = $_GET['name'] ?? '';
    $alter = $_GET['alter'] ?? 0;
    
    // $_POST: Daten aus Formular (methode="post")
    $benutzer = $_POST['benutzer'] ?? '';
    $passwort = $_POST['passwort'] ?? '';
    
    // $_REQUEST: Enthält Daten aus GET, POST und COOKIE
    $daten = $_REQUEST['daten'] ?? '';
    // Achtung: $_REQUEST ist unsicher (man weiss nicht, woher Daten kommen)
    
    // Empfehlung: Immer spezifisch sein ($_GET oder $_POST)
?>

<!-- 
Unterschied:
- $_GET: Nur GET-Daten
- $_POST: Nur POST-Daten
- $_REQUEST: GET + POST + COOKIE (Reihenfolge in php.ini: variables_order)
-->

Sichere Datenverarbeitung

php
<?php
    // Schlechte Praxis (unsicher)
    $name = $_GET['name'];  // FEHLER! Wenn 'name' nicht existiert
    echo $name;
    
    // Gute Praxis (mit Standardwert)
    $name = $_GET['name'] ?? 'Gast';  // Null-Koaleszenz-Operator
    echo htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
    
    // Noch besser: prüfen, ob gesetzt
    if (isset($_GET['name'])) {
        $name = $_GET['name'];
    } else {
        $name = 'Gast';
    }
    
    // Oder: filter_input() verwenden (empfohlen!)
    $name = filter_input(INPUT_GET, 'name', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
    if ($name === null || $name === false) {
        $name = 'Gast';
    }
    echo $name;
?>

9.4 Formularvalidierung (nicht leer, Format, Länge)

Clientseitige Validierung (HTML/JavaScript)

html
<!-- formular_validierung.html -->
<form method="post" action="verarbeite.php" onsubmit="return validiere()">
    <label>Name (2-50 Zeichen):<br>
        <input type="text" name="name" id="name" required 
               minlength="2" maxlength="50" 
               pattern="[A-Za-zÄäÖöÜüß ]+">
    </label><br><br>
    
    <label>E-Mail:<br>
        <input type="email" name="email" id="email" required>
    </label><br><br>
    
    <label>Alter (18-100):<br>
        <input type="number" name="alter" id="alter" 
               min="18" max="100" required>
    </label><br><br>
    
    <label>Passwort (mind. 8 Zeichen):<br>
        <input type="password" name="passwort" id="passwort" 
               required minlength="8">
    </label><br><br>
    
    <button type="submit">Registrieren</button>
</form>

<script>
function validiere() {
    var name = document.getElementById('name').value;
    var email = document.getElementById('email').value;
    var alter = document.getElementById('alter').value;
    var passwort = document.getElementById('passwort').value;
    
    // Name prüfen
    if (name.length < 2 || name.length > 50) {
        alert('Name muss zwischen 2 und 50 Zeichen lang sein!');
        return false;
    }
    
    // E-Mail prüfen
    var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
        alert('Bitte gültige E-Mail eingeben!');
        return false;
    }
    
    // Alter prüfen
    if (alter < 18 || alter > 100) {
        alert('Alter muss zwischen 18 und 100 liegen!');
        return false;
    }
    
    // Passwort prüfen
    if (passwort.length < 8) {
        alert('Passwort muss mindestens 8 Zeichen lang sein!');
        return false;
    }
    
    return true;  // Formular senden
}
</script>

Serverseitige Validierung (PHP)

php
<?php
    // verarbeite.php
    $fehler = [];
    $erfolg = false;
    
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        // 1. Name validieren
        $name = trim($_POST['name'] ?? '');
        if (empty($name)) {
            $fehler[] = "Name darf nicht leer sein.";
        } elseif (strlen($name) < 2 || strlen($name) > 50) {
            $fehler[] = "Name muss zwischen 2 und 50 Zeichen lang sein.";
        } elseif (!preg_match('/^[A-Za-zÄäÖöÜüß ]+$/', $name)) {
            $fehler[] = "Name darf nur Buchstaben und Leerzeichen enthalten.";
        }
        
        // 2. E-Mail validieren
        $email = trim($_POST['email'] ?? '');
        if (empty($email)) {
            $fehler[] = "E-Mail darf nicht leer sein.";
        } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $fehler[] = "Ungültige E-Mail-Adresse.";
        }
        
        // 3. Alter validieren
        $alter = $_POST['alter'] ?? '';
        if (empty($alter)) {
            $fehler[] = "Alter darf nicht leer sein.";
        } elseif (!is_numeric($alter)) {
            $fehler[] = "Alter muss eine Zahl sein.";
        } elseif ($alter < 18 || $alter > 100) {
            $fehler[] = "Alter muss zwischen 18 und 100 liegen.";
        }
        
        // 4. Passwort validieren
        $passwort = $_POST['passwort'] ?? '';
        if (empty($passwort)) {
            $fehler[] = "Passwort darf nicht leer sein.";
        } elseif (strlen($passwort) < 8) {
            $fehler[] = "Passwort muss mindestens 8 Zeichen lang sein.";
        }
        
        // Wenn keine Fehler: Erfolg!
        if (empty($fehler)) {
            $erfolg = true;
            // Hier könnte man Daten in Datenbank speichern...
        }
    }
?>

<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <title>Validierung</title>
    <style>
        .fehler { color: red; }
        .erfolg { color: green; }
    </style>
</head>
<body>
    <?php if (!empty($fehler)): ?>
        <div class="fehler">
            <h3>Fehler:</h3>
            <ul>
                <?php foreach ($fehler as $f): ?>
                    <li><?php echo htmlspecialchars($f); ?></li>
                <?php endforeach; ?>
            </ul>
        </div>
    <?php endif; ?>
    
    <?php if ($erfolg): ?>
        <div class="erfolg">
            <h3>Erfolgreich registriert!</h3>
            <p>Name: <?php echo htmlspecialchars($name); ?></p>
            <p>E-Mail: <?php echo htmlspecialchars($email); ?></p>
        </div>
    <?php endif; ?>
    
    <!-- Formular hier einfügen... -->
</body>
</html>

9.5 XSS verhindern (htmlspecialchars)

Was ist XSS (Cross-Site Scripting)?

XSS ist eine Sicherheitslücke, bei der Angreifer bösartigen Code in Webseiten einschleusen.

Beispiel für XSS-Angriff:

php
<?php
    // Schlechte Praxis (anfällig für XSS)
    $name = $_GET['name'] ?? '';
    echo "Willkommen " . $name;  // Gefährlich!
    
    // Wenn ein Angreifer folgende URL aufruft:
    // index.php?name=<script>alert('XSS')</script>
    // Dann wird das JavaScript ausgeführt!
?>

<!-- 
XSS-Schutzmassnahmen:
1. htmlspecialchars() verwenden
2. ENT_QUOTES flag verwenden (schützt auch einfache Anführungszeichen)
3. UTF-8 Encoding angeben
4. Immer vor Ausgabe escapen
-->

XSS-Schutz mit htmlspecialchars()

php
<?php
    // Richtig: htmlspecialchars() verwenden
    $name = $_GET['name'] ?? '';
    $name_sicher = htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
    echo "Willkommen " . $name_sicher;
    
    // Was htmlspecialchars() macht:
    // & → &amp;
    // " → &quot;
    // ' → &#039;  (mit ENT_QUOTES)
    // < → &lt;
    // > → &gt;
    
    // Also wird aus <script>alert('XSS')</script>
    // &lt;script&gt;alert('XSS')&lt;/script&gt;
    // Das wird im Browser als Text angezeigt, nicht ausgeführt!
    
    // Für HTML-Attribute (value="" etc.)
    $wert = htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
    echo '<input type="text" value="' . $wert . '">';
    
    // Für JSON-Ausgabe
    $daten = ["name" => $name];
    echo json_encode($daten, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
?>

<!-- 
Weitere XSS-Schutzmassnahmen:
1. Content Security Policy (CSP) Header setzen
2. Eingabedaten validieren (Server + Client)
3. Keine Benutzereingaben direkt in eval() oder exec() verwenden
4. Template-Systeme verwenden (die automatisch escapen)
-->

9.6 Praxis: Login-Formular, Registrierungsformular

Login-Formular

php
<!-- login.html -->
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
    <h2>Login</h2>
    <?php if (isset($_GET['fehler'])): ?>
        <p style="color: red;"><?php echo htmlspecialchars($_GET['fehler']); ?></p>
    <?php endif; ?>
    
    <form method="post" action="login_verarbeite.php">
        <label>Benutzername:<br>
            <input type="text" name="benutzer" required>
        </label><br><br>
        
        <label>Passwort:<br>
            <input type="password" name="passwort" required>
        </label><br><br>
        
        <button type="submit">Einloggen</button>
    </form>
    
    <p>Noch kein Konto? <a href="registrierung.html">Hier registrieren</a></p>
</body>
</html>

<?php
    // login_verarbeite.php
    session_start();
    header('Content-Type: text/html; charset=utf-8');
    
    $fehler = [];
    
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $benutzer = trim($_POST['benutzer'] ?? '');
        $passwort = $_POST['passwort'] ?? '';
        
        // Validierung
        if (empty($benutzer)) {
            $fehler[] = "Benutzername darf nicht leer sein.";
        }
        if (empty($passwort)) {
            $fehler[] = "Passwort darf nicht leer sein.";
        }
        
        // Wenn keine Fehler: "Login" prüfen (Beispiel)
        if (empty($fehler)) {
            // In echtem Projekt: Datenbank abfragen!
            $benutzer_korrekt = "max";
            $passwort_hash = password_hash("geheim", PASSWORD_DEFAULT);
            
            if ($benutzer === $benutzer_korrekt && password_verify($passwort, $passwort_hash)) {
                // Login erfolgreich
                $_SESSION['benutzer'] = $benutzer;
                $_SESSION['eingeloggt'] = true;
                
                header("Location: willkommen.php");
                exit();
            } else {
                $fehler[] = "Benutzername oder Passwort falsch.";
            }
        }
    }
    
    // Fehler anzeigen (Weiterleitung zu login.html mit Fehlermeldung)
    if (!empty($fehler)) {
        $fehler_string = urlencode(implode("<br>", $fehler));
        header("Location: login.html?fehler=" . $fehler_string);
        exit();
    }
?>

Registrierungsformular

php
<!-- registrierung.html -->
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <title>Registrierung</title>
</head>
<body>
    <h2>Registrierung</h2>
    <form method="post" action="registrierung_verarbeite.php">
        <label>Benutzername:<br>
            <input type="text" name="benutzer" required minlength="3" maxlength="20">
        </label><br><br>
        
        <label>E-Mail:<br>
            <input type="email" name="email" required>
        </label><br><br>
        
        <label>Passwort:<br>
            <input type="password" name="passwort" required minlength="8">
        </label><br><br>
        
        <label>Passwort bestätigen:<br>
            <input type="password" name="passwort_bestätigen" required>
        </label><br><br>
        
        <button type="submit">Registrieren</button>
    </form>
</body>
</html>

<?php
    // registrierung_verarbeite.php
    header('Content-Type: text/html; charset=utf-8');
    
    $fehler = [];
    
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $benutzer = trim($_POST['benutzer'] ?? '');
        $email = trim($_POST['email'] ?? '');
        $passwort = $_POST['passwort'] ?? '';
        $passwort_bestätigen = $_POST['passwort_bestätigen'] ?? '';
        
        // Validierung
        if (empty($benutzer) || strlen($benutzer) < 3 || strlen($benutzer) > 20) {
            $fehler[] = "Benutzername muss zwischen 3 und 20 Zeichen lang sein.";
        }
        
        if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $fehler[] = "Gültige E-Mail-Adresse erforderlich.";
        }
        
        if (empty($passwort) || strlen($passwort) < 8) {
            $fehler[] = "Passwort muss mindestens 8 Zeichen lang sein.";
        }
        
        if ($passwort !== $passwort_bestätigen) {
            $fehler[] = "Passwörter stimmen nicht überein.";
        }
        
        // Wenn keine Fehler: Registrierung speichern (Beispiel)
        if (empty($fehler)) {
            // In echtem Projekt: Datenbank speichern!
            $passwort_hash = password_hash($passwort, PASSWORD_DEFAULT);
            
            // Simuliere Speicherung
            echo "<h2>Registrierung erfolgreich!</h2>";
            echo "Benutzername: " . htmlspecialchars($benutzer) . "<br>";
            echo "E-Mail: " . htmlspecialchars($email) . "<br>";
            echo "Passwort (Hash): " . $passwort_hash . "<br>";
            echo "<p><a href='login.html'>Jetzt einloggen</a></p>";
            exit();
        }
    }
    
    // Fehler anzeigen
    if (!empty($fehler)) {
        echo "<h3>Fehler:</h3><ul>";
        foreach ($fehler as $f) {
            echo "<li>" . htmlspecialchars($f) . "</li>";
        }
        echo "</ul><p><a href='registrierung.html'>Zurück</a></p>";
    }
?>

Zusammenfassung

In diesem Kapitel haben Sie:

  • ✅ Den Unterschied zwischen GET und POST verstanden
  • ✅ Formulare mit method="get" und method="post" erstellt
  • ✅ Daten mit $_GET, $_POST und $_REQUEST empfangen
  • ✅ Formulardaten validiert (Client- und Serverseitig)
  • ✅ XSS-Angriffe mit htmlspecialchars() verhindert
  • ✅ Praxisbeispiele (Login, Registrierung) erstellt

Nächstes Kapitel: Wir werden Session-Control lernen (Login-Status, Cookies).


Übungsaufgaben:

  1. Erstellen Sie ein Suchformular mit GET-Methode
  2. Erstellen Sie ein Kontaktformular mit POST-Methode und Validierung
  3. Schützen Sie ein Formular vor XSS-Angriffen
  4. Erstellen Sie ein Login-System mit Session-Verwaltung

Häufige Fehler:

  • ❌ GET für Passwörter verwenden → Immer POST für sensible Daten!
  • ❌ Benutzereingaben direkt ausgeben → Immer htmlspecialchars() verwenden!
  • $_REQUEST verwenden → Immer spezifisch sein ($_GET oder $_POST)!
  • ❌ Validierung nur clientseitig → Immer auch serverseitig validieren!

Frei für alle Anfänger