Walidacja i sanityzacja — bezpieczne dane wejściowe
🎯 Po tej lekcji będziesz walidować e-mail i liczby przez filter_var, czyścić dane przez trim i rozumieć różnicę między walidacją a sanityzacją.
W poprzedniej lekcji sprawdzałeś tylko, czy pole jest puste. Ale co jeśli ktoś wpisze „abc" zamiast adresu e-mail albo „sto lat" zamiast wieku? Pora nauczyć się walidacji i sanityzacji — dwóch nierozłącznych technik obsługi danych wejściowych.
Walidacja vs sanityzacja — różnica
Te dwa terminy brzmią podobnie, ale robią różne rzeczy:
- Walidacja — sprawdza, czy dane spełniają wymagania. Odpowiada na pytanie: „czy ten email jest poprawny?". Wynik: tak lub nie (dane zostają niezmienione).
- Sanityzacja — czyści lub przetwarza dane. Usuwa zbędne spacje, zamienia format, usuwa niedozwolone znaki. Dane mogą się zmienić.
W praktyce często robisz obie naraz: sanityzujesz (np. przez trim), a potem walidatujesz (np. przez filter_var).
trim — pierwszy krok sanityzacji
Zanim cokolwiek sprawdzisz, wyczyść dane z przypadkowych spacji na początku i końcu. Użytkownicy nagminnie wklejają tekst ze spacjami:
<?php
declare(strict_types=1);
$email = ' [email protected] '; // użytkownik skopiował z maila
$email = trim($email);
echo $email; // wynik: [email protected]
Zasada: trim zawsze przed walidacją. Pole z samymi spacjami po trim stanie się pustym łańcuchem '' — łatwo sprawdzić wymagane pola.
filter_var — walidacja formatów
PHP dostarcza wbudowaną funkcję filter_var, która sprawdza wiele popularnych formatów danych. Przy flagach FILTER_VALIDATE_* zwraca przefiltrowaną wartość jeśli dane są poprawne, lub false jeśli nie.
Walidacja adresu e-mail
<?php
declare(strict_types=1);
$email = '[email protected]';
if (filter_var($email, FILTER_VALIDATE_EMAIL) !== false) {
echo 'Adres e-mail jest poprawny.';
} else {
echo 'Nieprawidłowy adres e-mail.';
}
// Kilka przykładów:
var_dump(filter_var('[email protected]', FILTER_VALIDATE_EMAIL)); // string(15) "[email protected]"
var_dump(filter_var('nie-to-email', FILTER_VALIDATE_EMAIL)); // wynik: bool(false)
var_dump(filter_var('@brak-nazwy.pl', FILTER_VALIDATE_EMAIL)); // wynik: bool(false)
!== false, nie samego !. Dla FILTER_VALIDATE_INT wartość 0 jest prawidłowym wynikiem i jest falsy — !0 zwróciłoby true, czyli błędnie uznałoby zero za nieprawidłowe.Walidacja liczby całkowitej
<?php
declare(strict_types=1);
$wiek = filter_var('25', FILTER_VALIDATE_INT);
var_dump($wiek); // wynik: int(25)
$blednyWiek = filter_var('dwadziescia', FILTER_VALIDATE_INT);
var_dump($blednyWiek); // wynik: bool(false)
// Walidacja z zakresem:
$opcje = ['options' => ['min_range' => 0, 'max_range' => 120]];
var_dump(filter_var(25, FILTER_VALIDATE_INT, $opcje)); // wynik: int(25)
var_dump(filter_var(200, FILTER_VALIDATE_INT, $opcje)); // wynik: bool(false)
var_dump(filter_var(-1, FILTER_VALIDATE_INT, $opcje)); // wynik: bool(false)
Kompletny przykład — formularz z walidacją
Oto formularz rejestracyjny łączący sanityzację, walidację i bezpieczne wyświetlanie danych:
<?php
declare(strict_types=1);
$imie = '';
$email = '';
$wiek = '';
$bledy = [];
$sukces = false;
if (isset($_POST['wyslij'])) {
// 1. Sanityzacja — wyczyść dane z formularza
$imie = trim($_POST['imie'] ?? '');
$email = trim($_POST['email'] ?? '');
$wiek = trim($_POST['wiek'] ?? '');
// 2. Walidacja — sprawdź wymagania
if ($imie === '') {
$bledy[] = 'Imię jest wymagane.';
} elseif (strlen($imie) < 2) {
$bledy[] = 'Imię musi mieć co najmniej 2 znaki.';
}
if ($email === '') {
$bledy[] = 'Adres e-mail jest wymagany.';
} elseif (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
$bledy[] = 'Podaj prawidłowy adres e-mail.';
}
if ($wiek === '') {
$bledy[] = 'Wiek jest wymagany.';
} else {
$opcje = ['options' => ['min_range' => 0, 'max_range' => 120]];
if (filter_var($wiek, FILTER_VALIDATE_INT, $opcje) === false) {
$bledy[] = 'Wiek musi być liczbą całkowitą od 0 do 120.';
}
}
if ($bledy === []) {
// Wszystko poprawne — tutaj zapisałbyś dane do bazy
$sukces = true;
}
}
?>
<!DOCTYPE html>
<html lang="pl">
<head><meta charset="UTF-8"><title>Rejestracja</title></head>
<body>
<?php if ($sukces): ?>
<p>Zarejestrowano: <?= htmlspecialchars($imie, ENT_QUOTES, 'UTF-8') ?>,
<?= htmlspecialchars($email, ENT_QUOTES, 'UTF-8') ?>,
wiek: <?= htmlspecialchars($wiek, ENT_QUOTES, 'UTF-8') ?></p>
<?php else: ?>
<?php if ($bledy !== []): ?>
<ul style="color:red">
<?php foreach ($bledy as $blad): ?>
<li><?= htmlspecialchars($blad, ENT_QUOTES, 'UTF-8') ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<form method="post" action="">
<label>Imię:
<input type="text" name="imie"
value="<?= htmlspecialchars($imie, ENT_QUOTES, 'UTF-8') ?>">
</label><br>
<label>E-mail:
<input type="email" name="email"
value="<?= htmlspecialchars($email, ENT_QUOTES, 'UTF-8') ?>">
</label><br>
<label>Wiek:
<input type="number" name="wiek"
value="<?= htmlspecialchars($wiek, ENT_QUOTES, 'UTF-8') ?>">
</label><br>
<button type="submit" name="wyslij">Zarejestruj się</button>
</form>
<?php endif; ?>
</body>
</html>
Podsumowanie nawyków bezpieczeństwa
| Krok | Co robisz | Funkcja |
|---|---|---|
| 1. Wejście | Wyczyść spacje | trim() |
| 2. Wejście | Sprawdź format | filter_var() |
| 3. Wyjście | Zabezpiecz HTML | htmlspecialchars() |
required, type="email") i JavaScript to wygoda dla użytkownika — nie bezpieczeństwo. Ktoś może wyłączyć JS lub wysłać żądanie HTTP ręcznie. Zawsze waliduj w PHP.Masz już solidne fundamenty bezpieczeństwa formularzy. W kolejnej lekcji zajmiemy się sesjami i ciasteczkami — czyli tym, jak „zapamiętać" użytkownika między kolejnymi żądaniami.
Funkcje w tej lekcji
Sprawdź się
Co zwraca filter_var('sto', FILTER_VALIDATE_INT)?
FILTER_VALIDATE_INT zwraca false gdy wartość nie jest prawidłową liczbą całkowitą. 'sto' to słowo, nie liczba — wynikiem jest false.
Jaka jest kluczowa różnica między walidacją a sanityzacją?
Walidacja odpowiada na pytanie 'czy dane są poprawne?' (tak/nie). Sanityzacja modyfikuje dane, usuwając zbędne znaki lub zamieniając format. Można robić obie naraz.
Dlaczego trim() stosuje się PRZED sprawdzeniem czy pole jest puste?
Pole zawierające tylko spacje (np. użytkownik wcisnął spację) wyglądałoby jako niepuste bez trim(). Po trim() ' ' staje się '' i sprawdzenie === '' działa poprawnie.
Ćwiczenie
Napisz funkcję validateKontakt(string $imie, string $email, string $wiek): array, która zwraca tablicę błędów. Reguły: imię minimum 2 znaki, email poprawny format, wiek liczba całkowita 0–120. Funkcja powinna zwrócić pustą tablicę gdy wszystko jest OK.
Pokaż rozwiązanie
<?php
declare(strict_types=1);
function validateKontakt(string $imie, string $email, string $wiek): array
{
$bledy = [];
if (strlen($imie) < 2) {
$bledy[] = 'Imię musi mieć co najmniej 2 znaki.';
}
if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
$bledy[] = 'Podaj prawidłowy adres e-mail.';
}
$opcje = ['options' => ['min_range' => 0, 'max_range' => 120]];
if (filter_var($wiek, FILTER_VALIDATE_INT, $opcje) === false) {
$bledy[] = 'Wiek musi być liczbą całkowitą od 0 do 120.';
}
return $bledy;
}
// Testy
print_r(validateKontakt('Ola', '[email protected]', '25')); // []
print_r(validateKontakt('X', 'nie-email', '999')); // 3 błędy