Formularz PHP wysyła dane z powrotem do skryptu, który go wypisał: napisz <form method="post"> z nazwanymi polami, a gdy $_SERVER['REQUEST_METHOD'] to 'POST', odczytaj każde pole jako $_POST['name']. Wszystko, co wypisujesz z powrotem, escapuj przez htmlspecialchars().
Uruchom ten blok, wpisz imię w formularzu i naciśnij Send: ten sam skrypt uruchomi się ponownie, tym razem z wypełnionym $_POST.
Dzieją się tu trzy rzeczy, których potrzebuje każda obsługa formularza:
- Sprawdzenie metody. Przy pierwszej wizycie żądanie to GET i nie ma czego przetwarzać.
?? 'GET'ma znaczenie tylko wtedy, gdy plik działa z wiersza poleceń, gdzieREQUEST_METHODnie jest ustawione; na serwerze WWW zawsze jest. ?? ''przy każdym polu. Pola może brakować (pole o zmienionej nazwie, żądanie wysłane przez skrypt), a odczyt brakującego klucza wypisuje ostrzeżenie.- Escapowanie na wyjściu. Imię wraca na stronę dwa razy, a
htmlspecialchars()sprawia, że wartość taka jak<b>Ada</b>jest pokazywana jako tekst, zamiast stać się znacznikiem. Szczegóły są na stronie o htmlspecialchars.
Walidacja formularza i błędy przy polach
Zbieraj błędy w tablicy z kluczami będącymi nazwami pól. Jeśli tablica jest pusta, formularz jest poprawny; w przeciwnym razie wypisz formularz ponownie z każdym komunikatem pod jego polem i z zachowanymi danymi odwiedzającego. Wyślij go pustego, potem ze złym e-mailem, a potem z poprawnymi wartościami.
novalidate wyłącza własne sprawdzenia przeglądarki, żebyś mógł zobaczyć działanie tych w PHP. W prawdziwym formularzu zachowaj oba: walidacja w przeglądarce to wygoda dla odwiedzającego, a walidacja w PHP to ta, która się liczy, bo każdy może wysłać żądanie bez twojego formularza. filter_var() sprawdza e-mail i zakres liczby całkowitej jednym wywołaniem każde; pozostałe filtry opisuje strona o filter_var.
Pola wyboru, przyciski opcji i listy rozwijane
Pole tekstowe zawsze wysyła wartość, nawet pustą. Pozostałe kontrolki nie:
- Niezaznaczone pole wyboru nie wysyła nic, więc jego klucza brakuje w
$_POST. - Pola wyboru o nazwie
topics[]przychodzą jako tablica:$_POST['topics']to['php', 'sql']. - Grupa przycisków opcji albo
<select>wysyłavaluewybranej opcji.
Aby zachować wybór po wysłaniu, wypisz checked lub selected przy pasującej opcji. Zaznacz kilka pól, wybierz poziom i naciśnij Save.
Dwa sprawdzenia po odczycie danych mają większe znaczenie, niż się wydaje. array_intersect() odrzuca każdy temat spoza twojej listy, a sprawdzenie is_string() razem z array_key_exists() przywraca poziom domyślny, jeśli ktoś wyśle wartość, której nigdy nie oferowałeś (albo tablicę, przez którą $levels[$level] rzuciłoby błąd). Lista rozwijana ogranicza to, co może wysłać przeglądarka, a nie to, co może zawierać żądanie.
Formularze wieloetapowe z polami ukrytymi
Pole ukryte przenosi wartość z jednego etapu do następnego, nie pokazując jej. Tutaj etap 1 pyta o imię, etap 2 pyta o język i przesyła imię dalej w ukrytym polu, a etap 3 pokazuje oba. Przejdź przez wszystkie trzy etapy.
Pola ukryte są widoczne w źródle strony i edytowalne jak każde inne pole, więc nadają się do przenoszenia własnych odpowiedzi odwiedzającego między etapami, ale nigdy do ceny, identyfikatora użytkownika czy roli. Takie dane trzymaj na serwerze, w sesji; zobacz sesje i ciasteczka.
Post/Redirect/Get: koniec z ponownym wysyłaniem przy odświeżeniu
Jeśli po udanym POST skrypt wypisze stronę z podziękowaniem bezpośrednio, naciśnięcie odświeżenia każe przeglądarce wysłać POST ponownie, a zamówienie albo komentarz zostanie zapisane dwa razy. Rozwiązanie to zapisanie, przekierowanie i pokazanie wyniku przez GET:
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$errors = validate($_POST);
if (!$errors) {
save_comment($_POST);
$_SESSION['flash'] = 'Comment posted.';
header('Location: /comments.php', true, 303);
exit;
}
// On errors, fall through and print the form with the messages.
}
$flash = $_SESSION['flash'] ?? null;
unset($_SESSION['flash']);
303 See Other każe przeglądarce wykonać przekierowanie przez GET. exit po header() ma znaczenie: bez niego reszta skryptu działa dalej. Przekierowanie musi też nastąpić przed jakimkolwiek wyjściem, inaczej PHP odmówi z komunikatem „headers already sent”.
Prawdziwe formularze dodają też token CSRF: losową wartość zapisaną w sesji i w ukrytym polu, porównywaną przy wysłaniu przez hash_equals(), żeby inna strona nie mogła wysłać danych do twojego formularza w imieniu zalogowanego odwiedzającego.
Testowanie walidacji bez przeglądarki
Umieść zasady w funkcji, która przyjmuje tablicę i zwraca błędy. Strona wywołuje ją z $_POST, a ty możesz wywołać ją z dowolną tablicą, co ułatwia sprawdzanie przypadków brzegowych. Dodaj do listy własne przypadki.
O czwartym przypadku ludzie zapominają. Żądanie może wysłać name[]=x, przez co $_POST['name'] staje się tablicą, a przekazanie tablicy do trim() rzuca TypeError i zatrzymuje skrypt. Sprawdzenie najpierw is_string() zamienia wrogie dane w zwykły błąd walidacji. Rzutowanie (string) we wcześniejszych blokach też unika TypeError, ale zamienia tablicę w słowo Array i wypisuje ostrzeżenie, więc is_string() to czystsze sprawdzenie.
Częsty błąd: odczyt $_POST przed wysłaniem formularza
Najczęstszy pierwszy skrypt formularza odczytuje pola na górze pliku:
<?php
$name = $_POST['name'];
echo "Hello, $name";
Przy pierwszej wizycie nic nie zostało wysłane, więc PHP wypisuje:
Warning: Undefined array key "name" in /var/www/form.php on line 2
Rozwiązanie to wzorzec z pierwszego bloku: przetwarzaj formularz tylko wtedy, gdy żądanie to POST, i odczytuj każde pole z wartością domyślną, $_POST['name'] ?? ''. Jeśli ostrzeżenie pojawia się po wysłaniu, porównaj atrybut name w HTML z kluczem w PHP: name="Name" i $_POST['name'] to różne klucze.
Najczęściej zadawane pytania
Jak wysłać formularz PHP na tę samą stronę?
Napisz <form method="post"> bez action (albo z action=""). Przeglądarka wysyła dane z powrotem na bieżący URL, więc ten sam skrypt pokazuje formularz i go obsługuje: sprawdź $_SERVER['REQUEST_METHOD'] === 'POST' i odczytaj pola z $_POST.
Jak zachować wartości formularza po wysłaniu w PHP?
Wypisz przesłaną wartość z powrotem w polu, escapowaną: <input name="email" value="<?= htmlspecialchars($_POST['email'] ?? '') ?>">. Dla pola wyboru wypisz checked, a dla opcji listy rozwijanej selected, gdy przesłana wartość się zgadza.
Jak pobrać wartości kilku pól wyboru (checkbox) w PHP?
Nadaj polom tę samą nazwę zakończoną nawiasami, name="topics[]". PHP umieszcza wtedy zaznaczone wartości w tablicy $_POST['topics']. Niezaznaczone pola nic nie wysyłają, więc użyj $_POST['topics'] ?? [] i sprawdź każdą wartość z listą, którą zaoferowałeś.
Dlaczego odświeżenie strony ponownie wysyła mój formularz PHP?
Ostatnie żądanie było POST, więc przeglądarka powtarza je przy odświeżeniu. Po udanym wysłaniu przekieruj przez header('Location: /thanks.php'); exit; (wzorzec Post/Redirect/Get). Odświeżenie powtórzy wtedy nieszkodliwy GET.
Czy $_POST w PHP jest bezpieczne?
Nie, każda wartość w $_POST pochodzi od odwiedzającego i może być czymkolwiek, w tym HTML, SQL albo tablicą tam, gdzie spodziewałeś się stringa. Waliduj ją na wejściu (filter_var, sprawdzanie długości i listy dozwolonych wartości) i escapuj na wyjściu (htmlspecialchars dla HTML, zapytania przygotowane dla SQL).