Introduzione
Un caso pratico di persistenza consiste nel ricordare a quale punto di una procedura guidata si è arrivati. Immaginiamo, per esempio, un modulo di configurazione diviso in più passaggi: dati personali, indirizzo di spedizione e riepilogo finale. Se l’utente chiude accidentalmente il browser o ricarica la pagina, può essere utile ripristinare automaticamente l’ultimo passaggio visitato.
In questo tutorial utilizzeremo un cookie per memorizzare esclusivamente il numero dello step corrente. Il cookie non conterrà dati sensibili, ma soltanto un valore semplice come 1, 2 o 3. I dati inseriti nei campi del modulo resteranno invece sul server o dovranno essere salvati con un meccanismo separato.
Questa distinzione è importante: un cookie è visibile e modificabile dal browser dell’utente. Non deve quindi essere considerato un archivio sicuro per password, dati personali, token non protetti o informazioni riservate.
Codice completo
Il seguente esempio è contenuto in un unico file chiamato wizard.php. Il programma:
- legge lo step corrente dal cookie;
- verifica che il valore sia compreso tra quelli consentiti;
- permette di passare allo step successivo o precedente;
- salva la posizione per sette giorni;
- offre un pulsante per ricominciare da capo.
<?php
declare(strict_types=1);
// Numero totale degli step disponibili.
const TOTAL_STEPS = 3;
// Durata del cookie: sette giorni.
const COOKIE_DURATION = 604800;
// Leggiamo lo step dal cookie, se presente.
$stepFromCookie = filter_input(
INPUT_COOKIE,
´wizard_step´,
FILTER_VALIDATE_INT
);
// Se il cookie è assente o contiene un valore non valido,
// partiamo dal primo step.
$currentStep = $stepFromCookie ?: 1;
// Manteniamo il valore entro l´intervallo consentito.
if ($currentStep < 1 || $currentStep > TOTAL_STEPS) {
$currentStep = 1;
}
// Gestione delle azioni richieste dal modulo.
$action = $_POST[´action´] ?? null;
if ($action === ´next´ && $currentStep < TOTAL_STEPS) {
$currentStep++;
}
if ($action === ´previous´ && $currentStep > 1) {
$currentStep--;
}
if ($action === ´reset´) {
// Scadenza nel passato: il browser eliminerà il cookie.
setcookie(´wizard_step´, ´´, [
´expires´ => time() - 3600,
´path´ => ´/´,
´secure´ => !empty($_SERVER[´HTTPS´]) && $_SERVER[´HTTPS´] !== ´off´,
´httponly´ => true,
´samesite´ => ´Lax´
]);
$currentStep = 1;
} else {
// Salviamo il nuovo step per sette giorni.
setcookie(´wizard_step´, (string) $currentStep, [
´expires´ => time() + COOKIE_DURATION,
´path´ => ´/´,
´secure´ => !empty($_SERVER[´HTTPS´]) && $_SERVER[´HTTPS´] !== ´off´,
´httponly´ => true,
´samesite´ => ´Lax´
]);
}
?>
<!doctype html>
<html lang="it">
<head>
<meta charset="UTF-8">
<title>Procedura guidata</title>
</head>
<body>
<h1>Configurazione guidata</h1>
<p>
Passaggio <strong><?= $currentStep ?></strong>
di <strong><?= TOTAL_STEPS ?></strong>
</p>
<?php if ($currentStep === 1): ?>
<h2>Dati personali</h2>
<p>Inserisci nome e indirizzo email.</p>
<?php elseif ($currentStep === 2): ?>
<h2>Indirizzo di spedizione</h2>
<p>Inserisci via, città e CAP.</p>
<?php else: ?>
<h2>Riepilogo</h2>
<p>Controlla le informazioni prima di confermare.</p>
<?php endif; ?>
<form method="post">
<?php if ($currentStep > 1): ?>
<button type="submit" name="action" value="previous">
Indietro
</button>
<?php endif; ?>
<?php if ($currentStep < TOTAL_STEPS): ?>
<button type="submit" name="action" value="next">
Avanti
</button>
<?php endif; ?>
<button type="submit" name="action" value="reset">
Ricomincia
</button>
</form>
</body>
</html> Spiegazione
Lettura del cookie
Il cookie viene letto tramite filter_input() e validato come intero. È preferibile non usare direttamente un valore ricevuto dal browser senza controllarlo: un utente potrebbe modificare manualmente il cookie e impostarlo, per esempio, a 999 oppure a una stringa non prevista.
La condizione che controlla l’intervallo garantisce che $currentStep resti sempre compreso tra 1 e 3. In caso contrario, il programma torna al primo passaggio.
Scrittura del cookie
La funzione setcookie() deve essere chiamata prima di produrre qualsiasi output HTML. Per questo motivo il codice PHP che aggiorna il cookie si trova all’inizio del file, prima di <!doctype html>.
L’array delle opzioni specifica:
- expires: la data di scadenza espressa come timestamp Unix;
- path: le pagine del sito che possono ricevere il cookie;
- secure: invia il cookie soltanto tramite HTTPS quando il sito usa HTTPS;
- httponly: impedisce l’accesso al cookie tramite JavaScript;
- samesite: riduce l’invio del cookie in richieste cross-site.
Eliminazione e ripristino
Per eliminare un cookie non basta assegnargli una stringa vuota. È necessario impostare una data di scadenza nel passato, mantenendo gli stessi attributi principali, soprattutto lo stesso path. Nel codice, l’azione reset riporta lo step al valore iniziale e cancella il cookie dal browser.
È importante ricordare che il cookie viene inviato dal browser nella richiesta successiva. Se lo si imposta durante una richiesta, il valore appena scritto non è automaticamente disponibile nella variabile $_COOKIE della stessa richiesta. Per questo l’esempio aggiorna direttamente $currentStep dopo aver chiamato setcookie().
Best practice
- Salvare solo dati non sensibili: uno step numerico è adatto; password, dati sanitari e informazioni finanziarie non lo sono.
- Validare sempre il contenuto: anche se il cookie è stato creato dalla propria applicazione, può essere modificato dall’utente.
- Usare HTTPS: l’opzione
secureprotegge il trasferimento del cookie sulla rete. - Limitare il percorso: se il wizard si trova, per esempio, in
/checkout, si può usarepath => ´/checkout´invece di/. - Considerare la privacy: anche un cookie tecnico deve essere classificato correttamente secondo la normativa e la configurazione del sito.
- Non fidarsi del cookie per i permessi: il numero dello step può controllare l’interfaccia, ma le autorizzazioni devono essere verificate lato server.
- Usare sessioni o database per dati complessi: il cookie dovrebbe contenere al massimo un identificatore casuale, mentre i dati reali devono rimanere sul server.
In un’applicazione reale, prima di mostrare il riepilogo finale è opportuno verificare nuovamente sul server che gli step precedenti siano stati completati correttamente. In questo modo un utente non può saltare i controlli semplicemente modificando il valore del cookie.
Riepilogo
I cookie sono utili per conservare piccole preferenze tecniche tra una visita e l’altra. Memorizzare lo step di una procedura guidata permette di migliorare l’esperienza dell’utente senza inserire dati sensibili nel browser.
La soluzione corretta prevede quattro passaggi fondamentali: leggere e validare il cookie, controllare che il valore sia entro un intervallo sicuro, aggiornarlo con una scadenza appropriata e prevedere un’azione per cancellarlo. Per informazioni importanti o dati personali, il cookie deve invece contenere soltanto un identificatore e lasciare la persistenza effettiva a sessioni o database.
