# Eingaben in PHP validieren und filtern mit filter_var

> Eingaben in PHP mit filter_var und filter_input_array validieren: Zahlen, E-Mail, URL, Bool, Erlaubnislisten und Grenzen. Mit Codebeispielen.

Quelle: https://phpsos.de/blog/eingaben-validieren-php/  
Stand: 25.10.2026  
Anbieter: PHP SOS, PHP-Notfallhilfe und Server-Sicherheit. Soforthilfe per WhatsApp: https://wa.me/491736494914?text=Hallo%20PHP%20SOS%2C%20wir%20brauchen%20Hilfe%20mit%20unserem%20PHP-Server.%20Firma%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**Kurz gesagt:** Eingaben in PHP validieren Sie mit `filter_var()` oder `filter_input_array()` und klaren Regeln je Feld: Typ, Bereich, Länge und erlaubte Werte. Was nicht passt, wird abgelehnt, nicht stillschweigend umgebaut. Validierung ist wichtig für saubere Daten und weniger Angriffsfläche, ersetzt aber weder Prepared Statements gegen SQL-Injection noch kontextgerechte Kodierung gegen XSS.

## Warum „alles filtern“ kein Konzept ist

In vielen älteren PHP-Projekten findet sich am Anfang jeder Datei eine Schleife, die alle Werte aus `$_GET` und `$_POST` durch eine Bereinigungsfunktion schickt. Das fühlt sich sicher an. In der Praxis entfernt es mal zu viel, etwa Apostrophe in Nachnamen, und mal zu wenig, weil dieselbe Funktion für SQL, HTML und Dateinamen gleichzeitig gelten soll.

Sinnvolle Validierung arbeitet anders: Sie fragt für jedes Feld, was dort erlaubt ist. Eine Bestellmenge ist eine ganze Zahl zwischen 1 und einer Obergrenze. Ein Sortierfeld ist einer von drei festen Werten. Ein Datum liegt in einem bestimmten Format vor und nach einem anderen Datum. Alles andere wird abgelehnt.

OWASP unterscheidet dabei zwei Ebenen: die **syntaktische** Prüfung, ob ein Wert die richtige Form hat, und die **semantische** Prüfung, ob er im Zusammenhang Sinn ergibt. Beide gehören auf den Server; Prüfungen im Browser dienen nur der Bedienbarkeit.

## Welche Filter PHP mitbringt

Die Filter-Erweiterung ist in PHP standardmäßig enthalten. Die wichtigsten Validierungsfilter laut PHP-Handbuch:

| Filter | Prüft | Wichtige Optionen und Hinweise |
|---|---|---|
| `FILTER_VALIDATE_INT` | ganze Zahl | `min_range`, `max_range` |
| `FILTER_VALIDATE_FLOAT` | Kommazahl | `decimal` für das Trennzeichen |
| `FILTER_VALIDATE_BOOL` | Wahrheitswert | mit `FILTER_NULL_ON_FAILURE` unterscheidbar von „falsch“ |
| `FILTER_VALIDATE_EMAIL` | Form einer E-Mail-Adresse | beweist nicht, dass das Postfach existiert |
| `FILTER_VALIDATE_URL` | Form einer URL | Schema selbst prüfen, keine internationalisierten Domains |
| `FILTER_VALIDATE_IP` | IP-Adresse | Flags für private und reservierte Bereiche |
| `FILTER_VALIDATE_REGEXP` | eigenes Muster | Muster mit `^` und `$` verankern |

Der Bereinigungsfilter `FILTER_SANITIZE_STRING` ist seit PHP 8.1 veraltet. Wer ihn noch nutzt, sollte die Validierung auf passende Filter umstellen und für die Ausgabe `htmlspecialchars()` verwenden.

## filter_var in PHP: ein Formular sauber prüfen

Mit `filter_input_array()` lässt sich ein ganzes Formular in einem Schritt gegen eine Definition prüfen. Unbekannte Felder werden dabei nicht übernommen:

```php
<?php
declare(strict_types=1);

$regeln = [
    'menge'   => ['filter' => FILTER_VALIDATE_INT,
                  'options' => ['min_range' => 1, 'max_range' => 50]],
    'email'   => FILTER_VALIDATE_EMAIL,
    'agb'     => ['filter' => FILTER_VALIDATE_BOOL, 'flags' => FILTER_NULL_ON_FAILURE],
    'versand' => ['filter' => FILTER_VALIDATE_REGEXP,
                  'options' => ['regexp' => '/^(standard|express)$/']],
];

$daten  = filter_input_array(INPUT_POST, $regeln) ?? [];
$fehler = [];

foreach ($regeln as $feld => $_) {
    if (!array_key_exists($feld, $daten) || $daten[$feld] === false || $daten[$feld] === null) {
        $fehler[] = $feld;
    }
}

if ($fehler !== []) {
    http_response_code(422);
    // Fehlermeldung je Feld ausgeben, Eingaben nicht verarbeiten
}
```

Beachten Sie die strikten Vergleiche mit `===`: Ein gültiger Wert `0` oder ein leerer String darf nicht mit einem Fehlschlag verwechselt werden. Warum lose Vergleiche hier gefährlich sind, erklärt [Type Juggling: Lose Vergleiche als Sicherheitsrisiko](https://phpsos.de/blog/type-juggling-php/). Wie PHP Anfragedaten überhaupt bereitstellt, beschreibt [Superglobals: $_GET, $_POST, $_FILES und Co.](https://phpsos.de/php/superglobals/).

## Fallstricke bei E-Mail, URL und freien Texten

Einige Filter tun weniger, als ihr Name vermuten lässt:

1. **URLs:** `FILTER_VALIDATE_URL` akzeptiert auch andere Schemata als http und https. Prüfen Sie das Schema danach mit `parse_url()` gegen eine feste Liste. Wird die URL vom Server abgerufen, gelten zusätzliche Regeln, siehe [Server-Side Request Forgery in PHP verhindern](https://phpsos.de/blog/ssrf-in-php/).
2. **E-Mail-Adressen:** Der Filter prüft die Form, nicht den Besitz. Wer sicher sein muss, schickt einen Bestätigungslink.
3. **Freitext:** Namen, Nachrichten und Adressen lassen sich kaum sinnvoll auf Zeichen beschränken. Prüfen Sie Länge und Zeichenkodierung, etwa mit `mb_check_encoding($wert, 'UTF-8')`, und verlassen Sie sich bei der Ausgabe auf Kodierung.
4. **Reguläre Ausdrücke:** Ohne `^` und `$` prüft ein Muster nur, ob es irgendwo im Text vorkommt, nicht ob der ganze Wert passt.
5. **Arrays statt Strings:** Ein Angreifer kann statt eines Textes ein Array senden. Ohne Typprüfung führt das zu Warnungen oder unerwartetem Verhalten.

> **Tipp:**
> Für feste Auswahlwerte wie Sortierung, Sprache oder Versandart ist eine Erlaubnisliste mit `in_array($wert, $erlaubt, true)` oder einem `match`-Ausdruck einfacher und strenger als jeder reguläre Ausdruck.

Ein weiterer häufiger Fehler betrifft Zahlen mit Bedeutung, etwa Preise, Mengen oder Rabatte. Dass ein Wert eine gültige Zahl ist, sagt nichts darüber, ob er im Zusammenhang erlaubt ist. Eine negative Menge, ein Rabatt über dem Warenwert oder ein Preis, der aus dem Formular statt aus der Datenbank übernommen wird, sind klassische Logikfehler. Preise, Berechtigungen und Statuswerte gehören deshalb immer auf den Server und nie in versteckte Formularfelder.

## JSON, Webhooks und Importe: Validierung jenseits von Formularen

Viele Eingänge sind heute keine Formulare mehr, sondern JSON-Anfragen von Apps, Webhooks von Zahlungsdiensten oder Importdateien von Lieferanten. Auch dort gilt: erst sicher einlesen, dann prüfen. OWASP rät, Größe und Verschachtelungstiefe zu begrenzen, bevor Daten überhaupt eingelesen werden. In PHP übernimmt `json_decode()` mit einer maximalen Tiefe und `JSON_THROW_ON_ERROR` einen Teil davon:

```php
<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // höchstens 64 KB
try {
    $daten = json_decode($roh, true, 16, JSON_THROW_ON_ERROR);
} catch (JsonException) {
    http_response_code(400);
    exit;
}
if (!is_array($daten) || !is_string($daten['bestellnummer'] ?? null)) {
    http_response_code(422);
    exit;
}
```

Bei Webhooks steht vor der inhaltlichen Prüfung die Frage, ob die Nachricht wirklich vom angegebenen Dienst stammt. Bietet der Dienst eine Signatur an, prüfen Sie diese und vergleichen sie mit `hash_equals()`. Bei Importdateien prüfen Sie jede Zeile wie ein Formular und brechen bei Fehlern sauber ab, statt halbe Datensätze zu übernehmen.

Fehlermeldungen sollten das betroffene Feld nennen, den abgelehnten Wert aber nicht ungefiltert zurückgeben. Sonst entsteht an der Fehlermeldung selbst eine neue Ausgabestelle, die wieder kodiert werden muss.

## Was Validierung nicht leisten kann

Validierung verkleinert die Angriffsfläche, aber sie ist laut OWASP nicht die Hauptverteidigung gegen Injection. Ein Nachname mit Apostroph ist gültig und muss trotzdem sicher in eine Datenbank gelangen. Das gelingt nur mit Prepared Statements, wie der Ratgeber [SQL-Injection in PHP verhindern](https://phpsos.de/ratgeber/sql-injection-php/) zeigt. Und ein gültiger Kommentartext wird erst durch kontextgerechte Kodierung bei der Ausgabe ungefährlich.

Die richtige Reihenfolge lautet also: beim Empfang validieren, bei der Verarbeitung parametrisieren, bei der Ausgabe kodieren. Zusätzlich gehören Größengrenzen davor: Anfragen, die viel zu groß sind, sollten Webserver und PHP gar nicht erst vollständig verarbeiten. Dazu dienen Einstellungen wie `post_max_size`, die nach PHP2Shell ohnehin überprüft werden sollten.

## Wie hilft PHP SOS konkret?

- Wir erfassen alle Eingänge Ihrer Anwendung: Formulare, Schnittstellen, Uploads, Importe und Webhooks.
- Wir legen je Feld fest, was erlaubt ist, und ersetzen pauschale Bereinigungsfunktionen durch klare Prüfungen.
- Wir prüfen, ob Datenbankzugriffe und Ausgaben unabhängig von der Validierung abgesichert sind.
- Wir dokumentieren die Regeln so, dass Ihr Team sie bei neuen Funktionen weiterführen kann.

Eine systematische Prüfung beschreibt die Leistung [Sicherheitsaudit und Penetrationstest](https://phpsos.de/leistungen/sicherheitsaudit-penetrationstest/).


## Häufige Fragen

**Was ist der Unterschied zwischen Validieren und Bereinigen?**  
Validieren prüft, ob ein Wert den Erwartungen entspricht, und lehnt ihn sonst ab. Bereinigen verändert den Wert, etwa indem Zeichen entfernt werden. Für Sicherheitsentscheidungen ist Ablehnen fast immer besser, weil ein stillschweigend veränderter Wert neue Fehler erzeugen kann.

**Ist FILTER_SANITIZE_STRING noch nutzbar?**  
Der Filter ist seit PHP 8.1 als veraltet markiert. Das PHP-Handbuch empfiehlt stattdessen htmlspecialchars() bei der Ausgabe. Bestehenden Code sollten Sie umstellen, weil veraltete Funktionen in künftigen Versionen entfallen können.

**Reicht FILTER_VALIDATE_URL, um Links sicher zu machen?**  
Nein. Der Filter prüft nur die Form der Adresse. Laut Handbuch muss eine gültige URL nicht mit http beginnen, deshalb müssen Sie das Schema selbst auf eine Erlaubnisliste wie https prüfen. Internationalisierte Domainnamen lehnt der Filter ab.

**Muss ich auch Daten aus der eigenen Datenbank validieren?**  
Bei der Ausgabe gelten sie als nicht vertrauenswürdig und werden passend kodiert. Eine erneute Validierung ist sinnvoll, wenn die Daten ursprünglich von außen kamen und jetzt in einem neuen Zusammenhang verwendet werden, etwa als Dateiname oder Teil eines Befehls.

**Hilft Validierung gegen PHP2Shell?**  
Nein. PHP2Shell betrifft die Verarbeitung von Anfragen im PHP-Interpreter, bevor Ihr Anwendungscode überhaupt läuft. Dagegen hilft nur das PHP-Update mit anschließendem Neustart aller PHP-Prozesse.

## Quellen

- [PHP-Handbuch: Filter-Konstanten](https://www.php.net/manual/de/filter.constants.php)
- [OWASP Input Validation Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
