# Walidacja i filtrowanie danych wejściowych w PHP za pomocą filter_var

> Walidacja danych wejściowych w PHP z filter_var i filter_input_array: liczby, e-mail, URL, wartości logiczne, listy dozwolonych i granice. Z przykładami kodu.

Źródło: https://phpsos.de/pl/blog/eingaben-validieren-php/  
Stan: 25.10.2026  
Dostawca: PHP SOS, Pomoc awaryjna PHP i bezpieczeństwo serwerów. Natychmiastowa pomoc przez WhatsApp: https://wa.me/491736494914?text=Dzie%C5%84%20dobry%2C%20PHP%20SOS%2C%20potrzebujemy%20pomocy%20z%20naszym%20serwerem%20PHP.%20Firma%3A%20%E2%80%A6%20Strona%20internetowa%3A%20%E2%80%A6

**Krótko:** Dane wejściowe w PHP walidujesz za pomocą `filter_var()` lub `filter_input_array()` i jasnych reguł dla każdego pola: typ, zakres, długość i dozwolone wartości. To, co nie pasuje, jest odrzucane, a nie po cichu przerabiane. Walidacja jest ważna dla czystych danych i mniejszej powierzchni ataku, ale nie zastępuje ani prepared statements przeciw SQL injection, ani kodowania zależnego od kontekstu przeciw XSS.

## Dlaczego „filtrować wszystko” nie jest koncepcją

W wielu starszych projektach PHP na początku każdego pliku znajduje się pętla, która przepuszcza wszystkie wartości z `$_GET` i `$_POST` przez funkcję oczyszczającą. Daje to poczucie bezpieczeństwa. W praktyce raz usuwa za dużo, na przykład apostrofy w nazwiskach, a raz za mało, ponieważ ta sama funkcja ma jednocześnie obowiązywać dla SQL, HTML i nazw plików.

Sensowna walidacja działa inaczej: dla każdego pola pyta, co jest tam dozwolone. Ilość w zamówieniu to liczba całkowita od 1 do górnej granicy. Pole sortowania to jedna z trzech stałych wartości. Data występuje w określonym formacie i jest po innej dacie. Wszystko inne jest odrzucane.

OWASP rozróżnia tu dwa poziomy: kontrolę **składniową**, czy wartość ma właściwą formę, oraz kontrolę **semantyczną**, czy w danym kontekście ma sens. Obie należą do serwera; kontrole w przeglądarce służą wyłącznie wygodzie obsługi.

## Jakie filtry oferuje PHP

Rozszerzenie filter jest w PHP domyślnie dołączone. Najważniejsze filtry walidacyjne według podręcznika PHP:

| Filtr | Sprawdza | Ważne opcje i wskazówki |
|---|---|---|
| `FILTER_VALIDATE_INT` | liczba całkowita | `min_range`, `max_range` |
| `FILTER_VALIDATE_FLOAT` | liczba z przecinkiem | `decimal` dla separatora |
| `FILTER_VALIDATE_BOOL` | wartość logiczna | z `FILTER_NULL_ON_FAILURE` można odróżnić od „fałsz” |
| `FILTER_VALIDATE_EMAIL` | forma adresu e-mail | nie dowodzi, że skrzynka istnieje |
| `FILTER_VALIDATE_URL` | forma adresu URL | schemat sprawdzić samodzielnie, brak internacjonalizowanych domen |
| `FILTER_VALIDATE_IP` | adres IP | flagi dla zakresów prywatnych i zarezerwowanych |
| `FILTER_VALIDATE_REGEXP` | własny wzorzec | zakotwiczyć wzorzec za pomocą `^` i `$` |

Filtr oczyszczający `FILTER_SANITIZE_STRING` jest od PHP 8.1 przestarzały. Kto jeszcze go używa, powinien przestawić walidację na odpowiednie filtry, a przy wyświetlaniu stosować `htmlspecialchars()`.

## filter_var w PHP: poprawne sprawdzanie formularza

Za pomocą `filter_input_array()` można sprawdzić cały formularz w jednym kroku względem definicji. Nieznane pola nie są przy tym przejmowane:

```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);
    // Wyświetlić komunikat o błędzie dla każdego pola, nie przetwarzać danych wejściowych
}
```

Zwróć uwagę na ścisłe porównania za pomocą `===`: prawidłowa wartość `0` lub pusty ciąg nie mogą być mylone z niepowodzeniem. Dlaczego luźne porównania są tu niebezpieczne, wyjaśnia artykuł [Type juggling: luźne porównania jako ryzyko bezpieczeństwa](https://phpsos.de/pl/blog/type-juggling-php/). Jak PHP w ogóle udostępnia dane żądania, opisuje artykuł [Superglobals: $_GET, $_POST, $_FILES i inne](https://phpsos.de/pl/php/superglobals/).

## Pułapki przy e-mailu, URL i tekstach swobodnych

Niektóre filtry robią mniej, niż sugeruje ich nazwa:

1. **Adresy URL:** `FILTER_VALIDATE_URL` akceptuje także inne schematy niż http i https. Sprawdź potem schemat za pomocą `parse_url()` względem stałej listy. Jeśli adres URL jest pobierany przez serwer, obowiązują dodatkowe reguły, zob. [Zapobieganie Server-Side Request Forgery w PHP](https://phpsos.de/pl/blog/ssrf-in-php/).
2. **Adresy e-mail:** Filtr sprawdza formę, a nie posiadanie. Kto musi mieć pewność, wysyła link potwierdzający.
3. **Tekst swobodny:** Imion, wiadomości i adresów prawie nie da się sensownie ograniczyć do znaków. Sprawdzaj długość i kodowanie znaków, na przykład za pomocą `mb_check_encoding($wert, 'UTF-8')`, a przy wyświetlaniu polegaj na kodowaniu.
4. **Wyrażenia regularne:** Bez `^` i `$` wzorzec sprawdza tylko, czy występuje gdzieś w tekście, a nie czy pasuje cała wartość.
5. **Tablice zamiast ciągów:** Atakujący może zamiast tekstu wysłać tablicę. Bez kontroli typu prowadzi to do ostrzeżeń lub nieoczekiwanego zachowania.

> **Wskazówka:**
> Dla stałych wartości wyboru, takich jak sortowanie, język czy sposób wysyłki, lista dozwolonych z `in_array($wert, $erlaubt, true)` lub wyrażeniem `match` jest prostsza i ostrzejsza niż każde wyrażenie regularne.

Kolejny częsty błąd dotyczy liczb o znaczeniu, takich jak ceny, ilości czy rabaty. To, że wartość jest prawidłową liczbą, nic nie mówi o tym, czy jest dozwolona w danym kontekście. Ujemna ilość, rabat przewyższający wartość towaru albo cena przejęta z formularza zamiast z bazy danych to klasyczne błędy logiki. Ceny, uprawnienia i wartości statusów należą więc zawsze na serwer, a nigdy do ukrytych pól formularza.

## JSON, webhooki i importy: walidacja poza formularzami

Wiele wejść to dziś nie formularze, lecz żądania JSON z aplikacji, webhooki z usług płatniczych albo pliki importowe od dostawców. Także tam obowiązuje: najpierw bezpiecznie wczytać, potem sprawdzić. OWASP radzi ograniczać rozmiar i głębokość zagnieżdżenia, zanim dane w ogóle zostaną wczytane. W PHP część tego przejmuje `json_decode()` z maksymalną głębokością i `JSON_THROW_ON_ERROR`:

```php
<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // najwyżej 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;
}
```

W przypadku webhooków przed kontrolą treści stoi pytanie, czy wiadomość rzeczywiście pochodzi od wskazanej usługi. Jeśli usługa oferuje podpis, sprawdź go i porównaj za pomocą `hash_equals()`. W przypadku plików importowych sprawdzaj każdy wiersz jak formularz i przy błędach przerywaj w czysty sposób, zamiast przejmować połowiczne rekordy.

Komunikaty o błędach powinny wskazywać pole, którego dotyczą, ale nie zwracać odrzuconej wartości bez filtrowania. W przeciwnym razie w samym komunikacie o błędzie powstaje nowe miejsce wyjścia, które znowu trzeba zakodować.

## Czego walidacja nie jest w stanie zapewnić

Walidacja zmniejsza powierzchnię ataku, ale według OWASP nie jest główną obroną przed injection. Nazwisko z apostrofem jest prawidłowe i mimo to musi bezpiecznie trafić do bazy danych. Udaje się to tylko za pomocą prepared statements, jak pokazuje poradnik [Zapobieganie SQL injection w PHP](https://phpsos.de/pl/ratgeber/sql-injection-php/). A prawidłowy tekst komentarza staje się bezpieczny dopiero dzięki kodowaniu zależnemu od kontekstu przy wyświetlaniu.

Właściwa kolejność brzmi więc: przy odbiorze walidować, przy przetwarzaniu parametryzować, przy wyświetlaniu kodować. Dodatkowo przed tym stoją granice rozmiaru: żądań, które są znacznie za duże, serwer WWW i PHP w ogóle nie powinny przetwarzać w całości. Służą do tego ustawienia takie jak `post_max_size`, które po PHP2Shell i tak należy sprawdzić.

## Jak konkretnie pomaga PHP SOS?

- Spisujemy wszystkie wejścia Państwa aplikacji: formularze, interfejsy, uploady, importy i webhooki.
- Ustalamy dla każdego pola, co jest dozwolone, i zastępujemy ogólne funkcje oczyszczające jasnymi kontrolami.
- Sprawdzamy, czy dostęp do bazy danych i wyświetlanie są zabezpieczone niezależnie od walidacji.
- Dokumentujemy reguły tak, aby Państwa zespół mógł je kontynuować przy nowych funkcjach.

Systematyczną kontrolę opisuje usługa [audyt bezpieczeństwa i test penetracyjny](https://phpsos.de/pl/leistungen/sicherheitsaudit-penetrationstest/).


## Częste pytania

**Jaka jest różnica między walidacją a oczyszczaniem?**  
Walidacja sprawdza, czy wartość odpowiada oczekiwaniom, a w przeciwnym razie ją odrzuca. Oczyszczanie zmienia wartość, na przykład usuwając znaki. W decyzjach dotyczących bezpieczeństwa odrzucenie jest prawie zawsze lepsze, ponieważ po cichu zmieniona wartość może powodować nowe błędy.

**Czy FILTER_SANITIZE_STRING można jeszcze używać?**  
Filtr jest od PHP 8.1 oznaczony jako przestarzały. Podręcznik PHP zaleca zamiast niego htmlspecialchars() przy wyświetlaniu. Istniejący kod należy zmienić, ponieważ przestarzałe funkcje mogą zniknąć w przyszłych wersjach.

**Czy FILTER_VALIDATE_URL wystarczy, aby zabezpieczyć linki?**  
Nie. Filtr sprawdza tylko formę adresu. Według podręcznika prawidłowy adres URL nie musi zaczynać się od http, dlatego schemat trzeba samodzielnie sprawdzić względem listy dozwolonych, takiej jak https. Internacjonalizowane nazwy domen filtr odrzuca.

**Czy muszę walidować także dane z własnej bazy danych?**  
Przy wyświetlaniu uznaje się je za niezaufane i odpowiednio koduje. Ponowna walidacja ma sens, jeśli dane pierwotnie pochodziły z zewnątrz i są teraz używane w nowym kontekście, na przykład jako nazwa pliku lub część polecenia.

**Czy walidacja pomaga przy PHP2Shell?**  
Nie. PHP2Shell dotyczy przetwarzania żądań w interpreterze PHP, zanim kod Państwa aplikacji w ogóle zacznie działać. Pomaga na to wyłącznie aktualizacja PHP z następującym po niej restartem wszystkich procesów PHP.

## Źródła

- [Podręcznik PHP: stałe filtrów](https://www.php.net/manual/de/filter.constants.php)
- [OWASP Input Validation Cheat Sheet (ściągawka o walidacji danych wejściowych)](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
