Nel primo articolo di questa serie abbiamo visto come installare e
configurare un server Web.
Ora occupiamoci di qualcosa di più interessante delle semplici
pagine html.
Probabilmente tutti saprete che è possibile scrivere delle
particolari pagine, chiamate forms, che rendono possibile
l'interazione tra l'utente e il server Web.
Nelle forms l'utente può inserire dei dati che successivamente
vengono elaborati da programmi che girano sul server e che possono
generare come risposta una pagina html che viene rispedita
all'utente.
Ma cosa può fare un programma così concepito?
Un uso molto comune delle forms è quello di creare front end per
la consultazione di archivi, quindi i programmi sul server andranno ad
interrogare i databases e genereranno pagine html contenenti i dati
estratti.
...e come devono essere scritti i programmi per poter interagire con il
server Web?
Esiste uno standard, chiamato CGI (Common Gateway Interface), che
stabilisce come leggere i dati che l'utente ha immesso nella form e
come passare i risultati delle elaborazioni al server, perché
siano rispediti al client.
In quali linguaggi si possono scrivere questi programmi?
Basta un qualsiasi linguaggio che sia in grado di leggere lo standard
input e le variabili di environment del sistema e di
scrivere sullo standard output. Devo dire che non mi viene in mente
nessun linguaggio che non risponda a questi requisiti minimi.
Il linguaggio che in questo momento gode il maggior favore per la
scrittura dei cgi-bin (i programmi per l'interfacciamento al Web
vengono così chiamati dal nome della directory in cui di solito
risiedono) è il Perl.
I motivi per questa scelta sono vari: si impara molto facilmente a
programmare in Perl se si conosce il C e si è pratici del
linguaggio delle shell Unix, è un linguaggio interpretato con un
ottimo set di strumenti per lo sviluppo (ha un ottimo debugger, un
profiler ed altri tools), è molto più portabile del C,
è un linguaggio di livello più alto del C, pur essendo
abbastanza veloce e sono disponibili moduli aggiuntivi che ne
permettono l'interfacciamento a tutti i più diffusi databases in
commercio (Oracle, Ingres, Sybase, Informix, ecc.).
Dopo questa sviolinata sul Perl, che è comunque nella dotazione standard di qualsiasi installazione di Linux, passiamo alle forms e all'effettivo sviluppo di qualche programmino di esempio.
Come prima cosa dobbiamo scrivere una form:
<!-- Prima prova di form --> <html> <head> <title>Ricerca indirizzi e numeri di telefono</title> </head> <body> <h3><center>Front end per la ricerca di indirizzi e numeri di telefono nel mio piccolo database di amici</center></h3> <p> Inserisci il nome, o parte di questo nel campo e premi il tasto "Ricerca". <p> <form method=post action="http:/cgi-bin/ricerca"> Nome: <input size=25 maxlength=25 name="nome"> <p> <input type="submit" value="Ricerca"> </body> </html>
Se inseriamo questo file nella directory delle pagine html (il default per il server NCSA è /var/httpd/htdocs) come prova.html, possiamo usare il nostro client per verificarla caricandola come:
http://localhost/prova.html
La pagina che visualizzerete avrà un campo per l'immissione del nome della persona di cui volete avere l'indirizzo e numero di telefono e un tasto che serve per passare i dati immessi al cerver.
Analizziamo la struttura della form. Ciò che la identifica come tale è la riga:
<form method=post action="http:/cgi-bin/ricerca">
Questa riga inoltre dice al server che il programma che deve essere
lanciato quando l'utente preme il tasto Ricerca si chiama
ricerca e risiede nella directory /cgi-bin.
La directory è specificata a partire dalla radice delle
directory accessibili dal server Web, quindi, sempre nel caso di una
configurazione standard, a partire da /var/httpd.
Il metodo con cui il server passerà i dati al programma cgi-bin
è il post, cioè i dati saranno passati come
standard input nella forma campo=valore.
La riga:
Nome: <input size=25 maxlength=25 name="nome">
definisce un campo per l'immissione di un testo, lungo abbastanza per
permettere di inserire 25 caratteri, presentato in modo tale che tutti
i 25 caratteri siano visibili sullo schermo.
È possibile specificare campi scrollabili, cioè
in cui è possibile immettere una stringa più lunga di
quanto non sia possibile mostrare sullo schermo: provate a modificare
i parametri size e maxlength.
Il parametro name dichiara il nome con cui questo campo sarà accessibile dal programma cgi-bin.
La riga:
<input type="submit" value="Ricerca">
definisce un pulsante di tipo submit, in grado di spedire il contenuto della form al server. La stringa che comparirà sul pulsante è data dal valore assegnato al parametro value.
A questo punto dobbiamo progettare un database di nomi, indirizzi e
numeri di telefono da interrogare con il nostro cgi-bin.
Questo database sarà una cosina molto semplice. Tanto per
iniziare propongo un file contenente i campi che ci interessano
separati da ;.
Proviamo con qualcosa del genere:
Andrea Bianchi;V. dei ciclamini, 42;123456 Franco Neri;V. dei salici, 69;234567 Mario Rossi;V. delle rose, 13;345678 Filippo Verdi;V.le dei pini,17;456789
Salviamo questo file come /var/httpd/cgi-bin/dati, magari come appartenente a root e con permissions 644 (lettura e scrittura per il possessore e sola lettura per gli altri).
Il programma cgi-bin in Perl è questo:
#!/usr/bin/perl read(STDIN,$_,$ENV{'CONTENT_LENGTH'}); ($nome, $valore) = split(/=/); print "Content-type: text/html\n\n"; print "<html><body>\n"; $res = open(DB, "dati"); if($res == 0){ print "Non posso aprire il database.<br>Contattare il Webmaster.\n"; print "</body></html>\n"; exit; } $flag = 0; while(<DB>){ ($nome, $via, $tel) = split(/;/); if($nome =~ /$valore/i){ $flag = 1; last; } } if($flag == 1){ print "Il signor/la signora <b>$nome</b><br>\n"; print "abita in <b>$via</b><br>\n"; print "Telefono: <b>$tel</b><p>\n"; }else{ print "Mi dispiace, ma non ho trovato alcun <b>$valore</b> nel database!\n"; } print "</body></html>\n";
Salviamo questo file come /var/httpd/cgi-bin/ricerca, con permesso di lettura ed esecuzione per tutti.
Analizziamo il programma. La riga:
read(STDIN,$_,$ENV{'CONTENT_LENGTH'});
legge lo standard input, per un numero di caratteri specificato nella variabile di environment CONTENT_LENGTH. Questa variabile viene settata dal server http nell'environment del programma chiamato (il nostro script "ricerca").
Il risultato della lettura viene immagazzinato nella variabile di
default $_.
La riga successiva:
($nome, $valore) = split(/=/);
esamina la stringa contenuta nella variabile di
default ed utilizza il carattere '=' come elemento
separatore al fine di dividerla.
I due pezzi risultanti vengono immagazzinati delle variabili
$nome e $valore che conterranno rispettivamente il nome
del campo della form ed il suo contenuto.
A questo punto spariamo al server http la nostra parola magica:
print "Content-type: text/html\n\n";
che segnala la presenza di una pagina html di risposta. Questa pagina la genereremo run-time da programma.
Possiamo addirittura passare le prime istruzioni html al server:
print "<html><body>\n";
in modo da segnalargli l'inizio della pagina.
Lo scopo del programma è quello di interrogare il nostro
database, che altro non è che un normalissimo file.
Come in un qualsiasi altro linguaggio di programmazione apriamo il
file e gestiamo eventuali errori:
$res = open(DB, "dati"); if($res == 0){ print "Non posso aprire il database.<br>Contattare il Webmaster.\n"; print "</body></html>\n"; exit; }
Il file aperto si chiama dati e il file descriptor associato, DB, verrà utilizzato per le operazioni di I/O.
Ora leggiamo il database e usciamo dal loop quando troviamo il nome cercato o quando arriviamo alla fine del file:
$flag = 0; while(<DB>){ ($nome, $via, $tel) = split(/;/); if($nome =~ /$valore/i){ $flag = 1; last; } }
Il costrutto <DB> legge una riga dal file descriptor indicato nella variabile di default $_. All'interno dell'istruzione while dà risultato falso quando si arriva a fine file, causando l'uscita dal loop.
L'istruzione:
$nome =~ /$valore/i
testa il contenuto della variabile $nome rispetto alla stringa
contenuta nella variabile $valore.
Il test è fatto considerando il contenuto di $valore come una
regular expression, del tipo di quelle che è possibile usare con
il grep.
La i alla fine indica che il test deve essere fatto in modo
case insensitive.
A questo punto non ci resta che presentare il risultato della nostra ricerca:
if($flag == 1){ print "Il signor/la signora <b>$nome</b><br>\n"; print "abita in <b>$via</b><br>\n"; print "Telefono: <b>$tel</b><p>\n"; }else{ print "Mi dispiace, ma non ho trovato alcun <b>$valore</b> nel database!\n"; } print "</body></html>\n";
Con poche righe di Perl abbiamo realizzato uno strumento abbastanza
sofisticato per la ricerca all'interno di un database.
Vale la pena notare che le ricerche possono essere condotte sia per
stringhe (ad esempio inserendo nel campo la stringa rossi),
sia per espressioni regolari (ad esempio inserendo nel campo la
stringa r.ss., che può trovare sia i dati del signor
Rossi, che del signor Russo).
Il programma per il momento restituisce i dati del primo soggetto
trovato nel database.
A rileggerci alla prossima puntata.
Per dubbi, congratulazioni, correzioni, insulti & altro scrivete a Nando Santagata.