Menu

Form in PHP: elaborare, validare e mostrare di nuovo

Un form PHP invia i dati a se stesso con <form method="post">, e lo script legge i campi da $_POST['name'] quando $_SERVER['REQUEST_METHOD'] è 'POST'. Impara la validazione, i messaggi di errore accanto ai campi, come mantenere i valori inseriti, checkbox e select e l'escape dell'output.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Un form PHP invia i dati allo script che lo ha stampato: scrivi <form method="post"> con dei campi con nome, e quando $_SERVER['REQUEST_METHOD'] è 'POST', leggi ogni campo come $_POST['name']. Applica htmlspecialchars() a tutto ciò che ristampi.

Esegui questo blocco, scrivi un nome nel form e premi Send: lo stesso script viene eseguito di nuovo, questa volta con $_POST compilato.

Qui succedono tre cose che servono a ogni gestore di form:

  • Il controllo del metodo. Alla prima visita la richiesta è un GET e non c'è nulla da elaborare. ?? 'GET' conta solo quando il file viene eseguito da riga di comando, dove REQUEST_METHOD non è impostato; su un server web lo è sempre.
  • ?? '' su ogni campo. Un campo può mancare (un input rinominato, una richiesta inviata da uno script), e leggere una chiave mancante stampa un warning.
  • L'escape in uscita. Il nome torna nella pagina due volte, e htmlspecialchars() fa sì che un valore come <b>Ada</b> venga mostrato come testo invece di diventare markup. I dettagli sono nella pagina su htmlspecialchars.

Validare un form e mostrare gli errori accanto ai campi

Raccogli gli errori in un array con il nome del campo come chiave. Se l'array è vuoto, il form è valido; altrimenti stampa di nuovo il form con ogni messaggio sotto il suo campo e l'input del visitatore ancora al suo posto. Invialo vuoto, poi con un'email non valida, poi con valori validi.

novalidate disattiva i controlli del browser così puoi vedere quelli di PHP al lavoro. In un form reale tienili entrambi: la validazione del browser è una comodità per il visitatore, quella di PHP è quella che conta, perché chiunque può inviare una richiesta senza il tuo form. filter_var() gestisce l'email e l'intervallo dell'intero con una chiamata ciascuno; la pagina su filter_var tratta gli altri suoi filtri.

Checkbox, radio button e select

Un campo di testo invia sempre un valore, anche vuoto. Gli altri controlli no:

  • Una checkbox non selezionata non invia nulla, quindi la sua chiave manca da $_POST.
  • Le checkbox chiamate topics[] arrivano come array: $_POST['topics'] è ['php', 'sql'].
  • Un gruppo di radio o una <select> invia il value dell'opzione scelta.

Per mantenere la scelta dopo l'invio, stampa checked o selected sull'opzione che corrisponde. Seleziona qualche casella, scegli un livello e premi Save.

I due controlli dopo la lettura dell'input contano più di quanto sembri. array_intersect() scarta ogni argomento che non era nel tuo elenco, e il controllo con is_string() più array_key_exists() riporta il livello a un default se qualcuno invia un valore che non hai mai offerto (o un array, che farebbe lanciare un errore a $levels[$level]). Una select limita ciò che può inviare un browser, non ciò che può contenere una richiesta.

Form in più passaggi con campi nascosti

Un input nascosto porta un valore da un passaggio al successivo senza mostrarlo. Qui il passaggio 1 chiede un nome, il passaggio 2 chiede una lingua e porta con sé il nome in un campo nascosto, e il passaggio 3 li mostra entrambi. Percorri tutti e tre i passaggi.

I campi nascosti sono visibili nel sorgente della pagina e modificabili come qualsiasi altro campo, quindi vanno bene per portare le risposte del visitatore tra un passaggio e l'altro, ma mai per un prezzo, un id utente o un ruolo. Tieni quelli sul server, in una sessione; vedi sessioni e cookie.

Post/Redirect/Get: evitare il reinvio al ricaricamento

Dopo un POST riuscito, se lo script stampa direttamente una pagina di "grazie", premere ricarica chiede al browser di inviare di nuovo il POST, e l'ordine o il commento viene salvato due volte. La soluzione è salvare, fare un redirect e mostrare il risultato con un 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 dice al browser di seguire il redirect con un GET. exit dopo header() conta: senza, il resto dello script continua a essere eseguito. Il redirect deve anche avvenire prima di qualsiasi output, altrimenti PHP si rifiuta con "headers already sent".

I form reali aggiungono anche un token CSRF: un valore casuale salvato nella sessione e in un campo nascosto, confrontato con hash_equals() all'invio, così un altro sito non può inviare dati al tuo form a nome di un visitatore autenticato.

Testare la validazione senza browser

Metti le regole in una funzione che riceve un array e restituisce gli errori. La pagina la chiama con $_POST, e tu puoi chiamarla con qualsiasi array, il che rende facile provare i casi limite. Aggiungi i tuoi casi all'elenco.

Il quarto caso è quello che si dimentica. Una richiesta può inviare name[]=x, che rende $_POST['name'] un array, e passare un array a trim() lancia un TypeError e ferma lo script. Verificare prima is_string() trasforma un input ostile in un normale errore di validazione. Anche il cast (string) dei blocchi precedenti evita il TypeError, ma trasforma l'array nella parola Array e stampa un warning, quindi is_string() è il controllo più pulito.

Errore comune: leggere $_POST prima che il form sia inviato

Il primo script di form più comune legge i campi in cima al file:

<?php
$name = $_POST['name'];
echo "Hello, $name";

Alla prima visita non è stato inviato nulla, quindi PHP stampa:

Warning: Undefined array key "name" in /var/www/form.php on line 2

La soluzione è lo schema del primo blocco: elabora il form solo quando la richiesta è un POST, e leggi ogni campo con un default, $_POST['name'] ?? ''. Se il warning compare dopo l'invio, confronta l'attributo name nell'HTML con la chiave in PHP: name="Name" e $_POST['name'] sono chiavi diverse.

Domande frequenti

Come invio un form PHP alla stessa pagina?

Scrivi <form method="post"> senza action (o con action=""). Il browser invia di nuovo all'URL corrente, quindi lo stesso script mostra il form e lo gestisce: verifica $_SERVER['REQUEST_METHOD'] === 'POST' e leggi i campi da $_POST.

Come mantengo i valori del form dopo l'invio in PHP?

Stampa di nuovo nel campo il valore inviato, con l'escape: <input name="email" value="<?= htmlspecialchars($_POST['email'] ?? '') ?>">. Per una checkbox stampa checked, e per un'opzione di una select stampa selected, quando il valore inviato corrisponde.

Come ottengo i valori di più checkbox in PHP?

Dai alle checkbox lo stesso nome che termina con le parentesi quadre, name="topics[]". PHP mette allora i valori selezionati in un array, $_POST['topics']. Le caselle non selezionate non inviano nulla, quindi usa $_POST['topics'] ?? [] e confronta ogni valore con l'elenco che hai offerto.

Perché ricaricare la pagina reinvia il mio form PHP?

L'ultima richiesta era un POST, quindi il browser la ripete al ricaricamento. Dopo un invio riuscito, fai un redirect con header('Location: /thanks.php'); exit; (lo schema Post/Redirect/Get). Il ricaricamento ripete allora un GET innocuo.

$_POST è sicuro da usare in PHP?

No, ogni valore in $_POST arriva dal visitatore e può essere qualsiasi cosa, compresi HTML, SQL o un array dove ti aspettavi una stringa. Validalo in ingresso (filter_var, controlli di lunghezza e su liste consentite) e applica l'escape in uscita (htmlspecialchars per l'HTML, prepared statement per l'SQL).

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA