L'interazione degli utenti con i servizi forniti da un sito Web prevede spesso di utilizzare procedure basate sulla compilazione di form; i parametri utilizzati per compilare i form (spesso del testo, ma non di rado anche immagini o altri file da caricare), vengono generalmente inviati ad un'applicazione realizzata con un linguaggio lato server che ha il compito di elaborarli.
Come noto la possibilità di inviare parametri tramite form è disponibile grazie ai "metodi", come GET o POST, questi ultimi conservano le informazioni inviate sotto forma di parametri di input che continuano ad essere disponibili anche quando l'applicazione ha concluso le operazioni di elaborazione dei dati. Ne consegue che il refresh della pagina contenente l'applicazione porterà ad una nuova elaborazione dei parametri dando vita ad un fenomeno di duplicazione noto come "submit multiplo".
Se per esempio un form è destinato a popolare la tabella di un database, un submit multiplo creerà due o più record contenenti gli stessi dati; se invece il form svolge la funzione di inviare un messaggio di posta elettronica, questo verrà recapitato due o più volte. Record e email duplicati sono inutili nella maggior parte dei casi, diventa quindi necessario ricorrere a soluzioni che permettano di evitare i submit multipli; in questa breve trattazione verrà proposta una soluzione dedicata ai form basati sul metodo POST che interagiscono con applicazioni realizzate in PHP.
Prevenire i submit multipli utilizzando le sessioni
Come è noto, oltre ai comuni campi di testo e a quelli per l'upload di file, in un form HTML è possibile inserire anche dei campi nascosti, per utilizzarli basta associare l'attributo hidden
alla tipologia del campo che si desidera definire; i contenuti dei campi nascosti verranno inviati tramite metodo ed elaborati esattamente come qualsiasi altro input "in chiaro", l'unica differenza tra i due tipi di campo sta nel fatto che mentre il valore associato al primo viene generalmente definito in sede di sviluppo, il secondo è invece stabilito dall'utilizzatore del form.
Nello specifico in questa sede verrà utilizzato all'interno di un form un campo nascosto valorizzato casualmente (random) tramite la funzione nativa di PHP denominata uniqid()
, essa viene utilizzata per generare un identificatore univoco (ID) basato sul parametro microtime
, cioè il tempo corrente calcolato in millisecondi.
Questo valore verrà associato ad una sessione che in seguito sarà utilizzata per il controllo dell'invio dei dati; si crei per esempio un file, denominato id.php
contenente il seguente codice:
<?php # inizializzazione della sessione @session_start(); # creazione del valore univoco $id = uniqid(); # associziaone del valore univoco ad una sessione $_SESSION['id'] = $id; ?>
Il funzionamento dello script appena presentato è abbastanza semplice, esso si occupa di inizializzare una sessione e di creare un valore per la chiave $_SESSION['id'] che entrerà a far parte dell'array globale $_SESSION
dell'ambiente di PHP.
A questo punto, il prossimo passaggio sarà quello di creare un form per l'invio dei dati; dato che quest'ultimo conterrà anche un campo nascosto valorizzato da id.php
, esso dovrà essere incluso all'inizio della pagina. Lo vedremo nella pagina successiva
<?php
# inclusione del file di sessione
@include 'id.php';
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="it" lang="it">
<head>
<title>Nome form</title>
</head>
<body>
<form action="ricevi.php" method="POST">
<dl>
<dt>Come ti chiami?</dt>
<dd>
<input type="hidden" name="id" value="<?php echo $id; ?>" />
<input type="text" name="nome" />
</dd>
</dl>
<p><input type="submit" value="Invia" /></p>
</form>
</body>
</html>
Si tratta di un form il cui compito sarà quello di inviare i parametri di input ad una pagina, ricevi.php, contenente l'applicazione per l'elaborazione dei dati; chiaramente il file destinato a processare le informazioni spedite tramite modulo potrebbe assolvere svariate funzioni come creare un record, inviare un messaggio, consentire l'accesso ad un'area protetta; per semplicità in questo caso l'applicazione si limiterà a stampare a video il dato elaborato.
Processare gli input con PHP
Una volta salvato il codice contenente il form HTML in un file, chiamato per esempio "invia.php", sarà possibile dedicarsi allo sviluppo della pagina destinata a raccogliere ed elaborare gli input inviati; a questo scopo, si analizzi il codice seguente:
<?php # inizializzazione della sessione @session_start(); # controllo sugli input if(!isset($_POST['nome'], $_POST['id'], $_SESSION['id'])) { echo 'Errore nei dati inviati'; } # confronto tra campo nascosto e sessione elseif($_POST['id'] != $_SESSION['id']) { echo 'Impossibile eseguire l'operazione'; }else{ # filtro sui dati di input $nome = @filter_var($_POST['nome'], FILTER_SANITIZE_STRING); # restituzione dell'output echo $nome; # distruzione della sessione unset($_SESSION['id']); } ?>
L'applicazione svolge in particolare il compito di confrontare il valore di sessione con quello del campo nascosto, questi devono essere identici altrimenti il resto del codice non potrà essere eseguito; dato che la sessione contenente il valore casuale verrà distrutta già dopo la prima esecuzione dello script, i dati inviati tramite POST non potranno essere processati una seconda volta, evitando la duplicazione dell'invio dovuta ad un eventuale refresh della pagina.
Conclusioni
In questa trattazione è stata analizzata una possibile soluzione contro i submit multipli da form basata sulla creazione di una sessione valorizzata tramite uniqid(); sono possibili eventuali implementazioni del codice o procedure alternative come quelle basate sull'utilizzo di funzioni come md5() al posto di uniqid() per ottenere stringhe casuali ancora più complesse.