Home / Indice sezione
 www.icosaedro.it 

 FORM dell'HTML

Ultimo aggiornamento: 2008-01-10

Riepiloghiamo gli strumenti di input dei dati offerti dai FORM dell'HTML e diamo le regole di interfaccia per rendere consistenti le pagine WEB. Consideriamo anche gli aspetti della acquisizione e della validazione dei dati, e le loro implicazioni per la sicurezza del sistema. Non faremo riferimento a nessun sistema specifico di programmazione, e pertanto questa discussione è del tutto generale. Le funzionalità di un FORM si possono estendere tramite i linguaggi di programmazione lato client (JavaScript e Java), ma qui prenderemo in esame solo il puro HTML in combinazione con la programmazione lato server.

Storico degli aggiornamenti

2006-05-22 Aggiunta discussione sui combobox, i FORM multipli e i FORM annidati.
2005-07-06 Prima stesura dell'articolo.

Indice

Regole di interfaccia
Charset ed encoding
Il tag FORM dell'HTML
Aspetto generale di un form di input
Acquisizione e validazione dei dati
Attributi dei control
Input di una linea di testo
Input di testo multilinea
Dati nascosti
Check box
Radio button
Lista a scelta singola
Lista a scelta multipla
Liste con numero arbitrario di elementi
Upload di file
Pulsanti
FORM multipli e FORM annidati
Cose che qui abbiamo omesso di trattare
Riferimenti
Argomenti correlati

Regole di interfaccia

Immaginiamo di salire su di una automobile, una qualunque. Ci aspettiamo di trovare un volante rotondo, la leva del cambio a destra e tre pedali. Ciò è confortante e ci permette in pochi attimi di prendere il controllo del mezzo con sicurezza. Immaginiamo invece che i produttori di automobili, in preda a turbamenti creativi, decidano di cambiare un po' tutto. Salendo su di un modello potremmo trovare una leva centrale, una sorta di joystick che permette di sterzare, accelerare e frenare, e poi dei pulsanti per cambiare marcia. Un altro produttore decide invece di farci trovare una soluzione più convenzionale, ma con il volante quadrato e i pedali sostituiti da pulsanti sulle razze. Un altro ancora opta per una soluzione avveniristica: nessun comando sul cruscotto e la vettura si controlla attraverso i movimenti impercettibili del corpo del guidatore registrati dal sedile sul quale siede: spostando il corpo in avanti si accelera, spostandolo indietro si frena, e ruotando il corpo a destra e a sinistra si sterza. Sarebbe questo un "progresso"? Sarebbe desiderabile? Io credo proprio di no. Il fatto è che tutti noi ormai concepiamo l'automobile come uno strumento di utilità, e perciò ci aspettiamo che essa si comporti in modo prevedibile e risponda a dei comandi convenzionali, ci aspettiamo che l'interfaccia tra noi e la macchina sia costruita rispettando precise regole non scritte ma largamente condivise. Il controesempio sono gli altri controlli presenti sul cruscotto necessari per regolare il condizionatore, il riscaldamento e altri ammennicoli: di solito si tratta di una selva di leve, pulsanti e pomelli che il guidatore e il passeggero devono seviziare nervosamente per ottenere l'effetto voluto. Nel caso di questi controlli nessuna convenzione è stata raggiunta tra i produttori, e gli utenti ne subiscono le conseguenze, magari ritrovandosi in mano il pomello divelto dal cruscotto che andava ruotato e non tirato.

Possiamo fare un discorso analogo per le interfacce grafiche utente dei computer, o in breve GUI (graphical user interface). Sono passati ormai oltre venti anni da quando la Apple col suo primo Macintosh introdusse il paradigma delle moderne GUI. Da allora poco è cambiato, e ancora oggi gli strumenti di interazione tra l'uomo e i programmi sono ancora pulsanti, campi di input di testo, pulsanti radio (radio buttons), caselle di spunta (check boxes) e menu a tendina. Tuttavia questi elementi, che nel complesso chiameremo control, non si possono usare a casaccio, ma si devono rispettare alcune convenzioni ben precise per quanto riguarda il loro aspetto e la loro distribuzione all'interno di una maschera, esattamente come per i pedali, le leve e i pulsanti dell'automobile. Nel seguito non ci limiteremo a descrivere solo gli aspetti strettamente tecnici dei FORM HTML, ma cercheremo di esplicitare anche alcuni principi guida per ottenere una GUI ordinata, consistente e facile da usare.

Charset ed encoding

Il termine charset indica un insieme di caratteri usati per rappresentare un testo. Ad esempio, il charset ASCII (o anche US-ASCII) codifica i 128 caratteri dell'ASCII. La tabella completa del charset ASCII la puoi consultare in /articoli/protocolli1.html.

La serie ISO-8859 rappresenta insiemi di 256 caratteri. In particolare, l'ISO-8859-1 è noto come "Latin 1" e rappresenta tutti i caratteri ASCII e gli altri caratteri usati in occidente, incluse le vocali accentate della lingua italiana. Recentemente il charset ISO-8859-1 è stato aggiornato per includere anche il simbolo dell'Euro, ed è diventato l'ISO-8859-15. Le tabelle della serie ISO-8859 le puoi consultare in http://czyborra.com/charsets/iso8859.html.

Il charset Unicode rappresenta oltre 60000 caratteri, cioè praticamente tutti quelli correntemente in uso al mondo. Anche qui, i primi 128 simboli coincidono con l'US-ASCII, che è quindi un sottoinsieme di tutti i charset. Altre informazioni sul charset Unicode le puoi consultare in http://czyborra.com/unicode/standard.html.

Il termine encoding indica il particolare formato usato per rappresentare ciascun carattere. Ad esempio, l'US-ASCII usa la codifica a 8 bit per carattere con l'ottavo bit sempre zero, quindi di fatto usa 7 bit. La serie ISO-8859 usa esattamente 8 bit per ogni carattere e quindi ogni carattere viene codificato in un byte. Per il charset Unicode, invece, esistono diverse soluzioni, ma quella di gran lunga più usata è l'UTF-8.

Per quanto riguarda il protocollo HTTP e le pagine WEB, è fondamentale specificare il charset e l'encoding di ogni pagina, altrimenti il browser non saprebbe come interpretare la sequenza di byte che compongono la pagina ricevuta dal server. A questo scopo la risposta del server deve contenere una riga di intestazione che specifica il tipo MIME dei dati inviati (nel nostro caso "text/html") il charset e l'encoding:

Content-Type: text/html; charset=UTF-8

Notare che il parametro "charset" rappresenta sia il charset che l'encoding, siccome "UTF-8" oppure "ISO-8859-15" includono entrambe le informazioni necessarie. Per brevità nel seguito, perciò, useremo il termine "charset" per indicare sia il charset vero e proprio, sia la codifica.

Per quello che riguarda il nostro discorso dei FORM HTML, i dati inseriti dall'utente possono essere restituiti al server in due modi diversi:

Fortunatamente i browser oggi disponibili hanno scelto tutti la prima soluzione, così semplificando il lavoro del server.

Bisogna però tenere conto di un problema. Come raccomandazione generale del W3C, i browser dovrebbero lavorare internamente usando Unicode per la massima generalità. Quando l'utente compila il FORM e lo invia al server, il browser deve convertire le stringhe Unicode nel charset richiesto dalla pagina. Talvolta questo non è possibile e quando il browser si trova di fronte a un carattere Unicode che non ha una rappresentazione nel charset della pagina, sorge il problema. Le soluzioni che il browser potrebbe adottare sono:

  1. Avvisare l'utente del problema e proporre una soluzione alternativa. Pedante.
  2. Scartare il carattere. Soluzione pericolosa perché è difficile accorgersi di quello che è avvenuto.
  3. Sostituire il carattere con una sequenza come "&#xxx;" dove "xxx" è il codice decimale Unicode del carattere. Ad esempio, se la pagina WEB utilizza l'US-ASCII e l'utente batte il carattere "è", il browser invierà per questo carattere la sequenza "è". Fastidioso, ma almeno si può riconoscere il problema. Purtroppo il carattere "&" stesso non viene codificato, sicché lato server non è possibile stabilire se questo carattere marca un codice Unicode oppure fa parte della stringa. Comunque questa è la soluzione adottata dai browser correnti.

La soluzione a tutti questi problemi è utilizzare UTF-8. Questo charset è quello che si va imponendo e probabilmente l'unico che verrà usato nel prossimo futuro di Internet.

Il tag FORM dell'HTML

Ci sono alcuni aspetti subdoli del tag FORM che qui esaminiamo. Nella sua forma più semplice è sufficiente l'attributo action, ma ci sono altri attributi da considerare.

<form method=post action="/il/programma"
    enctype="multipart/form-data">
    ...
</form>

L'attributo method specifica che il browser deve usare il metodo POST del protocollo HTTP piuttosto che il metodo GET. Il metodo POST è quello più generale e consigliato.

L'attributo action specifica l'URL del programma che deve acquisire i dati del FORM.

L'attributo enctype specifica che il metodo POST deve inviare i valori dei singoli control utilizzando la codifica "multipart/form-data" più evoluta rispetto alla codifica "application/x-www-form-urlencoded" che verrebbe usata altrimenti.

L'attributo accept-charset permette di specificare l'elenco dei charset che il programma riconosce. In questo documento non useremo tale possibilità, e il browser invierà i dati usando lo stesso charset della pagina che contiene il FORM.

L'attributo accept permette di specificare i tipi MIME dei file accettabili quando il FORM prevede anche l'invio di file. Non useremo questa caratteristica in questo documento. Per un esempio di FORM che fa uso di questo attributo, vedi l'articolo PHP File Upload (www.icosaedro.it/articoli/php-file-upload.html).

Tutti i control che andremo a considerare nel seguito devono essere sempre inclusi dentro al tag FORM.

Aspetto generale di un form di input

Tutti abbiamo dovuto litigare con un famigerato form di input per registrarci in un sito ed ottenere l'accesso ai servizi desiderati. Abbiamo anche sperimentato la frustrazione di dovere ripetere più volte l'immissione dei dati a causa di ambiguità e di errori misteriosi. L'errore tipico è inviare dati (azione di submit) dopo avere accidentalmente cliccato su di un insospettabile control dal significato oscuro. Da queste esperienze nascono i primi due principi:

Principio delle due fasi dell'input. Esistono due momenti ben distinti della immissione dei dati: la scrittura dei dati stessi da parte dell'utente, e l'invio dei dati al computer. Tra le due fasi l'utente deve poter controllare ed eventualmente correggere i dati inseriti.
Principio della consistenza dell'aspetto dei control. Tutti i control devono avere un aspetto coerente e devono essere immediatamente riconoscibili sia nell'ambito dello stesso programma che nell'ambito del sistema operativo utilizzato. Ad esempio, se la norma sono i pulsanti rettangolari grigi con le scritte nere, allora tutti i pulsanti devono avere queste caratteristiche.

Probabilmente i pulsanti esagonali roteanti farebbero la loro bella figura in un videogioco, ma non sono giustificati in nessuna altra applicazione. Inoltre ci aspettiamo che un pulsante sia la rappresentazione grafica di un pulsante della realtà, e che pertanto abbia dimensioni ragionevoli: pulsanti larghi come tutto lo schermo o che contengono una frase intera diventano semplicemente delle grandi aree grigie difficilmente riconoscibili per quello che realmente sono.

 

Esempio errato: pulsanti sovradimensionati.

 

Nel mondo occidentale leggiamo partendo dall'alto verso il basso, e da sinistra verso destra. Lo stesso ordine dovrebbe venire rispettato quando si posizionano i control in un FORM. I pulsanti di submit, che inviano i dati del FORM al server, devono apparire per ultimi perché sono l'ultima cosa che l'utente deve azionare. Abbiamo perciò il seguente:

Principio dell'ordine di lettura. I control devono essere distribuiti all'interno del FORM nell'ordine di lettura e di azionamento naturale. I pulsanti, che causano il submit dei dati, devono perciò apparire per ultimi.

Talvolta distribuire i control secondo un rigido criterio di ordine logico comporta uno sfruttamento non ottimale della superficie dello schermo, con comparsa della barra di scorrimento verticale. Alcuni programmatori pensano che questo sia un difetto da evitare a tutti i costi, e per ovviare a questo presunto inconveniente si cimentano in laboriose opere di cesellatura. Tre osservazioni. 1. Qualunque opera di cesellatura abbiamo fatto, l'utente avrà un monitor o una finestra di dimensioni completamente diverse dalla nostra. 2. L'utente è ipovedente e usa l'ingrandimento 200%. Oppure l'utente è ipervedente e usa il 50%. 3. Spesso ne risulta una pagina WEB non ridimensionabile, o difficilmente ridimensionabile, con risultati disastrosi in visualizzazione e stampa. Ne valeva la pena?

Acquisizione e validazione dei dati

Quando l'utente invia i dati al server, il server deve riconoscere questi dati e tradurli in una rappresentazione interna consistente. Conviene distinguere due aspetti di questo procedimento: l'acquisizione e la validazione.

Per acquisizione si intende il meccanismo che permette al programma lato server di leggere i valori ricevuti dal browser. Il meccanismo specifico dipende dal sistema di programmazione usato. I tipi di dato coinvolti sono le stringhe di caratteri, i numeri, i flag logici e gli array di questi elementi. Comunque sia relizzata l'acquisizione, essa deve permettere al programma di ripresentare il form all'utente in modo che il form appaia esattamente come era stato compilato, senza modifiche o artefatti.

Questo è utile per gestire il ciclo acquisizione/validazione/errore illustato nella figura qui sotto: se i dati non sono validi, il programma deve descrivere in modo accurato l'errore e deve lasciare all'utente tutto il tempo per prendere visione del problema (magari l'utente dovrà consultare la documentazione del programma, oppure chiederà aiuto ad un collega, oppure farà una copia del messaggio di errore per riferimento futuro, ecc.). Fatto questo, il programma deve riproporre il form non valido mostrandolo esattamente così come era stato introdotto, errori inclusi.



Il ciclo di presentazione, acquisizione e validazione dei dati immessi attraverso un FORM. Il FORM può essere inizialmente vuoto, oppure può contenere dei dati default. Se la validazione fallisce viene presentata una descrizione del problema rilevato e quindi il FORM viene ripresentato all'utente con i dati che aveva immesso, giusti o sbagliati che fossero.


L'acquisizione è utile anche per gestire l'inserimento di dati scomposto su diverse maschere distinte quando la validazione non è opportuna o non è possibile fintanto che l'insieme dei dati non è stato completamente compilato.

La validazione è il processo di calcolo che permette di stabilire se i dati acquisiti sono validi oppure no. "Validi" significa che possono essere regolarmente elaborati e non producono inconsistenze sul sistema. Se i dati sono validi allora vanno accettati dal programma senza altri ritardi. Se sono sbagliati allora vanno respinti con motivazione. Non esistono situazioni intermedie.

Il programma non deve mai tentare di correggere i dati perché qualsiasi tentativo automatizzato in tal senso potrebbe portare a travisare le intenzioni dell'utente e l'utente, nella fretta di completare l'input, potrebbe non accorgersi delle alterazioni apportate dal programma. Ad esempio, se è richiesta la data di scadenza di un contratto e l'utente lascia in bianco il campo "data di scadenza", il programma non deve compilare il campo con la data "oggi più un anno" ma deve lasciare all'utente il compito di indicare l'effettiva data di scadenza come risulta dal contratto che solo l'operatore che sta eseguendo l'inserimento può conoscere.

Il programma può invece suggerire manovre correttive, ma con discrezione e lasciando spazio all'utente di correggere in modo consapevole. Se un importo monetario inserito deve essere arrotondato all'unità di Euro e invece l'utente introduce anche i centesimi, il programma non deve arrotondare il valore inserito, ma deve segnalare il problema all'utente e poi deve consentirgli di eseguire l'arrotondamento secondo il criterio che lui decide di applicare. La maschera di errore potrebbe suggerire l'importo arrotondato secondo lo schema di arrotondamento predisposto dal programma, o magari potrebbe anche suggerire diversi arrotondamenti scelti tra tra gli schemi in uso in ambito contabile.

Tutti i dati che il server riceve dal client possono essere contraffatti, mancanti del tutto o contenere valori imprevisti inseriti dall'utente. Stabilito che l'applicazione WEB deve validare accuratamente le richieste provenienti dal browser, come reagire quando si rilevano inconsistenze abnormi probabilmente frutto di qualche tentativo malevolo?

Principio della sfiducia. Non possiamo rivestire alcuna fiducia nei dati restituiti dal browser. Un dato può mancare, oppure può essere arbitrariamente lungo, o contenere sequenze illegali di caratteri.

Per ogni dato occorre quindi un algoritmo di validazione in grado di stabilire se esso è valido. E' possibile, ed anzi relativamente facile, inviare al server dati del tutto arbitrari. Sta nella logica del programma evitare che queste situazioni possano compromettere il sistema o la base dati. Vedremo per ogni control quali accorgimenti specifici bisogna adottare.

Ecco alcuni suggerimenti guida per il programmatore:

Esistono linguaggi di programmazione lato client (JavaScript e Java) con i quali si possono estendere le funzionalità dell'interfaccia WEB. In particolare, questi strumenti permettono di eseguire la validazione dei dati lato client velocizzando l'interazione con l'utente e riducendo il traffico in rete. Tuttavia la validazione dei dati lato client non può mai sostituire la validazione lato server che deve comunque essere presente e costituisce l'unico vero filtro contro gli accessi malevoli.

Inoltre la validazione lato client richiede di scrivere due volte il codice di validazione: una volta lato server e una volta lato client. I due algoritmi devono rimanere sincronizzati al cambiare delle specifiche del programma. Conviene evitare del tutto la validazione lato client, almeno nella fase di prototipazione del programma. La validazione lato client la si può rimandare a una fase successiva dello sviluppo del programma, quando le specifiche saranno mature e stabili e quando lo si riterrà opportuno per ragioni di efficienza della interazione con l'utente.

Attributi dei control

Molti tag dell'HTML hanno dei parametri che si chiamano attributi. Gli attributi hanno la forma generale nome=valore dove il nome identifica l'attributo e il valore è una stringa di caratteri. Alcuni attributi non hanno un valore perché si comportano come flag, cioè hanno effetto solo quando sono presenti. Il valore di un attributo è una stringa generica codificata nel charset usato per la pagina. Tuttavia sono richiesti alcuni accorgimenti affinché il contenuto della stringa non si confonda coi tag HTML. Ricordiamo in breve i tre modi possibili per codificare questa stringa (v. www.w3.org/TR/html401/intro/sgmltut.html par. 3.2.2):

La prima e la seconda soluzione sono quelle che si prestano meglio ad essere automatizzate in una funzione di conversione che prende una stringa generica e la trasforma nel valore dell'attributo. La terza soluzione viene usata più spesso quando si scrive il codice HTML a mano oppure quando, in base alla logica del programma, è certo che la stringhe siano già valide, per esempio quando sono dei numeri.

L'attributo name è il nome del control. Esso viene restituito al server al momento del submit insieme al valore del control. Ad esempio, se viene premuto il pulsante

 
 
<input type=submit name=b1 value="Salva">
 

il server riceverà la coppia "b1=Salva".

L'attributo value è il valore del control e può avere significati leggermente diversi a seconda del control specifico.

Fatte queste premesse possiamo passare in rassegna i vari tipi di control offerti dai FORM HTML.

Input di una linea di testo

E' uno dei control più usati: esso permette l'input di una riga di testo:

 
 
<input type=text name=TITOLO value="Via col vento"
size=20 maxlength=30>
 

L'attributo name è il nome sotto il quale verrà restituito il valore del control al momento del submit. Nel nostro esempio tale nome sarà "TITOLO".

L'attributo value è il testo iniziale del control. Se questo attributo viene omesso, il control appare inizialmente vuoto.

L'attributo size è la larghezza desiderata del control in unità piuttosto arbitrarie equivalenti a circa un carattere. Se omesso, il browser sceglie una dimensione default che ritiene appropriata.

L'attributo maxlength è la lunghezza massima della riga. Il browser rifiuta l'inserimento di un numero di caratteri superiore a quello specificato. Se questo attributo viene omesso, non c'è limite alla lunghezza della riga che l'utente può inserire.

Acquisizione e validazione. Di norma all'atto del submit del FORM il browser restituisce il valore corrente del control rispettando il charset della pagina WEB e la lunghezza massima specificata nell'attributo maxlength. Notare però che non c'è garanzia che tutto ciò avvenga realmente in questo modo. Un browser impazzito, o un utente malizioso possono forzare l'invio di dati arbitrari. Lato server dovremo quindi sempre verificare che il dato sia effettivamente presente, che il charset corrisponda e che la lunghezza massima non sia maggiore di quella attesa. In caso di non conformità potremmo eliminare silentemente i codici non validi. Se è stato specificato l'attributo maxlength potremo troncare silentemente la stringa alla lunghezza massima prevista.

Il testo non dovrebbe mai includere codici di controllo. Pertanto dovremo controllare l'esistenza di codici ASCII compresi tra 0 e 31 oltre al codice 127, e prendere i provvedimenti del caso. Eliminare silentemente questi codici potrebbe essere una soluzione adatta nella maggior parte dei casi. Questa operazione dovrebbe essere fatta prima di ogni altra operazione di sanificazione.

Notare inoltre che gli spazi eventualmente lasciati dall'utente in testa o in coda al testo inserito vengono anch'essi ritornati, e talvolta è necessario rimuoverli esplicitamente, a seconda della logica del programma prevista per questo dato.

Input di testo multilinea

Questo control permette di inserire un testo più articolato che si estende su più righe. Il testo ha una lunghezza arbitraria, sicché il browser tipicamente visualizza una barra di scorrimento verticale quando il numero di righe eccede l'altezza del control. Inoltre, il browser visualizza anche una barra di scorrimento orizzontale quando una riga del testo eccede la larghezza del control e non contiene caratteri di spazio che consentano di portare a-capo la parte eccedente. L'utente deve premere il tasto RETURN quando vuole aprire una nuova riga. Le righe lunghe spezzate dal browser in corrispondenza degli spazi per farle stare dentro al control, vengono poi restituite intere al momento del submit.

 
 
<textarea name=Articolo cols=50 rows=4>
Questo &egrave; un testo.
Ecco un'altra riga.</textarea>
 

L'attributo name è il nome sotto il quale verrà restituito il valore del control al momento del submit.

Gli attributi cols e rows specificano la larghezza e l'altezza del control. Se omessi, il browser utilizza valori default che ritiene appropriati.

Il valore iniziale del control deve essere specificato come normale testo HTML prima del tag di chiusura </textarea>. Ricordare che se questo testo viene generato dinamicamente dal programma allora bisogna convertire il carattere "<" nel simbolo "&lt;" e il carattere "&" nel simbolo "&amp;".


Attenzione!I browser che ho provato (Mozilla 1.7.3 e Internet Explorer 6.0) ignorano la prima riga vuota del testo compreso tra i tag <textarea> e </textarea>. Questo ha un curioso effetto collaterale. Ad esempio, se l'utente inserisce nella text area una riga vuota e poi un testo, e successivamente il programma ripropone questo testo nella text area, la prima riga vuota risulta "sparita". Per assicurare un comportamento coerente, bisogna quindi aggiungere un a-capo subito dopo il tag di apertura. Quindi scriveremo
<textarea name=xxxx>
qui il valore iniziale del testo</textarea>
Notare che subito dopo il tag di apertura il programma deve mettere un a-capo.

Un errore molto comune che commettono gli utenti nel compilare questo control è quello di premere il tasto RETURN quando vedono il cursore avvicinarsi al margine destro dell'area del control, così producendo dei testi che includono un numero indesiderato di righe. Per prevenire questo malinteso è bene che la larghezza del control sia resa generosamente grande.

Notare che non esiste modo di specificare la lunghezza massima del testo da immettere.

Di norma ogni a-capo inserito dall'utente viene convertito nella sequenza dei caratteri di controllo carriage return (codice ASCII 13) e dal carattere line feed (codice ASCII 10), in questo ordine.

Acquisizione e validazione. Di norma all'atto del submit del FORM il browser restituisce il valore corrente del control rispettando il charset della pagina WEB. Notare però che non c'è garanzia che ciò avvenga realmente in questo modo. Un browser impazzito, o un utente malizioso possono forzare l'invio di dati arbitrari. Lato server dovremo quindi sempre verificare che il dato sia effettivamente presente e che il charset corrisponda.

Le varie righe sono separate dai codici carriage return e line feed. Se il nostro sistema lo richiede, sarà necessario convertire queste sequenze. Come al solito, non c'è garanzia che le linee siano separate utilizzando questa sequenza, per cui dovremo anche qui fare un controllo.

Il codice di controllo HT (horizontal tabulation, codice ASCII 9) permette di incolonnare dati o di indentare linee di testo. Di norma i campi di tabulazione sono larghi 8 caratteri, e ogni HT fa passare all'inizio del campo di tabulazione seguente. Di norma un utente non può inserire il carattere HT in una <TEXTAREA>, perché premendo il tasto TAB il browser sposta l'input focus sul control seguente del <FORM>. Tuttavia tale codice potrebbe essere inserito quando si fa il copia-e-incolla da un file di testo. Occorre decidere come trattare questo codice. Ci sono due possibilità:

Per quanto riguarda la ripresentazione del testo inserito, bisogna ricordare che in un testo HTML normale gli spazi multipli e il codice HT vengono collassati sempre in un solo spazio. L'unico modo di rendere correttamente queste spaziature è di mostrare il testo in una <TEXTAREA> oppure in un brano di testo preformattato <PRE>...</PRE>. In quest'ultimo caso bisogna anche ricordare di spezzare le linee lunghe a una lunghezza ragionevole, altrimenti nel caso di paragrafi molto lunghi il browser mostra una barra di scorrimento orizzontale, e in stampa il testo viene troncato.

In generale è bene porre molta cura nel preservare i caratteri di spaziatura multipli e il carattere HT perché vengono spesso utilizzati dagli utenti come semplice strumento per formattare il testo, comporre tabelle, incolonnare elenchi, disegnare "ASCII-art" e riprodurre sorgenti strutturati di programmi. Alterare queste formattazioni significa spesso stravolgere il significato del testo, con grave frustrazione dell'utente che vi aveva posto tanta cura.

A parte i codici carriage return, line feed e HT, il testo non dovrebbe mai includere altri codici di controllo. Pertanto dovremo controllare l'esistenza di codici ASCII compresi tra 0 e 31 oltre al codice 127, e prendere i provvedimenti del caso. Eliminare silentemente questi codici potrebbe essere una soluzione adatta nella maggior parte dei casi. Questa operazione dovrebbe essere fatta prima di ogni altra operazione di sanificazione.

Se il programma prevede una lunghezza massima per il testo, allora dovremo controllare che il testo immesso rispetti questo limite e, nel caso lo superi, dovremo informare l'utente e dargli la possibilità di intervenire.

Notare che gli spazi e le righe vuote eventualmente lasciati dall'utente in testa o in coda al testo vengono di norma lasciati dal browser, e in certi casi può essere necessario rimuoverli.

Dati nascosti

Un control di input di tipo hidden (nascosto) contiene informazioni impostate dal server nella pagina HTML che il browser deve ritornare allo stesso server tali quali al momento del submit. I campi hidden non vengono visualizzati dai browser, ma naturalmente è possibile leggerli ispezionando il codice HTML della pagina. Si tratta quindi di informazioni che il server parcheggia temporaneamente nella stessa pagina inviata al client, ma che poi il server desidera gli vengano restituite.

 
 
<input type=hidden name="ultimo_valore" value=123>
 

I campi hidden sono utili al server per "ricordare" talune informazioni tra una chiamata e l'altra. Dal punto di vista del browser e dell'utente si tratta solo di un inutile impiccio che non porta informazioni utili e che rallenta la comunicazione. Il programmatore dovrebbe quindi limitare il numero e le dimensioni di questi campi e magari considerare altri strumenti, come il meccanismo della sessione di utente (che qui non discutiamo).

Gli attributi name e value specificano la coppia nome/valore per il parametro da ritornare al server al momento del submit del FORM.

Acquisizione e validazione. Valgono le stesse considerazioni già fatte del i campi di tipo testo su linea singola. In più il programmatore deve fare attenzione quando include nel campo hidden una informazione riservata che l'utente non dovrebbe conoscere (chiave di un data base, informazioni di stato del server, ecc.), perché sebbene questi campi siano "nascosti", in realtà sono facilmente leggibili sia da parte dell'utente sia da parte di chiunque possa intercettare il traffico di rete tra il browser e il server. Un HMAC (hashed message authentication code) può essere utile per evitare che il dato ritornato dal browser venga contraffatto. La crittazione può essere utile per evitare che il dato sia leggibile dall'utente. La soluzione definitiva resta comunque il meccanismo della sessione, con il quale i dati restano sul server.

Check box

Questo control permette all'utente di abilitare o meno una certa funzionalità dell'applicazione WEB. Lato server, ad un checkbox corrisponde di solito una variabile di tipo booleano che vale TRUE se il checkbox è selezionato, e vale FALSE altrimenti. Il checkbox si presenta di norma come un quadratino seguito dalla scritta che descrive la funzionalità da esso abilitata. Un segno di spunta (check mark) appare nel quadratino se il checkbox è attivato. L'utente può cliccare nel quadratino per cambiarne lo stato.

 
Invia e-mail di conferma ordine
 
<input type=checkbox name="email_conferma"
value=1 checked> Invia e-mail di conferma ordine
 

L'attributo name è il nome sotto il quale verrà restituito il valore del control al momento del submit se il checkbox è spuntato (checked). Notare che se il checkbox non è spuntato al momento del submit del FORM, il browser semplicemente non invia alcun valore per questo control.

L'attributo value è il valore del control restituito al momento del submit. In generale non è necessario sforzarsi di definire un valore particolare, tanto quello che interessa lato server è solo verificare se il valore è stato restituito o meno, non il valore in sè.

L'attributo checked non ha valore e, quando presente, definisce lo stato iniziale del control come checked. Se lo stato iniziale deve essere non checked, allora basta non mettere questo attributo nel codice HTML del control.

Il testo che descrive la funzionalità attivata dal checkbox deve trovarsi immediatamente a destra del quadratino. Il testo deve essere sempre nella forma positiva: "Sovrascrivi dati esistenti" è meglio di "Non sovrascrivere i dati esistenti". Il checkbox attivato deve contrassegnare una funzionalità in più, non il suo contrario: un checkbox per "Disabilitare e-mail di conferma" è una contorsione logica inutile.

Per quanto riguarda lo stato iniziale di un checkbox, i criteri da applicare sono i seguenti, nell'ordine:

  1. Se il FORM rappresenta dati preesistenti, lo stato iniziale del checkbox deve riflettere questi dati.
  2. Se la funzionalità comporta un rischio o ha effetti potenzialmente pericolosi, proporre lo stato iniziale più sicuro.
  3. Se la funzionalità viene usata molto frequentemente (molto più del 50% dei casi) abilitare per default.
  4. In tutti gli altri casi lasciare inizialmente disabilitato.

Acquisizione e validazione. E' molto semplice: se il parametro di POST "email_conferma" è presente nei dati ritornati dal browser, allora il checkbox è checked, altrimenti no; il valore restituito per il parametro è irrilevante. Questo è l'unico control che non richiede validazione perché non può essere contraffatto da un utente malizioso.

Radio button

Questo control permette di scegliere una e una soltanto tra due o più opzioni. Lato server un gruppo di radio button viene di solito associato a una variabile di tipo intero che assume il valore 0 per il primo radio button, il valore 1 per il secondo e così via. Quando l'utente clicca su di un radio button, questo si abilita. Quando clicca su di un altro radio button, questo si abilita mentre il precedente radio button attivo si disabilita, esattamente come succedeva nelle radio da automobile di una volta con le stazioni presintonizzate. Cliccare su di un radio button già attivo di norma non ha effetto.

In questo esempio, un gruppo di radio button permette all'utente di scegliere un colore di sfondo. L'ultimo radio button è attivo per default ed esprime la scelta "nessuno sfondo".

 
Colore sfondo Rosso
Verde
Blu
Nessuno sfondo
 
<FIELDSET><LEGEND><b>Colore sfondo</b></LEGEND>
<input type=radio name=sfondo value=1> Rosso<br>
<input type=radio name=sfondo value=2> Verde<br>
<input type=radio name=sfondo value=3> Blu<br>
<input type=radio name=sfondo value=0 checked> Nessuno sfondo
</FIELDSET>
 

NOTA: è bene allineare a sinistra tutti i radio button di un gruppo, ed inoltre sarebbe bene isolarli dal resto della pagina, magari sfruttanto una tabella o un FIELDSET con LEGEND per racchiuderli in una cornice che ne evidenzia la correlazione e ne descrive complessivamente la funzione.

L'attributo name è il nome sotto il quale verrà restituito il valore del radio button attivo al momento del submit. Notare che se nessun radio button era attivo nella pagina inizialmente inviata al browser e se l'utente non ha operato una selezione, nessun valore verrà restituito per questo gruppo di control. Ovviamente tutti i radio button appartenenti allo stesso gruppo devono avere lo stesso nome.

L'attributo value è il valore del control restituito al momento del submit. Ovviamente ogni radio button dovrebbe avere un valore distinto.

L'attributo checked non ha valore e, quando presente, definisce il radio button inizialmente selezionato.

C'è un comportamento subdolo nel come il meccanismo dei radio button è stato concepito. Se la pagina HTML inizialmente inviata al browser non specificava alcun radio button attivo, l'utente ha la possibilità di selezionare o meno una delle opzioni del gruppo ma, se lo fa, nessun browser poi permette di ritornare allo stato iniziale in cui nessun radio button era attivato. Si tratta di una ambiguità che il programmatore dovrebbe evitare. Se il programma prevede la possibilità che nessuna delle opzioni specificate dal gruppo di radio button venga selezionata, allora è meglio prevedere un ulteriore radio button che renda esplicita questa possibilità, esattamente come abbiamo fatto nell'esempio precedente introducendo l'ultima opzione. Inoltre bisogna sempre selezionare uno dei radio button.

Acquisizione e validazione. Con il submit del FORM il browser ritorna il parametro "sfondo" con il valore corrispondente del radio button selezionato. Se nessun radio button è stato selezionato e il programma non ha impostato una opzione iniziale preselezionata, nessun valore viene ritornato per questo gruppo di control: se la logica del programma non lo permette, è necessario segnalare l'errore all'utente e consentirgli di inserire il dato mancante. Il programma deve anche prevedere che in caso di submit contraffatto il dato potrebbe non essere ritornato. E' necessario validare il dato ritornato: nel nostro esempio abbiamo usato un numero compreso tra 0 e 3, per cui la verifica è particolarmente facile.

Lista a scelta singola

Questo control permette di scegliere una opzione all'interno di un elenco. Il comportamento logico della lista a scelta singola è pertanto simile a quello di un gruppo di radio button. La reale differenza sta nel modo in cui si presenta il control, che assume la forma di un menu a tendina:

 
Colore sfondo:
 
Colore sfondo: <select name=sfondo>
<option value=0 selected>--</option>
<option value=1>Rosso</option>
<option value=2>Verde</option>
<option value=3>Blu</option>
</select>
 

Il tag SELECT racchiude la lista. L'attributo name specifica il nome del parametro che il browser dovrà restituire al server. I valori possibili sono specificati negli attributi value dei tag OPTION annidati dentro al tag SELECT. I tag OPTION delimitano il testo delle singole opzioni della lista, in formato HTML. Il tag OPTION può contenere l'attributo selected che marca l'opzione preselezionata.

In generale i browser presentano la prima opzione della lista come preselezionata, sebbene taluni documenti richiedano il contrario (RFC 1866, 8.1.3). Lo standard HTML 4.01 raccomanda perciò di specificare sempre l'opzione inizialmente selezionata. Questa raccomandazione è in linea con quanto abbiamo detto riguardo alla questione dei radio buttons.

Il menu a tendina permette di distinguere bene quattro situazioni, a seconda che la scelta sia facoltativa e il dato disponibile:

In generale conviene scegliere una lista a scelta singola al posto di un gruppo di radio button quando il numero di opzioni sarebbe eccessivo, oppure quando il numero di opzioni viene determinato dinamicamente dal programma che genera il FORM, e quindi non è noto a priori.

Acquisizione e validazione. La lista dell'esempio ritorna al server il parametro "sfondo" che riporta il valore (da 0 a 3) della opzione selezionata. Il parametro potrebbe mancare. Inoltre il valore ritornato dovrebbe essere tra quelli inseriti nella lista al momento della sua generazione. Quest'ultimo controllo è facile quando le opzioni sono contrassegnate da semplici numeri compresi tra un minimo e un massimo, ma diventa difficile quando si tratta di altri valori. Bisogna prestare particolare attenzione quando il valore viene utilizzato come chiave primaria del data base o per altri fini, dato che potrebbe essere contraffatto.

Inquadriamo meglio il problema con un esempio. Abbiamo un sistema di WEB mail che permette agli utenti registrati di consultare la propria posta. Tutti i messaggi di tutti gli utenti sono mantenuti in una tabella del DB e contrassegnati da un numero univoco (la chiave primaria) e dal nome dell'utente. Mettiamo ad esempio che la lista a scelta singola permetta di selezionare uno tra i tanti messaggi di posta elettronica contenuti nella mailbox dell'utente. Risulta naturale che i valori delle opzioni della lista siano le chiavi primarie che individuano i messaggi. E' evidente che un utente malevolo potrebbe selezionare messaggi di altri utenti oltre ai propri semplicemente inviando una richiesta con una chiave primaria contraffatta. Questo va sicuramente impedito.

Le soluzioni al problema della validazione possono essere diverse:

Lista a scelta multipla

Permette di selezionare zero, una o più opzioni da una lista di opzioni. Si ottiene aggiungendo l'attributo multiple (senza valore) al tag SELECT, mentre gli altri attributi conservano il loro significato. Nel caso delle liste a scelta multipla diventa utile anche l'attributo size del tag SELECT, che permette di specificare il numero di opzioni da visualizzare allo stesso tempo.

 
 
<select name=prodotti multiple size=3>
<option value=0>Mele</option>
<option value=1 selected>Pere</option>
<option value=2 selected>Banane</option>
<option value=3>Pesche</option>
<option value=4>Albicocche</option>
<option value=5>Prugne</option>
</select>
 

L'attributo selected contrassegna le opzioni preselezionate.

Cliccando con il mouse su di una opzione, questa viene selezionata, mentre le altre eventualmente già selezionate vengono deselezionate. Per selezionare opzioni multiple, l'utente deve premere il tasto CTRL mentre seleziona una opzione da aggiungere o togliere a quelle scelte. Il tasto SHIFT permette di selezionare intervalli di opzioni, anche se in modo poco intuitivo.

Acquisizione e validazione. Se nessuna opzione risulta selezionata, nessun valore viene ritornato col submit. Se la logica del programma richiede che almeno una delle opzioni venga selezionata, è a questo punto che dovremo sollevare la condizione di errore.

Se una o più opzioni vengono selezionate, allora altrettanti parametri "prodotto" vengono ritornati al server, tutti con lo stesso nome ma con valori diversi; sarà compito del server riorganizzare questi valori in un array o altra struttura dati. Se la logica del programma prevede un limite massimo al numero di opzioni selezionabili, è a questo punto che il programma deve sollevare la condizione di errore. Per la validazione si presentano gli stessi problemi già discussi per la lista a scelta singola, con la differenza che la validazione deve essere applicata a tutte le opzioni scelte.

Inoltre un submit contraffatto potrebbe contenere più valori di quelli a suo tempo inseriti nella lista, o valori duplicati. Riconoscere valori duplicati non è così banale come sembra, soprattutto se i valori in questione sono numeri: ad esempio, la stringa "123" e la stringa "0123", seppur diverse, tipicamente sono lo stesso valore quando vengono tradotte in un numero intero. Questo fatto, e cioè che stringhe diverse possono codificare valori uguali per il programma, rende delicata la scrittura di routine generali di validazione di questo control.

Liste con un numero arbitrario di elementi

Le liste a scelta singola e a scelta multipla sono adatte quando il numero di voci è piuttosto piccolo. Tipicamente questo è il caso di elenchi definiti in modo statico dal programma, come i mesi dell'anno, le provincie di una data regione o le modalità di esecuzione di un pagamento. Le liste non sono adatte quando il numero di voci sale oltre il centinaio, e quando le liste sono determinate dinamicamente e quindi il numero di voci non è noto a priori ma potrebbe diventare arbitrariamente grande man mano che il DB del programma si arricchisce di dati. Usando i normali control HTML, infatti, l'intera lista viene caricata nella pagina HTML ogni volta che la pagina viene presentata. Inoltre selezionare una voce da un elenco lunghissimo diventa difficoltoso per l'utente. Si impone quindi una soluzione diversa che mantenga "leggere" le pagine e che dia all'utente la possibilità di trovare e selezionare in modo pratico una o più voci all'interno di un elenco di dimensione arbitraria. Qui daremo le indicazioni di massima su come realizzare quello che chiameremo un "combobox", in pratica un nuovo tipo di control implementato in puro HTML.

Per prima descriviamo come l'interazione dovrebbe apparire. Situazione: un FORM con diversi campi; uno di questi campi richiede la selezione di un prodotto scelto da una lista di centinaia o migliaia contenuti nel DB. E' evidente che non potremo usare una lista a scelta singola perché il numero di voci sarebbe troppo grande. Dobbiamo rendere il programma "scalabile" con l'aumentare del numero dei prodotti. Ecco che dobbiamo ricorrere al nostro combobox. Il suo aspetto è il seguente:


Prodotto scelto:   --

Tutto il meccanismo coinvolge tre pagine HTML: la pagina del FORM che contiene il combobox; la maschera di ricerca prodotto; la pagina con l'elenco dei prodotti che soddisfano i criteri di ricerca voluti. Vediamo adesso come interagiscono fra di loro queste pagine.

Inizialmente il prodotto scelto è "--", che significa "nessun prodotto scelto". Seguendo la convenzione che abbiamo già visto per le liste, se la selezione del prodotto è obbligatoria mostreremo invece il simbolo "??".

Per scegliere il prodotto l'utente deve premere il pulsante Scegli che lo porta alla maschera di ricerca prodotti. Qui può selezionare il prodotto eseguendo una ricerca per marca, modello, categoria o qualsiasi altro criterio ritenga opportuno. La maschera di ricerca ha due pulsanti: il pulsante Annulla annulla la ricerca e riporta alla maschera precedente senza compiere alcuna operazione; il pulsante Ricerca attiva la ricerca nel DB dei prodotti e presenta l'elenco dei prodotti trovati che soddisfano i criteri di ricerca inseriti. L'utente clicca sul prodotto voluto e viene rimandato al FORM iniziale. Nel FORM iniziale, magicamente, il combobox viene aggiornato con la scelta eseguita:


Prodotto scelto:   Materasso a molle INSOMNIA

L'utente prosegue la compilazione del FORM come al solito, ed eventualmente può cambiare anche il prodotto scelto.

Vediamo ora, per sommi capi, come avviene il trucco. Il pulsante Scegli esegue in realtà il submit del FORM, dando così modo al server di memorizzare lo stato del FORM parzialmente compilato. In questa fase non si esegue alcuna validazione. Quindi il server presenta la pagina di ricerca prodotto, poi l'elenco dei prodotti, ed infine acquisisce la scelta operata dall'utente. Il prodotto scelto viene messo nei dati del FORM originario, e quindi il FORM originario viene riproposto con il valore del combobox aggiornato.

Notare che il problema è stato risolto producendo una interfaccia semplice, intuitiva e scalabile. In particolare non sono stati coinvolti linguaggi di programmazione lato client, nè i trucchi "sporchi" spesso usati per risolvere in modo spiccio queste situazioni. Tutto è stato implementato solo con un accorto lavoro lato server.

Upload di file

Per "upload" intendiamo l'invio di un file dal browser verso il server. L'operazione inversa, e cioè l'invio di un file dal server al browser, è gestibile attraverso la richiesta GET. Una discussione tecnica più approfondita del meccanismo di upload dei file via HTTP si può trovare nell'articolo PHP File Upload citato nei riferimenti.

Il control di input di tipo "file" permette di eseguire l'upload di un file indicato dall'utente:

 
Foto:
 
Foto: <input type=file name=foto size=50>
 

Il pulsante "Browse..." o "Choose..." (che diventa "Sfoglia..." nei browser localizzati in italiano) quando premuto visualizza una finestra che consente all'utente di selezionare un file da inviare al server al momento del submit del FORM. Il protocollo di invio files dell'HTML permette di inviare anche due o più files con un solo control di questo tipo. Tuttavia mi pare che nessun browser supporti tale funzionalità (eccetto forse le vecchie versioni di Opera, ma non le più recenti), sicché ci dovremo accontentare di un solo file per ogni control.

L'attributo name è, come al solito, il nome del parametro HTTP che conterrà il file al momento del submit del FORM.

L'attributo value permette di specificare il nome iniziale del file. Siccome è una funzionalità pericolosa, i browser ignorano questo attributo. Di conseguenza non c'è ragione di usarlo.

L'attributo size specifica la larghezza del campo di input nel quale appare il nome del file scelto. Siccome non sappiamo quanto sarà lungo questo nome di file, e siccome l'unità di misura è piuttosto arbitraria, in definitiva questo valore andrà determinato con qualche prova. 50 o 70 caratteri dovrebbero consentire di vedere una buona porzione del nome del file nella maggior parte delle situazioni.

Quello che manca a questo control è la possibilità di indicare il "valore corrente", cioè il file già presente sul server. In questo senso questo control ha una semantica diversa dagli altri control. Inoltre c'è un problema di interazione: supponiamo di aver compilato tutto il FORM, e di avere anche indicato un file; supponiamo che tale file sia anche piuttosto lungo, tanto da richiedere diversi secondi di upload. Al termine premiamo il pulsante di submit. Cosa succede se i dati immessi non superano la validazione? Non possiamo invitare l'utente a correggere i dati immessi e per giunta costringerlo a rifare la selezione e l'upload del file, che invece era corretto. La soluzione che qui proponiamo prevede che, nel caso un file sia già disponibile sul server, il FORM presenti una sorta di control di upload di file esteso che include il nome del file corrente sul server, il suo tipo MIME e la sua lunghezza, come in questo esempio:

 
Foto: Vacanze.jpg (image/jpeg, 47587 B) /
 
Foto: <b>Vacanze.jpg</b> (image/jpeg, 47587 B)
<input type=submit name="foto_rimuovi" value=Rimuovi> /
<input type=file name=foto size=15>
 

L'utente ha quindi tre possibilità:

  1. Confermare il file corrente sul server "Vacanze.jpg" semplicemente premendo il pulsante di submit del FORM. Il server mantiene il file prima caricato.
  2. Rimuovere il file corrente premendo il pulsante "Rimuovi". Il server rimuove il file prima caricato, non esegue la validazione e ripresenta il FORM con i dati parzialmente compilati.
  3. Immettere un nuovo file premendo il pulsante "Browse..." (o "Sfoglia...").

Una volta che l'utente abbia terminato la compilazione del FORM, premerà il pulsante di submit "Salva" (o altro nome evocativo). Il server riceve il FORM: se è stato specificato un file, questo file viene salvato definitivamente, eventualmente sostituendo quello preesistente; se non è stato specificato un file, oppure è stato rimosso col pulsante "Rimuovi", allora il server cancellerà il file preesistente. In questo modo il FORM come visto dall'utente riflette sempre lo stato effettivo dei dati sul server. Se invece l'utente preme il pulsante "Annulla" il server non altera i dati che esistevano, neanche se l'utente ha premuto il pulsante "Rimuovi".

Acquisizione e validazione. Il browser include il file tra i parametri del submit usando una opportuna codifica. Oltre al nome del parametro ("foto", nel nostro esempio) le altre informazioni inviate sono: il nome originario del file; il suo tipo MIME. Lato server non possiamo fare alcun affidamento sulla presenza e sul valore di questi dati. Se nessun file viene selezionato dall'utente, il browser invia un file vuoto con nome vuoto.

Il nome del file sul sistema del browser potrebbe contenere caratteri non ASCII. In tal caso le specifiche HTML 4.01 e il documento RFC 1867 richiedono che il nome del file venga codificato secondo lo schema dell'RFC 2047, par. 4.2. Ad esempio, se il nome del file è "Caffè Brilli.jpg" dovrebbe essere reso come "=?ISO-8859-15?Q?Caff=E8_Brilli=2Ejpg?=". Lato server dovremo sempre controllare la presenza di questa codifica ed eseguire la conversione opportuna nel charset usato dal programma.


Attenzione!Nessun browser sembra rispettare questo requisito, e i nomi dei file vengono restituiti usando il charset della pagina che contiene il form. Se il nome del file contiene caratteri che non sono previsti nel charset della pagina, allora questi caratteri vengono codificati nella forma "&#xxx;" dove "xxx" è il codice decimale Unicode del carattere. Purtroppo il carattere "&" stesso non viene codificato, sicché lato server non è possibile riconoscere il problema in modo certo. Provato con Mozilla 1.7.3 e Internet Explorer 6.0. Forse è più semplice così.

Inoltre il nome del file potrebbe contenere caratteri specifici del sistema operativo del client, ma non adatti per un nome di file sul server. Ad esempio, sul file system di tipo Unix i caratteri ASCII "/" e il codice ASCII 0 sono vietati, mentre i nomi di file "." e ".." sono riservati. Occorre quindi fare attenzione nel sanificare il nome del file fornito qualora lo si voglia salvare sul server. Meglio sarebbe salvare il nome del file originale così come fornito, ad esempio nel data base, e poi salvare il file usando un nome adatto generato all'uopo rispettando le convenzioni del file system del server.

Riguardo al tipo MIME, ricordiamo che questo codifica il tipo del file. In particolare, le cosiddette "estensioni" dei nomi dei file non si dovrebbero utilizzare per determinare il tipo del file, ma ci si dovrebbe unicamente basare sul tipo MIME fornito. Ad esempio, se il file si chiama "Vacanze.jpg" e il tipo MIME fornito è "text/plain", il file va considerato come un testo puro. Eventualmente, lato server potremo anche verificare che il contenuto del file corrisponda effettivamente al tipo MIME fornito. Ad esempio, se il file è del tipo "image/gif" potremmo controllare che il file abbia effettivamente la struttura di una immagine GIF.

Pulsanti

Dei pulsanti abbiamo già accennato. Essi causano l'invio dei dati del FORM inviando al server una richiesta GET o POST del protocollo HTTP. Questa azione del browser viene anche detta "submit", che poi è anche il nome che l'HTML ha dato a questo particolare control. La richiesta include i valori dei control impostati dall'utente. Esempio di pulsante:

 
 
<input type=submit name=salva value="Salva">
 

L'attributo name e il valore value vengono inviati al server come parametro.

L'attributo value viene anche usato dal browser anche per contrassegnare il pulsante con una scritta. Purtroppo l'HTML non fa distinzione tra questi due ruoli diversi dell'attributo, e ciò può creare qualche complicazione al programmatore quando il FORM include diversi pulsanti oppure quando si hanno siti in più lingue.

Ricordiamo alcune regole di interfaccia per impostare bene i pulsanti:

Acquisizione e validazione. Se il pulsante del nostro esempio viene premuto, il browser invia al server il parametro "salva=Salva". Se il FORM include due o più pulsanti, il server può distinguere quale pulsante è stato premuto usando due strategie:

FORM multipli e FORM annidati

Di norma una pagina HTML contiene al più un FORM e uno o più pulsanti di submit che inviano tutti i valori dei control al server. Nulla vieta di mettere due o più FORM in una pagina, ma bisogna tenere conto che un dato pulsante di submit invia solo i valori dei control del FORM del quale il pulsante fa parte, mentre i valori dei control degli altri FORM, anche se compilati, vengono perduti. Questo può confondere l'utente, che potrebbe compilare i campi di un FORM e poi fare il submit di un altro FORM vuoto. Nell'esempio della maschera qui sotto l'utente può eseguire una ricerca di tipo bibliografico. Il programmatore ha ritenuto opportuno di distinguere nettamente due situazioni diverse e ha perciò prodotto due aree di input distinte:


Ricerca per autore

Autore:


Ricerca per titolo

Titolo:

Anno di pubblicazione:

Maschera di ricerca, prima soluzione.


Analizziamo questa soluzione. Supponiamo che le due aree della maschera siano gestire da due FORM distinti: il primo FORM ha come action il programma sul server che fa la ricerca per autore, mentre il secondo FORM ha come action il programma sul server che fa la ricerca per titolo. Esiste un possibile problema di interazione: se l'utente compone il nome dell'autore e poi preme il pulsante "Ricerca" più in basso, il server riceve solo dei campi vuoti, mentre il nome dell'autore così diligentemente composto dall'utente viene perso. Se l'utente tenta prima una ricerca per autore e poi passa alla ricerca per titolo, il nome dell'autore scompare, sicché le ricerche incrociate autore/titolo non si possono fare.

Meglio allora integrare tutti i control in un unico FORM e quindi un unico action: il programma lato server deduce quale tipo di ricerca eseguire in base a quale dei due pulsanti "Ricerca" è stato premuto. Il programma lato server ha così la possibilità di salvare tutti i campi del FORM, inclusi quelli che non fanno parte della ricerca corrente. Una volta che l'utente ha visionato il risultato dell'ultima ricerca, il programma ha quindi la possibilità di riproporre il FORM originario con tutti i campi compilati come erano stati scritti dall'utente. L'utente può raffinare il criterio di ricerca aggiungendo o modificando i campi già compilati senza dover ripetere completamente l'inserimento. Questa tecnica si chiama anche dello sticky form. Questo è già un passo avanti.

Ma si può fare ancora meglio: facciamo un solo FORM ed eliminiamo il primo pulsante "Ricerca", lasciando quindi un solo pulsante di submit. Lato server eseguiremo la ricerca in base ai valori dei campi che sono stati compilati. Quando l'utente compila due o più campi, il server eseguirà una ricerca incrociata in "AND". In altri termini, lato server dovremo costruire dinamicamente l'interrogazione al data base. Con questa soluzione non solo abbiamo eliminato il doppio FORM, ma abbiamo migliorato tutto il programma.


Ricerca bibliografica

Autore:

Titolo:

Anno di pubblicazione:

Maschera di ricerca, soluzione migliore.


L'unico caso in cui i FORM multipli in una sola pagina HTML sono utili è quando la pagina contiene solo pulsanti che rimandano ad altrettanti action diversi, e al più dei campi hidden. Ad esempio, abbiamo un elenco di prodotti e ciascuna voce ha a fianco un pulsante "Acquista..." per inserire il prodotto nel carrello. Si potrebbe obiettare che lo stesso risultato lo si potrebbe ottenere con delle semplici ancore, eventualmente con parametri GET nell'URL. Tuttavia a volte dei bei pulsanti rendono più efficace l'interfaccia perché sottolineano l'attivazione di una azione e non il semplice passaggio a un'altra pagina. Inoltre i campi hidden sono più adatti quando i dati da trasportare sono troppo voluminosi per un semplice URL.


Java 2 - I fondamenti
Cay Horstmann, Gary Cornell
McGraw-Hill (2004) dettagli...
JavaServer Pages
Hans Bergsten
O'Reilly (2002) dettagli...
HTML 4.01
Gabriele Gigliotti
Apogeo (2004) dettagli...
PHP 5 Power Programming
Andi Gutmans, Stig Saether Bakken, Derick Rethans
Prentice Hall (2005) dettagli...

Soluzione con tanti pulsanti e tanti FORM. Ogni FORM causa l'invio dei campi hidden specifici della voce in elenco. Al posto dei pulsanti avremmo potuto usare delle ancore, che sono però meno adatte a trasportare molte informazioni.

Nella figura qui sopra abbiamo voluto strafare e abbiamo anche inserito un'ancora per ogni prodotto che permette all'utente di vedere la scheda informativa completa. L'ancora, ormai tutti gli utenti lo sanno, è un riferimento a un'altra pagina che non produce una azione irreversibile, e quindi un'ancora in questo caso è la soluzione di interfaccia appropriata per far accedere alla scheda completa del prodotto. In generale non si possono inserire le ancore nelle maschere che contengono un FORM, dato che l'ancora non produce il submit dei dati. Infatti se una maschera con un FORM contenesse anche un'ancora, e l'utente compilasse alcuni campi, premendo distrattamente l'ancora i valori immessi verrebbero perduti! Se proprio vogliamo mettere qualcosa di simile a un'ancora dentro a una maschera che contiene un FORM con dei campi compilabili, allora abbiamo due soluzioni:

La questione dei FORM annidati (cioè un FORM inserito dentro a un altro FORM) la possiamo liquidare rapidamente: non si può fare perché non ha senso. In realtà non ho trovato documenti che contemplino esplicitamente questo caso, ma ritengo la mia deduzione abbastanza convincente da non richiedere ulteriori accertamenti :-)

Cose che qui abbiamo omesso di trattare

Il campo di input di tipo "password" ha lo stesso comportamento del tipo "text" ma il testo in esso presente non viene visualizzato dal browser. E' utile per l'input di password o altre informazioni riservate.

Il control di input di tipo "image" permette di sostituire un normale pulsante con una immagine. Abbiamo già detto che tale pratica è da evitare, salvo quei rari casi nei quali la funzionalità svolta dal pulsante può essere rappresentata meglio con una immagine.

Il control di input di tipo "button" è un pulsante che non produce submit e deve essere gestito via JavaScript.

Il control di input di tipo "reset" è un pulsante che, quando premuto, non causa il submit, ma ripristina lo stato del FORM con i valori iniziali. Si tratta di una funzionalità inutile o pericolosa perché di solito viene premuto per sbaglio, causando la perdita di tutti i dati faticosamente inseriti dall'utente fino a quel punto. Meglio prevedere un pulsante "Salva" per confermare e salvare i dati del FORM, e un pulsante "Annulla" per annullare le modifiche o l'inserimento dei dati e passare alla pagina successiva secondo la logica del programma.

Riferimenti

Argomenti correlati


Umberto Salsi
Commenti
Contatto
Mappa
Home / Indice sezione
Still no comments to this page. Use the Comments link above to add your contribute.