|
Cominciamo a renderci conto in
pratica di quanto appena detto ed esaminiamo la routine principale in
listato 1.
1 ## Programma principale
2 $REREFER="http://www.provider.it/cgi-bin/form.pl";
3
4 print "Content-type: text/html\n\n";
5
6 # decodifica l'input
7 # mostra la form vuota se non c'e' input
8 unless(&UnCgi) {
9 &PrintForm('');
10 exit 0;
11 }
12
13 # verifica la form e riemettila se e' sbagliata
14 if($_=&CheckForm) {
15 &PrintForm($_);
16 exit 0;
17 }
18
19 # tutto ok
20 &ProcessForm;
21 exit 0;
Listato 1
In linea 4 si stampa un
header che serve al browser per rendersi conto che tipo di output gli
stanno inviando. Il protocollo http prevede specificamente che ogni
output al browser cominci con una intestazione che identifica il tipo
del documento restituito. Normalmente un server Web identifica il
tipo del documento che serve dal nome, in base alla sua
configurazione, e genera automaticamente l'header necessario.
Ma uno script CGI può
teoricamente generare molti tipi diversi di documento. Anche se non è
il nostro caso (noi generiamo esclusivamente HTML) esistono script
che generano, a seconda di come sono invocati, HTML o GIF o altra
roba. Quindi lo standard CGI prevede che l'output cominci con
l'identificazione del tipo. Tra l'altro il messaggio di errore che
talvolta compare (Server Error) viene generato DAL SERVER quando uno
script CGI non genera correttamente questo header.
Questo avviene spesso quando si
tenta di eseguire uno script in Perl senza averne controllato la
sintassi. Se ci sono errori il Perl nemmeno comincia l'esecuzione
dello script ma si limita a produrre dei messaggi di errore, che non
sono le due righe iniziali che il server si aspetta. Da qui il Server
Error.
Comunque sia, superati i dettagli
burocratici in riga 4, cominciamo il lavoro duro decodificando
l'input con la subroutine UnCgi. Ne vedremo l'implementazione
più avanti, intanto accontentiamoci di sapere che cosa fa.
Questa subroutine legge l'input, che viene passato come una stringa
nel formato criptico che avete già assaggiato, la analizza e
salva il risultato nell'array associativo %WWW. Gli array
associativi in Perl sono degli array speciali che possono essere
indicizzati con delle stringhe generiche, che agiscono come chiavi di
una tabella di database. Avremo quindi che ogni chiave di %WWW
corrisponde ad un campo della form e il suo valore è il
valore specificato dall'utente: per esempio, se abbiamo un campo nome,
allora il suo valore è $WWW{'nome'}. La UnCgi
ritorna falso se non abbiamo avuto alcun risultato dall'analisi della
stringa di input: il che significa che il nostro script non è
stato invocato dalla form ma richiamato direttamente, probabilmente
seguendo un link. In questo caso semplicemente generiamo un modulo
vuoto e terminiamo (linee 8-11).
Se invece la UnCgi ritorna vero, abbiamo qualcosa in input: il
che vuol dire che lo script è stato richiamato con dei dati. E'
il momento di verificarli (linea 14): se ci sono errori la
CheckForm, che naturalmente verifica i dati in ingresso,
ritorna il messaggio di errore. Avrete capito che il parametro usato
dalla PrintForm è il messaggio di errore: la form viene
ristampata col messaggio restituita dalla CheckForm e viene
re-inizializzata con i valori letti dall'input, mantentendo
così i valori che l'utente ha appena immesso per poterli
correggere senza ribattere tutto . Se invece non ci sono errori si
passa alla ProcessForm che invia la mail e stampa un messaggio di
ringraziamento.
In listato 2 vediamo la
funzione di stampa della form.
1 ### PrintForm
2 # input: %WWW
3
4 sub PrintForm {
5 local ($err) = @_;
6
7 # intestazione
8 print <<"EOF";
9 <title>FORM DEMO</title>
10 <body>
11 <h1>FORM DEMO</h1>
12 EOF
13
14 # messaggio d'errore
15 print "<br><b>Errore:</b>$err<br>"
16 if($err) ;
17
18 # stampa la form con i campi correnti
19 print <<"EOF";
20 <form action="$REREFER">
21 Nome:<br>
22 <input type="text" name="name" size="20" value="$WWW{'name'}"><br>
23 Indirizzo:<br>
24 <input type="text" name="address" size="40" value="$WWW{'address'}"><br>
25 Telefono:<br>
26 <input type="text" name="phone" size="10" value="$WWW{'phone'}"><br>
27 <input type="submit" value="INVIA">
28 </form>
29 EOF
30 }
Listato 2
Innanzitutto osserviamo la stampa con l'inline quoting del Perl. Si
tratta di una caratteristica che ci permette di inserire testo o dati
in un programma così com'è, e questo è
particolarmente utile nel nostro caso, in cui inseriamo pagine HTML
che magari ci siamo creati a parte utilizzando un apposito editor.
Il meccanismo è semplice: invece
di scrivere una stringa tra virgolette, come di consueto in Perl,
scriviamo << seguito da un delimitatore. Tutte le linee
dalla riga successiva fino al delimitatore (escluso) saranno
considerate una stringa e sostituite al posto del "<<".
Il delimitatore è pure una stringa, racchiusa tra virgolette
singole o doppie e va scelta in modo che non occorra nel testo
incorporato inline. Come ricorderete in Perl abbiamo due tipi di
virgolette: singole (l'apice singolo) doppie (i doppi apici). Per la
verità ce ne è un terzo, l'apice singolo inverso, che
serve per eseguire comandi esterni, ma non ci interessa per il
momento.
Le virgolette singole servono ad
inserire stringhe così come sono: nessun carattere nella
stringa ha significato speciale (eccetto le sequenze \' che
sta per l'apice stesso e \\ che sta per il backslash). Le
virgolette doppie invece ammettono una interpretazione del testo
racchiuso un po' più flessibile. Innanzitutto sono ammesse
sequenze speciali come \t, \n eccetera (queste stanno
per il tab, il newline e così via, seguendo convenzioni che
provengono dal linguaggio C). Poi è possibile effettuare la
cosiddetta interpolazione di stringhe: sequenze di caratteri che
cominciano con $ all'interno della stringa sono considerate
variabili e come tali vengono espanse.
Le virgolette intorno al delimitatore
hanno la funzione di precisare il tipo di interpretazione che deve
essere dato al testo incorporato. Se si tratta di virgolette singole
il testo viene considerato così com'è, mentre se si
tratta di virgolette doppie le variabili vengono espanse. Nel nostro
caso è proprio quest'ultimo comportamento quello che ci
interessa. Come si vede in listato 2 abbiamo alcuni
print
<<"EOF";
seguiti da alcune linee di HTML. Ma
non si tratta di HTML puro: infatti vi sono inserite delle variabili
Perl che vengono espanse quando si stampa la stringa. Per esempio
abbiamo $REREFER che è stata inizializzata all'URL del
nostro script e serve per richiamarlo. E poi abbiamo $WWW{'name'},
$WWW{'address'} eccetera.
Cogliamo l'occasione anche per parlare
di subroutine e di passaggio di parametri. Una subroutine è
semplicemente una serie di comandi, racchiusi tra graffe e preceduti
da sub <nome-subroutine>. Non abbiamo sintassi per
passare i parametri: i parametri di una subroutine sono passati
attraverso l'array @__. Per dargli un nome normalmente si
assegnano gli elementi dell'array a delle variabili locali. E' questo
il senso della riga 5. La local rende la variabile argomento
una variabile locale, che non va in conflitto con altre con lo stesso
nome.
Riprendiamo l'analisi della nostra
subroutine. Come si vede (listato 2 riga 8), si stampa
innanzitutto una intestazione, poi se c'è un errore (passato
come primo argomento) lo si stampa. Infine si stampa la form con i
campi di input inizializzati ai valori provenienti dallo stesso campo
alla "passata precedente".
Se facciamo un attimo mente locale a
come funziona il nostro programma, dovrebbe essere chiaro adesso come
fa la form a mantenere i dati tra una invocazione e l'altra.
Consideriamo il caso che l'utente immetta il nome e tralasci
l'indirizzo. La funzione di verifica non fa proseguire e la form
viene ristampata. Ora il valore del campo name appena immesso
è stato decodificato e memorizzato nella variabile $WWW{'name'},
il campo address in $WWW{'address'} e così via.
Quindi quando la form viene ristampata, il valore di default dei vari
campi (quello specificato dal campo VALUE del tag INPUT)
è quello proveniente dalla form che l'utente ha appena
inviato. E quindi il valore appena immesso viene ripresentato per
eventuali correzioni.
|