Lezione Precedente Elenco Lezioni Lezione Successiva

Laboratorio di Sistemi Informativi

Validazione dati

Veniamo ad una problematica tipica delle applicazioni sulle basi di dati: la validazione dei dati inseriti. Si tratta di fare in modo che le operazioni richieste dall'utente non violino i vincoli di integrità imposti sulla base di dati. Ad esempio, nel caso della procedura di inserimento di nuovi oggetti, sarebbe preferibile che il sistema si rifiutasse di inserire un oggetto con il nome o la descrizione vuota. Analogamente, non dovrebbe essere possibile inserire nel campo categoria_id di un oggetto un valore inesistente (si tratta di un vincolo di integrità referenziale). Notare che, per quanto riguarda l'ultimo punto, visto che all'utente viene presentata la scelta tra le sole categorie esistenti, sembra impossibile che il problema si verifichi: vedremo che così non è.

Ci sono tre possibili ambienti in cui effettuare la validazione dei dati in una architettura a tre livelli:
  1. nel server database
  2. nel server applicativo (il server web nel nostro caso)
  3. nel client (il browser)
La validazione all'interno del browser fa sì che i dati non vengano neanche spediti al server web. Ad esempio, se l'utente immette una stringa dove il sistema si aspetta un numero, è possibile far sì che il browser si accorga di questo fatto e richieda all'utente di reimmettere i dati. La validazione lato client richiede l'utilizzo del linguaggio Javascript. Notare che la validazione lato client non è sicura!! L'utente può sempre disattivare Javascript e quindi aggirare (volontariamente o no) i controlli.

Quando la validazione dati è eseguita sul server web, il programma che gestisce l'applicazione (i vari script PHP nel nostro caso) effettuano dei controlli prima di effetturare eventuali modifiche nella base di dati. La modifica viene effettuata solo se il controllo ha successo, altrimenti si visualizza un appropriato messaggio di errore.

Infine, si può relegare tutto al DBMS: questi può controllare la validità dei vincoli di chiavi esterna, o anche vincoli più complessi qualora questi siano supportati.  Tuttavia, un approccio di questo tipo è poco efficiente (i dati devono viaggiare dal client fino al server DBMS anche quando errati). Inoltre, è necessario comunque che l'errore venga successivamente mostrato all'utente, per cui lo script PHP deve accorgersi che si è verificato un errore nell'esecuzione di un comando SQL, capire a cosa è dovuto questo errore, e visualizzare il messaggio appropriato. Se a ciò aggiungiamo che MySQL offre solo un supporto limitato al trattamento dei vincoli di integrità, si capisce che questo è un approccio che è meglio lasciar perdere.

Modelli di validazione

Decidere come visualizzare i messaggi di errori dovuti alla presenza di dati sbagliati è un problema difficile. Se questo aspetto dell'applicazione viene pensato male, l'utente può trovarsi infastidito da continui messaggi di errori, difficili da eliminare, magari anche inaccurati o poco informativi. Non c'è niente di peggio che avere un messaggio che dice che si è verificato un errore ma non spiega in che campo di input c'è il problema.

La validazione è in realtà un processo composto da due fasi: individuazione degli errori e presentazione degli errori all'utente.  L'individuazione degli errori può essere:
La validazione interattiva era praticabile solo lato client. Se si voleva realizzare lato server, richiedeva l'invio di dati al server web e il successivo ricarimento della pagina ogni volta che l'utente modificava il valore di campo di una form, causando una perdita di tempo inaccettabile. Negli ultimi anni, con l'evoluzione della tecnologia nota come AJAX (Asynchronous JavaScript and XML), comincia a essere possibile realizzare una validazione interattiva anche lato server, senza eccessiva degradazione delle prestazioni.

Per quanto riguarda la presentazione degli errori, questa può avvenire in due modi:
Come per il caso precedente, quando la validazione è lato server la presentazione batch degli errori è preferibile, perché più efficiente. Visualizzare gli errori uno alla volta, chiedere di correggerli, e passare poi all'errore successivo richiede continui passaggi di dati tra browser e server web.

In generale la soluzione migliore è avere una validazione batch a posteriori sul lato server assieme ad una validazione lato client (che può essere di qualunque tipo si desideri). Perché raddoppiare le validazioni?
  1. la validazione lato server è essenziale perchè non può essere aggirata dall'utente. In questo modo ci si assicura veramente che i dati inseriti rispettino tutti i vincoli richiesti.
  2. la validazione lato client è però più efficiente, e inoltre può essere sia eseguita a posteriori che interattiva, adattandosi quindi meglio al tipo di applicazione. Dunque, essa è opzionale ma altamente desiderabile.

ATTENZIONE! Purtroppo mentre PHP è indipendente dal browser che sta usando l'utente, lo stesso non vale per Javascript. Ne segue che, quando si adotta la validazione lato client, occorre controllare su vari tipi di browser che la validazione funzioni bene, visto che non tutto si comporta esattamente allo stesso modo con browser diversi.

Validazione batch della pagina di inserimento

Una prima soluzione al problema può essere data dallo script inserimento-validate.php. Questo controlla che il nome e la descrizione dell'oggetto non siano vuoti. Qualora ciò non accada, invece di inserire l'oggetto viene visualizzata una pagina di errore.

È possibile tuttavia visualizzare gli errori in maniera più accattivante. Ad esempio, possiamo modificare lo script in modo che, in caso di errore, venga rivisualizzata la pagina di inserimento dati, con in più l'elenco dei problemi che si sono verificati e con i campi di input già pre-riempiti. Si ottiene inserimento-validate2.php.

In questo script abbiamo fatto uso delle variabili di sessione $_SESSION['postdata'] e $_SESSION['errors'] per passare i valori immessi dall'utente e gli errori che si sono generati dalla fase di controllo dati/inserimento alla fase di richiesta dati/visualizzazione errori. Le variabili vengono controllate nella FORM di immissione dati e, se presenti, causano il preriempimento dei campi di input e la visualizzazione dei messaggi di errore. Una volta che queste variabili di sessione non servono più, ovvero alla fine dello script con la FORM, è necessario eliminarle, e lo abbiamo fatto usando la seguente funzione:

Come alternativa a unset si potrebbe pensare di utilizzare session_destroy, che però distrugge tutte le variabili di sessione, compresa quella che ci indica se abbiamo o no fatto il login: almeno nel nostro caso, questa soluzione non è applicabile.

Altra caratteristica di inserimento-validate2.php è l'uso dell'operatore @. Si tratta di un operatore unario che ha come effetto quello di inbire la generazione dei messaggi di errore che si verificherebbero altrimenti. Ad esempio: $x=1/0 genera l'errore di divisione per zero, mentre $x=@(1/0) non genera alcun errore. Noi la utilizziamo per preriempire i campi di input con il valore immesso precedentemente. Come abbiamo detto, questi valori si trovano in $_SESSION['postdata'], per cui, per visualizzare il campo nome opportunamente riempito, si dovrebbe usare:

<input name="nome" type="text" value="<?php echo $_SESSION['postdata']['nome']?>">

Quando però lo script della FORM viene eseguito perché è stato premuto il pulsante "Inserisci oggetto" dal menù, la variabile di sessione $_SESSION['postdata'] non è definita, e la riga di sopra genererebbe un errore. A questo si può sopperire chiamando prima isset() per vedere se $_SESSION['postdata'] esiste, come in:

<input name="nome" type="text" value="<?php if (isset($_SESSION['postdata']['nome'])) echo $_SESSION['postdata']['nome']?>">

o più semplicmente con:

<input name="nome" type="text" value="<?php @echo $_SESSION['postdata']['nome']?>">

ATTENZIONE! Cosa dire del vincolo di integrità che lega gli oggetti alle categorie? Il nostro software non controlla che la categoria che viene passata allo script di inserimento sia veramente presente nel database. Il controllo sembrerebbe inutile, visto che allo script di inserimento si accede tramite una form che consente di scegliere solo categorie veramente esistenti. Tuttavia, questo è vero solo se l'obiettivo è quello di impedire che l'utente "buono" non sbagli, ma non impedisce assolutamente che l'utente "cattivo" violi i vincoli di integrità della nostra base di dati. Vedremo i dettagli nella lezione sulla sicurezza.

Validazione interattiva della pagina di inserimento voli

Visto che non è scopo del corso insegnare il JavaScript, mostriamo solo un esempio di come è possibile implementare un controllo interattivo lato client: inserimento-validate-js.php.

Esercizi e Soluzioni

Esercizio 1

Modificare inserimento-validate2 in modo tale che, quando si verifica un errore, l'etichetta dei campi di input che sono stati riempiti con i dati sbagliati vengano visualizzati in corsivo. A questo proposito, è possibile usare il tag <em>.

Lezione Precedente Elenco Lezioni Lezione Successiva

Valid HTML 4.01 Transitional Valid CSS!