La possibilità di interfacciare una base di dati relazionale con il Web è senza dubbio assai interessante in quanto unisce la potenza, l'affidabilità, la sicurezza dei moderni RDBMS (Relational Data Base Management System) con la facilità d'uso e la diffusione ormai universale degli strumenti di navigazione sia in Internet che nelle Intranet aziendali.
I campi di impiego di questa tecnologia sono numerosissimi: si pensi ad esempio alla possibilità di fornire ai cittadini l'accesso via Internet a dati di interesse pubblico o personale, oppure, all'interno di una azienda, alla gestione di archivi con interfacce basate sui normali, e molto «amichevoli», programmi di navigazione, con le quali si riducono al minimo i problemi di compatibilità e di installazione sui computer degli utilizzatori.
Le applicazioni Web si basano generalmente su una architettura a tre livelli (three-tier):
front-end o presentation tier o interfaccia: è il livello costituito dai moduli visualizzati con i browser sui computer clienti;
middle tier o logica applicativa: è il livello occupato dal servente Web o meglio da un Application server (ad esempio Tomcat) che sovrintende all'elaborazione dei dati, grazie a strumenti quali i CGI, PHP, ASP, servlet Java, Jsp e simili;
back-end o data tier o gestione dati persistenti: qui risiede il servente RDBMS.
Tale architettura è schematizzata nella figura 7.1.
|
Tra i tre componenti il dialogo avviene secondo il modello client-server, nel senso che l'interfaccia è cliente della logica applicativa che a sua volta è cliente della gestione dati persistenti.
Quando si parla di livelli architetturali delle applicazioni Web si fa spesso riferimento anche allo schema (pattern) MVC (Model View Controller) proposto originariamente con il linguaggio Smalltalk e ora molto diffuso per lo sviluppo di interfacce grafiche in applicazioni orientate agli oggetti.
Il suo uso è presente in numerose tecnologie attuali, anche in ambito Web: nei framework basati su PHP (Symfony, Zend Framework), su Ruby (Ruby on Rails), su Python (Django), su Java (Swing, Struts), o su .NET di Microsoft.
Con l'appena citato termine framework (piano di lavoro) si intende una struttura di supporto per la progettazione e realizzazione del software basata su librerie usabili con uno o più linguaggi e corredate da strumenti di aiuto alla programmazione come editor avanzati e debugger. I principali vantaggi dell'uso dei framework risiedono nella standardizzazione delle operazioni più comuni per lo sviluppo del software e nella possibilità di riutilizzare componenti già pronti senza doverli riprogettare e riscrivere ogni volta da zero. |
Anche lo schema MVC comprende tre livelli con compiti distinti:
model: fornisce i metodi per accedere ai dati usati dall'applicazione;
view: visualizza i dati e gestisce il dialogo con gli utenti;
controller: riceve, tramite la view, i comandi dell'utente e li esegue alterando eventualmente lo stato degli altri due componenti.
Lo schema non è in contrasto con quanto richiesto in una applicazione three-tier in quanto implica la separazione fra la logica applicativa che spetta al controller e al model, e l'interfaccia utente che è a carico della view.
In qualche caso si tende anzi a confondere lo schema MVC con le architetture a tre livelli; ciò non è corretto per almeno due motivi:
esso opera una separazione logica ulteriore nel solo livello di interfaccia organizzando le relative funzionalità e gestendo l'interazione con gli altri strati applicativi;
nelle applicazioni three-tier il livello interfaccia non comunica direttamente con il data tier e le comunicazione «transitano» sempre attraverso il middle tier; nello schema MVC invece abbiamo una interazione «triangolare» (vedi figura 7.2), con la view che invia gli aggiornamenti al controller, il controller che aggiorna il model, e la view che riceve aggiornamenti direttamente dal model.
|
Dal punto di vista storico, si può inoltre notare che l'architettura three-tier si presenta negli anni '90 nell'ambito delle applicazioni distribuite, con la separazione dei tre livelli su piattaforme distinte, mentre MVC nasce nel decennio precedente, presso lo Xerox PARC, inizialmente per applicazioni non distribuite.
Maggiori dettagli sulle architetture three-tier e, in generale, sulle applicazioni multi-livello, sono disponibili nel capitolo 10 dedicato alla programmazione distribuita.
Nei prossimi paragrafi esaminiamo più da vicino i metodi e gli strumenti utili alla gestione dei dati di un database tramite un'interfaccia Web.
Gli strumenti scelti per trattare questo argomento e per produrre qualche semplice esempio fanno tutti parte del software libero.
Ovviamente questa non è l'unica scelta che poteva essere fatta, data la presenza sul mercato di molte alternative proprietarie anche tecnicamente molto valide; la preferenza per questa categoria di programmi è però ampiamente motivata da tutta una serie di considerazioni per approfondire le quali si consiglia di consultare i numerosi documenti, dedicati a tali argomenti, sul sito <http://www.linuxdidattica.org>.
Qui elenchiamo brevemente solo alcuni dei motivi più importanti per la scelta di programmi e strumenti liberi:
motivi «etici»: opportunità di usare software libero anziché proprietario in ambito educativo;
motivi didattici: maggiore validità dei programmi liberi in ambito didattico (si pensi alla possibilità di sfruttare in tale contesto i sorgenti dei programmi);
motivi pratici e di legalità: disponibilità e di copie illimitate e legali dei programmi da far utilizzare a chi ne ha necessità in qualsiasi ambito (didattico e non);
motivi economici: gratuità del software;
motivi tecnologici: si parla di prodotti che sono all'avanguardia nel loro settore e molto diffusi anche in ambito professionale (ad esempio Apache nell'ambito dei serventi Web).
Gli strumenti cui si fa riferimento nel proseguo di questo paragrafo sono:
GNU/Linux (distribuzione Debian, o derivata, nel nostro caso Ubuntu-7.04) come sistema operativo delle macchine che fungono da serventi Web;
MySQL versione 5.0 e PostgreSQL versione 8.2 come RDBMS;
PHP versione 5 come linguaggio per il motore applicativo e l'interfaccia tra Web e le basi di dati.
Anche se in questa sede non vengono forniti dettagli sul reperimento e l'installazione dei pacchetti software necessari (come al solito si rimanda ad appositi testi o alla documentazione presente anche in Internet o ai manuali in linea in ambiente GNU/Linux), forniamo un elenco degli stessi facendo riferimento alla piattaforma Ubuntu-7.04:
apache2-mpm-prefork, modulo da usare nel caso si voglia avere un servente Web non basato sui thread ma sui processi come la vecchia versione Apache 1.3;
apache2-utils, programmi di utilità per Apache2;
apache2.2-common, moduli standard di Apache2;
libmysqlclient15off, librerie per la parte cliente di MySQL;
mysql-common, file richiesti da MySQL;
postgresql-client-common, gestore di versioni multiple del cliente PostgreSQL;
postgresql-common, gestore di versioni multiple o di cluster multipli del servente PostgreSQL;
libapache2-mod-php5, modulo per PHP5 per Apache2 (solo versione a processi);
php5, interprete PHP5;
php5-common, esempi e documentazione di PHP5;
php5-mysql, modulo per la connessione a una base di dati MySQL da script PHP5;
php5-pgsql, modulo per la connessione a una base di dati PostgreSQL da script PHP5;
php5-cli, interprete PHP5 da linea di comando (non essenziale);
phpmyadmin, applicazione Web, scritta in PHP, per gestire basi di dati MySQL (non essenziale);
phppgadmin, applicazione Web, scritta in PHP, per gestire basi di dati PostgreSQL (non essenziale).
Supponiamo di avere installato con successo tutto il software sulla macchina su cui effettuare le prove e di avere quindi il servente Apache che risponde all'indirizzo http://localhost
; dotato di tutto il necessario per l'esecuzione di script PHP5 e per l'interfacciamento a basi di dati MySQL e PostgreSQL.
Segnaliamo che è possibile lavorare con questi strumenti anche in ambiente MS-Windows (versioni superiori alle 9x o alla home) in quanto esistono pacchetti Apache, MySQL, PostgreSQL, PHP5 anche per questa piattaforma.
Inoltre esistono prodotti come EasyPHP o XAMPP installando i quali si hanno a disposizione in MS-Windows, già pronti all'uso: un servente Apache, un servente MySQL, un interprete PHP5 e l'applicazione phpmyadmin per la gestione via Web delle basi di dati, cui si accede collegandosi a http://localhost/mysql
.
A proposito dei due RDBMS prescelti segnaliamo come il primo sia nettamente più utilizzato nell'ambito delle applicazioni di rete: molti siti di commercio elettronico si appoggiano infatti su archivi gestiti con MySQL.
Per sottolineare questo fatto facciamo notare che è stato addirittura coniato un acronimo: LAMP, le cui lettere indicano i componenti che sono alla base di molte applicazioni Web esistenti: Linux, Apache, MySQL, PHP.
Tra i motivi della grande diffusione di MySQL ci sono l'estrema semplicità di configurazione e gestione e le buone prestazioni specialmente per basi di dati di dimensioni non elevate (come quelle su cui si basano solitamente i negozi in rete).
Tali pregi hanno superato, per gli sviluppatori, i difetti che erano presenti almeno nelle versioni precedenti alla 5.0 e che consistono principalmente nella non completa aderenza allo standard SQL (Structured Query Language), nell'assenza di viste logiche, di trigger, di selezioni annidate.
Nel caso di PostgreSQL, tali difetti non erano presenti neanche nelle prime versioni, ma questo non gli ha permesso di godere delle preferenze degli addetti ai lavori (non è il primo caso, in ambito informatico, in cui un prodotto superiore dal punto di vista tecnologico ha meno successo di uno con caratteristiche inferiori).
In queste dispense, per eliminare ogni possibile discussione, si è scelto di considerare entrambi i prodotti.
Nei due RDBMS la gestione fisica dei dati non è banale e non prevede la memorizzazione degli stessi in su un unico file per ogni base di dati, come avviene invece per altri gestori di basi di dati (ad esempio Access di Microsoft o SQLite); quindi, a differenza che in questi ultimi, per fare salvataggi di sicurezza dei dati di un archivio, non è sufficiente salvare un file, ma occorre utilizzare gli appositi strumenti messi a disposizione dai serventi RDBMS.
La trattazione su MySQL e PostgreSQL è ovviamente parziale: vengono introdotti solo i comandi necessari alla gestione di piccole basi di dati in vista di una successiva interrogazione con il linguaggio PHP; si considerano note le nozioni relative alle basi di dati relazionali in generale, al loro progetto (passando per i modelli concettuale e logico), alla sintassi e alle regole del linguaggio SQL. |
MySQL è un sistema di gestione di basi di dati relazionali multi-piattaforma distribuito da MySQL AB come software libero sotto licenza GPLv2 (General Public License version 2).
Una volta installato MySQL con successo si può iniziare ad usarlo senza grosse difficoltà; la directory predefinita a partire dalla quale vengono salvati gli archivi è /var/lib/mysql
e l'amministratore della base di dati è, almeno inizialmente, l'utente root (si rimanda al paragrafo 6.4.1 per quanto riguarda il modo in cui si possono acquisire i privilegi di tale utente in Ubuntu).
Prima di iniziare si deve attivare il demone mysqld con il comando (eseguito sempre con i diritti di root):
#
/etc/init.d/mysql start
Con comandi analoghi contenenti, invece di start, restart, stop, status si ottiene il riavvio, la fermata, lo stato corrente del demone.
Si tenga comunque presente che, in caso di corretta installazione del pacchetto, il demone viene inserito tra quelli attivati automaticamente all'accensione della macchina grazie alla presenza del file /etc/rc2.d/S19mysql
che è un collegamento simbolico a /etc/init.d/mysql
; in mancanza si può provvedere a definire tale collegamento con i comandi:
#
cd /etc/rc2.d
#
ln -s ../init.d/mysql .
Il servente MySQL risponde alle richieste sulla porta 3306; questa è l'impostazione predefinita modificabile intervenendo nel file di configurazione /etc/mysql/my.cnf
cambiando la riga:
|
Per verificare il funzionamento del servente MySQL possiamo collegarci ad esso come utente root eseguendo mysql che è il programma di interfaccia in modalità testuale.
Il comando prevede numerose opzioni, qui elenchiamo solo le più importanti:
-u: per indicare il nome dell'utente con il quale ci colleghiamo al servente;
-p: per immettere la password dell'utente;
Per avere tutte le informazioni sull'uso di questo comando si può consultare il manuale in linea eseguendo:
$
man mysql
Vediamo un esempio di comando per il collegamento a un servente MySQL:
$
mysql -h localhost -u root -p mysql
si riceve la richiesta di inserire la password per l'utente root e, se non ci sono errori, ci si collega alla base di dati mysql (quella che contiene tutte le informazioni amministrative del servente).
La stringa di invito dei comandi (prompt dei comandi) di MySQL ha il seguente aspetto:
mysql>
Per chiudere la connessione occorre digitare il comando:
mysql>
\q
Si può anche eseguire mysql senza alcuna opzione e senza indicazione della base di dati da utilizzare; in questo caso si effettua un collegamento alla macchina locale senza socket di rete ma usando il cosiddetto «Unix-domain socket», l'utente usato ha stesso nome di quello correntemente collegato al sistema GNU/Linux e la base di dati da utilizzare è indefinita.
Per cambiare la base di dati corrente si esegue il comando (l'utente deve avere i permessi di uso su di essa come mostrato più avanti):
mysql>
use nome_basi_dati
Per creare una base di dati si esegue:
mysql>
CREATE DATABASE nome_base_dati;
e per cancellarla:
mysql>
DROP DATABASE nome_base_dati;
Lavorare come utente root è quasi sempre inopportuno per motivi di sicurezza e questo vale anche nel caso di MySQL; vediamo allora come si crea un utente, chiamato dba, «normale» per GNU/Linux, ma dotato di tutti i privilegi necessari per essere l'amministratore del RDBMS.
Prima di tutto creiamo (da utente root) l'utente nel sistema GNU/Linux, supponendo ovviamente che non esista già:
#
adduser dba
inserendo la password, confermandola e rispondendo alle altre richieste di informazioni sull'utente che sono comunque non essenziali.
Poi colleghiamoci a MySQL e definiamo anche qui il nuovo utente:
mysql>
CREATE USER dba;
quindi assegniamogli i privilegi:
mysql>
GRANT ALL PRIVILEGES ON *.* TO dba@"%"
\
\ IDENTIFIED BY 'parola_segreta' WITH GRANT OPTION;
spieghiamo brevemente le parti salienti del comando:
«*.*» significa che ci riferisce a qualsiasi base di dati e qualsiasi tabella in essa contenuta;
"%" può essere sostituito da una indicazione più restrittiva dei nodi di rete da cui l'utente può collegarsi, ad esempio: 172.16.% oppure 172.16.1.1;
se si vuole dare la possibilità all'utente di collegarsi senza password (sconsigliato) basta eliminare la parte «IDENTIFIED BY ....»;
infine con «WITH GRANT OPTION» che è facoltativo, si da all'utente dba, visto che deve essere l'amministratore, la possibilità di assegnare i privilegi ad altri utenti.
A questo punto si può chiudere il collegamento come utente root e accedere da una console al sistema GNU/Linux come utente dba, oppure da utente root eseguire il cambio di identità con il comando:
#
su dba
Quindi ci si collega a MySQL:
$
mysql -h localhost -u dba -p mysql
Notiamo che in questo caso l'uso di «-u dba» è superfluo ma non provoca alcun errore.
Si possono creare altri utenti, altre basi di dati e assegnare i relativi privilegi; ad esempio per assegnarli all'utente fulvio per la base di dati prova:
mysql>
GRANT ALL PRIVILEGES ON prova.* TO fulvio@"%"
\
\IDENTIFIED BY 'parola_segreta';
Per togliere questi privilegi:
mysql>
REVOKE ALL PRIVILEGES ON prova.* FROM fulvio@"%";
Elenchiamo una serie di informazioni utili all'amministrazione e all'uso di un servente MySQL, sottolineando come esse siano solo una piccola parte di quelle necessarie e come presuppongano, in qualche caso, la conoscenza delle regole del linguaggio SQL:
accesso da remoto: nel file /etc/mysql/my.cnf
, commentare la riga:
|
o valorizzare opportunamente la riga:
|
o fare entrambe le cose.
cambiare password ad un utente:
mysql>
SET PASSWORD FOR nome_utente = PASSWORD('parola_segreta');
ottenere l'aiuto rispettivamente per i comandi di mysql e di SQL:
mysql>
help
mysql>
help comando
connettersi ad altra base di dati:
mysql>
use nome_base_dati
ottenere la lista delle basi di dati gestite dal servente:
mysql>
SHOW DATABASES;
ottenere la lista delle tabelle presenti nella base di dati:
mysql>
SHOW TABLES;
visualizzare la struttura di una tabella:
mysql>
DESCRIBE nome_tabella
cancellare un utente:
mysql>
DROP USER nome_utente
salvare una base di dati (comprese le definizioni delle strutture delle tabelle) in un file:
$
mysqldump nome_base_dati > nome_file
il comando mysqldump prevede le opzioni «-u», «-p», «-h», con lo stesso significato visto per mysql, e tante altre per le quali si rimanda alla consultazione del manuale in linea;
per ripristinare in una base dati, appositamente creata, il contenuto di un file di salvataggio si può usare il comando:
$
mysql nome_base_dati < nome_file
Si noti che le parole riservate del linguaggio SQL si scrivono in maiuscolo anche se vengono riconosciute pure in minuscolo e che i comandi SQL, a differenza di quelli di mysql, devono sempre terminare con «;». |
Creiamo, come utente dba, con le modalità mostrate in precedenza, l'utente fulvio per MySQL e una base di dati con stesso nome assegnando gli opportuni privilegi.
Colleghiamoci poi a MySQL come utente fulvio e creiamo in tale base di dati una tabella di nome rubrica per le successive prove di gestione via Web con PHP; la tabella contiene alcuni indirizzi e numeri telefonici e ha una chiave costituita da codice auto-incrementante:
$
mysql -h localhost -u fulvio -p fulvio
mysql>
CREATE TABLE rubrica(codice INT AUTO_INCREMENT, cognome
\
\VARCHAR(20), nome VARCHAR(20),
->
indirizzo VARCHAR(40), telefono VARCHAR(15), data_nas DATE,
\
\email VARCHAR(30), PRIMARY KEY (codice));
come si vede il comando può essere spezzato su più righe; le righe successive alla prima sono righe di continuazione come evidenziato anche dalla stringa di invito che cambia aspetto.
Il comando viene considerato concluso quando si incontra il simbolo «;».
Inseriamo alcune registrazioni all'interno della tabella con i comandi:
mysql>
INSERT INTO rubrica (cognome, nome, indirizzo, telefono,
\
\data_nas, email)
->
VALUES('Paperino', 'Paolino', 'via Roma 1 Paperopoli',
->
'010011234567','1980-01-01','paperino.paolino@maxplanck.it');
mysql>
INSERT INTO rubrica (cognome, nome, indirizzo, telefono,
\
\data_nas, email)
->
VALUES('Rossi', 'Mario', 'via Roma 34 Treviso',
->
'04220101010','1981-01-01','rossi.mario@maxplanck.it');
Si noti come i valori del campo codice non vengano inseriti perché, essendo esso auto-incrementante, viene opportunamente valorizzato dal servente MySQL.
Verifichiamo i dati inseriti con il comando:
mysql>
SELECT * FROM rubrica;
che dovrebbe dare il risultato mostrato in figura 7.6.
Le stesse operazioni possono essere fatte mediante il più amichevole programma phpmyadmin utilizzabile, dopo l'installazione e la configurazione per le quali si rimanda alla documentazione del programma stesso, collegandosi all'URI: http://localhost/phpmyadmin
.
PostgreSQL è un sistema di gestione basi di dati relazionali multi-piattaforma molto avanzato e quasi del tutto rispondente allo standard SQL; è stato sviluppato originariamente dal dipartimento di informatica dell'Università di Berkeley in California ed è distribuito come software libero con una licenza speciale.
Una volta installato PostgreSQL con successo si può iniziare ad usarlo senza grosse difficoltà; la directory predefinita a partire dalla quale vengono salvati gli archivi è /var/lib/postgresql/8.2/main/
e l'amministratore della base di dati è l'utente postgres al quale è consigliabile assegnare una password, operazione che deve essere svolta dall'utente root di Linux (si rimanda al paragrafo 6.4.1 per quanto riguarda il modo in cui si possono acquisire i privilegi di tale utente in Ubuntu).
Prima di iniziare si deve attivare il demone postgres con il comando (eseguito sempre con i diritti dell'utente root):
#
/etc/init.d/postgresql-8.2 start
Con comandi analoghi contenenti, invece di start, restart, stop, status si ottiene il riavvio, la fermata, lo stato corrente del demone.
Si tenga comunque presente che, in caso di corretta installazione del pacchetto, il demone viene inserito tra quelli attivati automaticamente all'accensione della macchina grazie alla presenza del file /etc/rc2.d/S19postgresql-8.2
che è un collegamento simbolico a /etc/init.d/postgresql-8.2
; in mancanza si può provvedere a definire tale collegamento con i comandi:
#
cd /etc/rc2.d
#
ln -s ../init.d/postgresql-8.2 .
Il servente PostgreSQL risponde alle richieste sulla porta 5432; questa è l'impostazione predefinita modificabile intervenendo nel file di configurazione /etc/postgresql/8.2/main/postgresql.conf
cambiando la riga:
|
La prima volta che viene eseguito il programma di amministrazione delle basi di dati, vengono creati i file fondamentali per la loro gestione.
Per verificare il buon funzionamento del servente PostgreSQL creiamo (da utente root) un utente nel sistema GNU/Linux con nome, ad esempio, fulvio, supponendo ovviamente che non esista già:
#
adduser fulvio
Poi ci si connette su una console come utente postgres, oppure da utente root si esegue il cambio di identità con il comando:
#
su postgres
e si crea l'utente fulvio anche per PostgreSQL:
$
createuser fulvio
Il sistema pone a questo punto delle domande relative al nuovo utente: è opportuno rispondere in modo che non sia un superuser e che sia abilitato a creare basi di dati ma non altri utenti.
Se si deve eliminare un utente PostgreSQL il comando (da eseguire sempre come utente postgres) è:
$
dropuser nome_utente
Una volta creato l'utente desiderato (fulvio) possiamo accreditarci con le sue credenziali ed eseguire psql che è il programma di interfaccia, in modalità testuale, verso il servente PostgreSQL.
Il comando prevede numerose opzioni, qui elenchiamo solo le più importanti:
-U: per indicare il nome dell'utente con il quale ci colleghiamo al servente;
-W: per immettere la password dell'utente;
Per avere tutte le informazioni sull'uso di questo comando si può consultare il manuale in linea eseguendo:
$
man psql
Vediamo un esempio di comando per il collegamento a un servente PostgreSQL:
$
psql -h localhost -U fulvio -W template1
si riceve la richiesta di inserire la password per l'utente fulvio e, se non ci sono errori, ci si collega alla base di dati template1 (una di quelle di esempio già presenti sul servente).
La stringa di invito dei comandi (prompt dei comandi) di PostgreSQL contiene il nome della base di dati corrente e ha il seguente aspetto:
template1=>
Per chiudere la connessione occorre digitare il comando:
template1=>
\q
Si può anche eseguire psql senza alcuna opzione e senza indicazione della base di dati da utilizzare; in questo caso si effettua un collegamento alla macchina locale senza socket di rete ma usando il cosiddetto «Unix-domain socket», l'utente usato ha stesso nome di quello correntemente collegato al sistema GNU/Linux e la base di dati da utilizzare ha lo stesso nome dell'utente.
Questa base di dati deve ovviamente esistere e l'utente deve potersi collegare senza inserire password, altrimenti il tentativo di collegamento non ha successo.
Un utente può eventualmente creare la propria base di dati predefinita (o qualsiasi altra) nel modo seguente:
$
createdb nome_base_dati
Per cancellare una base di dati il comando è invece:
$
dropdb nome_base_dati
Elenchiamo a questo punto una serie di informazioni utili all'amministrazione e all'uso di un servente PostgreSQL, sottolineando, ancora una volta, come esse siano solo una piccola parte di quelle necessarie e come presuppongano la conoscenza delle regole del linguaggio SQL:
abilitare la connessione da clienti remoti: nel /etc/postgres/8.2/main/postgresql.conf
valorizzare opportunamente la riga:
|
che è inizialmente commentata (il valore per difetto è comunque localhost);
aggiungere poi in /etc/postgres/8.2/main/pg_hba.conf
una riga come questa:
|
oppure, se si vuole limitare l'accesso con password MD5:
|
eventualmente commentare la riga:
|
se si vuole disattivare la possibilità di collegarsi in locale al servente PostgreSQL, senza immettere password, per gli utenti del sistema GNU/Linux;
vedere i commenti presenti in entrambi i file e la documentazione di PostgreSQL per avere maggiori dettagli;
amministrare un utente: collegarsi come utente postgres e eseguire:
$
psql template1
poi:
template1=>
UPDATE pg_authid SET rolpassword='parola_segreta'
\
\WHERE rolname='nome_utente';
per le versioni di PostgreSQL precedenti alla 8.1 il comando è invece:
template1=>
UPDATE pg_shadow SET passwd='parola_segreta'
\
\WHERE usename='nome_utente';
cambiare password ad un utente:
template1=>
ALTER user nome_utente WITH password 'parola_segreta';
assegnare privilegi per una tabella:
template1=>
GRANT [ALL] [priv] ON nome_tabella TO public;
in questo caso i privilegi (tutti se ALL, o quelli specificati) vengono assegnati allo schema public quindi a tutti gli utenti, in alternativa si può specificare il nome di un utente;
togliere privilegi per una tabella ad un utente:
template1=>
REVOKE [ALL] [priv] ON nome_tabella FROM nome_utente;
creare utente con password criptata MD5 (sempre da utente postgres):
$
createuser -e nome_utente
ottenere l'aiuto rispettivamente per i comandi di psql e di SQL:
template1=>
\?
template1=>
\h [comando]
premere [q] per uscire dalla visualizzazione dell'aiuto;
connettersi ad altra base di dati:
template1=>
\c nome_base_dati
ottenere la lista delle basi di dati gestite dal servente:
template1=>
\l
ottenere la lista delle tabelle presenti nella base di dati:
template1=>
\dt
visualizzare la struttura di una tabella:
template1=>
\d nome_tabella
salvare una base di dati (comprese le definizioni delle strutture delle tabelle) in un file:
$
pg_dump nome_base_dati > nome_file
il comando pg_dump prevede le opzioni «-U», «-W», «-h», con lo stesso significato visto per psql, e tante altre per le quali si rimanda alla consultazione del manuale in linea;
per ripristinare in una base dati, appositamente creata, il contenuto di un file di salvataggio si può usare il comando pg_restore (vedere manuale in linea) o, più semplicemente, il comando:
$
psql -d nome_base_dati -f nome_file
Si può notare che, ancora una volta, le parole riservate del linguaggio SQL si scrivono in maiuscolo, anche se non è obbligatorio, e che i comandi SQL, a differenza di quelli di psql, devono sempre terminare con «;». |
Creiamo, come utente fulvio nella base di dati omonima, una tabella di nome rubrica per le successive prove di gestione via Web con PHP; la tabella contiene alcuni indirizzi e numeri telefonici e ha una chiave costituita da codice auto-incrementante:
fulvio=>
CREATE TABLE rubrica(codice serial, cognome VARCHAR(20),
\
\nome VARCHAR(20),
fulvio(>
indirizzo VARCHAR(40), telefono VARCHAR(15),
\
\data_nas DATE, email VARCHAR(30));
come si vede il comando può essere spezzato su più righe; le righe successive alla prima sono righe di continuazione come evidenziato anche dalla stringa di invito che cambia aspetto.
Il comando viene considerato concluso quando si incontra il simbolo «;».
Inseriamo alcune registrazioni all'interno della tabella con i comandi:
fulvio=>
INSERT INTO rubrica (cognome, nome, indirizzo,
\
\delefono, data_nas, email)
fulvio->
VALUES('Paperino', 'Paolino', 'via Roma 1 Paperopoli',
fulvio(>
'010011234567','1980-01-01','paperino.paolino@maxplanck.it');
fulvio=>
INSERT INTO rubrica (cognome, nome, indirizzo,
\
\telefono, data_nas, email)
fulvio->
VALUES('Rossi', 'Mario', 'via Roma 34 Treviso',
fulvio(>
'04220101010','1981-01-01','rossi.mario@maxplanck.it');
Si noti come i valori del campo codice non vengano inseriti perché, essendo esso auto-incrementante, viene opportunamente valorizzato dal servente PostgreSQL.
Verifichiamo i dati inseriti con il comando:
fulvio=>
SELECT * FROM rubrica;
che dovrebbe dare il risultato mostrato in figura 7.12.
Le stesse operazioni possono essere fatte mediante il più amichevole programma phppgadmin utilizzabile, dopo l'installazione e la configurazione per le quali si rimanda alla documentazione del programma stesso, collegandosi all'URI: http://localhost/phppgadmin
.
Il PHP (inizialmente Personal Home Pages, adesso PHP Hypertext Preprocessor) nasce nel 1995 per mano di Rasmus Lerdorf allo scopo di semplificare la gestione di alcune pagine HTML.
La primissima versione era originata dal alcuni script Perl ma successivamente Lerdorf ne scrisse una versione in linguaggio c.
Le tappe più importanti della successiva evoluzione sono state:
nel giugno 1998 esce PHP3 con il nuovo «motore» Zend (frutto del lavoro di Zeev Suraski e Andi Gutmans), il supporto per molte basi di dati (oltre a quello già presente per mSQL, PostgreSQL, MySQL) e la possibilità di essere usato su macchine MS-Windows; PHP risulta installato in circa il 10% dei domini esistenti;
nel maggio 2000 esce PHP4 e la licenza passa da GPL a licenza speciale (PHP); viene inserito il supporto per le sessioni;
nel 2004 è la volta di PHP5 che, grazie al motore Zend versione 2 estende il linguaggio secondo il modello della programmazione ad oggetti; inoltre viene introdotto il supporto all'XML e ai Web Services; attualmente PHP è installato su oltre il 30% dei serventi Web.
Si tratta di un linguaggio interpretato, multi-piattaforma, che viene utilizzato principalmente per dotare di capacità elaborativa i documenti HTML (anche se esiste la possibilità di eseguire script da linea di comando grazie al pacchetto php5-cli).
Le istruzioni PHP sono incorporate all'interno dei sorgenti HTML e vengono eseguite dal lato servente grazie alla presenza del motore Zend.
Il linguaggio si presta particolarmente per la scrittura di applicazioni Web per l'amministrazione di basi di dati; i gestori di basi di dati supportati sono moltissimi e fra essi troviamo MySQL, PostgreSQL, Oracle, Sybase, Informix.
Una trattazione completa del linguaggio PHP non rientra negli scopi di queste dispense; ci limitiamo a illustrare le sue caratteristiche di base, aiutandoci con degli esempi, per essere poi in grado di realizzare dei banali interfacciamenti a basi di dati MySQL e PostgreSQL.
Qualche dettaglio in più viene fornito sulla gestione delle sessioni e sulla prevenzione della «SQL injection» che sono argomenti molto importanti ma non sempre considerati in modo adeguato nei testi, nei manuali e in genere nella documentazione riguardante l'uso di PHP.
I comandi PHP si inseriscono all'interno di un documento HTML in qualunque posizione ma si tengono separati dal resto del sorgente racchiudendoli tra le stringhe ;<?php e ?>.
I documenti contenenti comandi PHP devono avere estensione .php e non .html; il viceversa non è vero: si possono cioè scrivere documenti privi di istruzioni PHP il cui nome ha estensione .php senza temere alcun malfunzionamento (semplicemente, malgrado l'estensione, essi non vengono elaborati dal motore Zend di PHP).
Vediamo subito un esempio che permette anche di verificare il buon funzionamento del PHP sulla nostra macchina: definiamo nella directory radice del servente Web (solitamente /var/www/
) un file chiamato phpinfo.php
contenente questa unica riga:
|
Se si apre il documento collegandosi a http://localhost/phpinfo.php
e se tutto funziona correttamente, si ottiene una risposta, mostrata parzialmente nella figura 7.14, contenente numerose informazioni riguardanti il PHP, il servente Web ed altro ancora.
Il linguaggio PHP può essere utilizzato anche indipendentemente dalla connessione a basi di dati, come evidenziato dal seguente esempio in cui vediamo un documento HTML per con un modulo per l'immissione di dati, arricchito con alcuni comandi PHP; i dati di input vengono passati ad un altro file e trattati ancora con istruzioni PHP.
Ecco il sorgente del primo documento:
|
Come al solito i numeri di riga sono stati aggiunti per facilitare la spiegazione delle varie parti del sorgente; prima però di commentarlo in dettaglio forniamo alcune informazioni sulla sintassi dei comandi PHP che ha grandi somiglianze con quella del linguaggio c:
le istruzioni PHP si scrivono in minuscolo e si concludono sempre con «;»;
i blocchi di istruzioni sono delimitati da «{» e «}»
i commenti si inseriscono con «//» su una riga singola oppure compresi tra «/*» e «*/» anche su più righe
gli operatori e molte istruzioni (ad esempio if, for, while) sono gli stessi del linguaggio c.
Altre caratteristiche il linguaggio PHP le ha invece ereditate dal Perl:
i nomi delle variabili devono iniziare con il simbolo «$»
nelle istruzioni di output le variabili vengono interpolate se contenute tra doppi apici e lasciate inalterate se tra apici singoli;
c'è il supporto alle espressioni regolari;
esiste l'istruzione foreach e si possono usare vettori associativi.
Notiamo inoltre che, come il Perl, anche PHP è un linguaggio «debolmente tipizzato»; ciò significa che non occorre dichiarare il tipo delle variabili prima di utilizzarle e che le conversioni di tipo eventualmente necessarie vengono fatte, quando possibile, automaticamente a tempo di esecuzione.
Vediamo adesso qualche dettaglio riguardante il documento precedente:
nella prima parte (righe 9-18) vengono visualizzate informazioni sulla connessione grazie all'istruzione echo e all'uso di alcune variabili di ambiente; il resto del documento contiene la definizione del modulo per l'immissione di semplici dati anagrafici;
le variabili di ambiente di cui sopra fanno parte del gruppo di variabili messe a disposizione dal servente HTTP (vedi paragrafo 6.7) e sono utilizzabili dal PHP grazie al vettore associativo $_SERVER;
un vettore associativo è un vettore contenente una serie di coppie chiave-valore cui si accede specificando la chiave dell'elemento cercato invece di un indice come nei vettori tradizionali; quindi, ad esempio, a riga 14, riferendosi alla chiave 'SERVER_ADDR'. si ottiene il rispettivo valore, cioè l'indirizzo IP del servente;
a riga 10 abbiamo una istruzione PHP commentata che è stata inserita per poter accennare al vecchio metodo con cui venivano gestite le variabili di ambiente in PHP: fino alla versione 4.2 era possibile accedere direttamente a tali variabili, come si vede nell'istruzione commentata, ed era addirittura possibile usare le variabili provenienti da un modulo semplicemente facendo riferimento al loro nome preceduto da un «$» (questo fatto è illustrato nel listato del prossimo documento); nelle versioni più recenti di PHP tutto questo non è più possibile a meno che non si cambi nel file di configurazione /etc/php5/apache2/php.ini
la riga:
|
in:
|
cosa comunque altamente sconsigliata per motivi di sicurezza; in luogo di questo accesso diretto alle variabili, ormai deprecato, si devono utilizzare i vettori associativi «super-globali» (cioè accessibili da qualsiasi punto di un sorgente PHP) di cui un esempio è $_SERVER e altri molto importanti sono $_POST e $_GET introdotti nel prossimo documento.
L'aspetto del documento è quello mostrato nella figura 7.18.
Si noti che i dati del modulo vengono inviati a modulo1-ris.php
che risiede nella stessa directory del documento di partenza; qui infatti non è obbligatorio definire una directory apposita, come la /cgi-bin
usata per i CGI, dove memorizzare gli script PHP.
Il file per l'elaborazione dei dati e la creazione della risposta non è altro che un ulteriore pagina HTML corredato da istruzioni PHP; il suo contenuto è:
|
La prima parte ricalca quella del primo documento; successivamente vengono visualizzati i dati inviati dal modulo.
Notiamo subito che, a differenza di quanto avviene con i CGI, non è necessario far precedere il contenuto della risposta dall'intestazione HTTP e dalla riga vuota in quanto questo a questo provvede automaticamente il motore PHP nel momento in cui viene incontrata la prima istruzione di output (echo o print()). |
Commentiamo più in dettaglio le parti più significative del sorgente:
la riga 20 è commentata e mostra come si potrebbe accedere direttamente alle variabili del modulo se fosse attivata l'opzione register_globals; la cosa, come detto, è decisamente da evitare e quindi si usa il vettore super-globale $_POST oppure $_GET in base a quale è il metodo di invio dei dati (righe dalla 22 alla 33); in alternativa si potrebbe usare il vettore super-globale $_REQUEST che contiene i dati provenienti dal modulo qualunque sia il metodo utilizzato per l'invio;
alle righe 35 e 36 vediamo l'uso della funzione print() al posto della echo;
la riga 37 può essere considerata speculare rispetto alle altre righe in cui si emette un output in quanto in essa abbiamo la funzione di uscita del PHP che si preoccupa di emettere una parte di codice HTML oltre al valore di una variabile; nelle altre righe abbiamo invece l'uscita PHP inserita all'interno dei normali tag HTML (separata ovviamente dalle stringhe «<?php» e «?>»); i due modi di far convivere il codice HTML con le istruzioni PHP sono ugualmente efficaci e la preferenza dipende dalle caratteristiche del documento di risposta o dell'elaborazione che si sta effettuando: si può addirittura scrivere un file PHP in cui tutto il contenuto della risposta, compresi i tag HTML, viene emesso all'interno di istruzioni echo o funzioni print() nel codice PHP;
sempre osservando le righe 35, 36 e 37 possiamo sottolineare il concetto di «espansione» di una variabile: quando si usa una variabile in output ad essa viene sostituito il suo valore anche se è contenuta fra doppi apici come una costante stringa; per evitare questo comportamento occorre usare gli apici singoli come mostrato nella riga 36 che è commentata; il suo effetto sarebbe quello di emettere la stringa "$cognome" piuttosto che il valore di tale variabile;
alle righe 41-49 si cerca di determinare con quale browser l'utente ha compilato il modulo e inviato i dati: a riga 42 viene definita una variabile con il risultato della funzione strstr() definita sulla stringa contenuta nella variabile di sistema HTTP_USER_AGENT e sulla stringa "Mozilla"; il risultato è la stringa ottenuta da quella di partenza escludendo la parte precedente la parola "Mozilla"; nelle righe 43-48 ci sono alcune istruzioni condizionali la cui sintassi è esattamente uguale a quella del linguaggio c (si noti ad esempio l'uso del simbolo «!» per la negazione) in cui si usa ancora la funzione strstr(); la logica complessiva è la seguente: se $var1 è diversa dalla stringa vuota e non contiene la stringa "compatible" stiamo usando il programma di navigazione Mozilla o uno da esso derivato, altrimenti se contiene la stringa "MSIE" stiamo usando Internet Explorer, altrimenti stiamo usando un programma di navigazione diverso da entrambi.
L'aspetto della risposta è quello mostrato nella figura 7.20.
Se il modulo di provenienza dei dati prevede la possibilità di più valori per uno stesso campo (caso di un controllo <select> con attributo multiple), occorre attribuire al campo un nome terminante con «[]» in modo che in PHP siano poi disponibili i valori immessi all'interno di un vettore; se ad esempio il nome nel modulo è scelte[] in PHP abbiamo che $_REQUEST['scelte'] è un vettore e non un singolo valore. |
Le istruzioni PHP possono essere anche utilizzate per controllare la correttezza dei dati inseriti in un modulo.
In certi casi però controlli di questo tipo vengono svolti direttamente sulla macchina cliente con codice eseguito su quest'ultima usando ad esempio JavaScript.
Questa soluzione presenta l'indubbio vantaggio di far diminuire il carico di lavoro del servente ma non è sempre praticabile: se ad esempio si deve controllare la presenza di un codice prodotto in un archivio residente sulla macchina remota, non si può fare a meno di utilizzare un modulo di elaborazione che venga eseguito su quest'ultima e cioè lato servente.
Inoltre l'utente che sta usando la procedura potrebbe aver disabilitato l'esecuzione di codice JavaScript sul suo programma di navigazione, rendendo così inefficaci i controlli inseriti sul lato cliente.
Facendo riferimento all'esempio del paragrafo precedente, supponiamo di voler controllare che il campo denominato email sia non vuoto e sia un indirizzo di posta elettronica scritto correttamente; il controllo viene fatto usando istruzioni PHP da aggiungere ovviamente al file modulo1_ris.php
.
Vengono mostrate le singole istruzioni da utilizzare lasciando al lettore l'individuazione delle opportune modifiche alla logica di elaborazione necessarie al loro inserimento nel file in oggetto.
Il controllo sulla valorizzazione del campo email può essere fatto con la funzione strlen() che restituisce la lunghezza in byte dell'argomento:
|
Per quanto riguarda invece la correttezza dell'indirizzo di posta possiamo supporre che esso debba avere la seguente forma:
almeno 2 caratteri diversi da spazio e da «@»;
il simbolo «@»;
almeno un carattere diverso da spazio, da punto e da «@»;
un punto;
almeno altri due caratteri diversi da spazio, da punto e da «@».
Per controllare che la variabile sia aderente a questo formato (nel gergo tecnico si dice che si ha un match tra essa e la sequenza di cui sopra, chiamata pattern) si utilizza uno strumento molto efficace, proposto originariamente per il linguaggio Perl, ma ormai esportato in molti altri linguaggi: le espressioni regolari (regexp).
Le espressioni regolari sono tanto potenti quanto ostiche, specialmente per i non esperti, anche a causa della loro sintassi davvero succinta e per niente amichevole.
Una loro trattazione, anche solo superficiale, richiederebbe probabilmente una dispensa apposita; ci limitiamo quindi a pochi esempi, fra i quali includiamo la soluzione da adottare per il controllo del nostro indirizzo di posta, confidando che questo piccolo «assaggio» possa spingere chi necessita di approfondimenti a consultare la vasta mole di documentazione reperibile sull'argomento.
La funzione da usare per le espressioni regolari è preg_match() che, nella forma più comune ha due argomenti: il pattern e la stringa da controllare; se la stringa soddisfa il pattern la funzione ritorna vero, altrimenti ritorna falso.
Ecco dunque l'istruzione per effettuare il controllo di correttezza sull'indirizzo di posta elettronica:
|
Nella tabella seguente cerchiamo di fornire una spiegazione del pattern scandendolo da sinistra a destra e sottolineando ancora una volta che la mole di nozioni trascurate nella spiegazione è nettamente superiore a quella delle nozioni presenti:
|
Come ulteriore esempio supponiamo di voler controllare la validità del campo cognome del modulo del paragrafo precedente; la regola che deve essere soddisfatta è che siano presenti solo caratteri alfabetici minuscoli (eccetto la prima maiuscola), il carattere spazio e l'apostrofo (semplifichiamo leggermente la questione imponendo che nei cognomi composti sia maiuscolo solo il primo carattere).
|
In questo esempio vediamo anche l'uso della funzione stripslashes() che permette di eliminare il carattere «\» aggiunto automaticamente nell'input per mascherare eventuali «'».
Esiste anche la funzione addslahes() che permette invece di aggiungere il carattere «\» prima di caratteri che possono causare problemi se presenti in campi da inserire in una base di dati; si tratta dei caratteri «'», «"» e «\».
Anche in questo caso utilizziamo una tabella per la spiegazione del pattern per il controllo del cognome:
|
Infine ipotizziamo di dover controllare un numero di telefono (contenuto nella variabile $telefono) imponendo che debba essere costituito da un insieme di due, tre o quattro cifre, seguite dal segno meno e da almeno altre 4 cifre.
|
Ed ecco la tabella per la spiegazione del pattern:
|
In questo paragrafo prendiamo in esame un argomento molto interessante: la gestione delle sessioni in PHP; prima di entrare nei dettagli e di illustrare qualche esempio è però opportuno introdurre il concetto di stato di una applicazione e le motivazioni per cui le sessioni sono importanti per la gestione dello stato nelle applicazioni Web.
Quando si utilizza una normale applicazione su un singolo sistema di elaborazione (quindi senza coinvolgere la rete come accade invece per le applicazioni Web) non si riesce a cogliere immediatamente l'esistenza di due entità al suo interno:
la parte dell'applicazione che svolge le funzioni di interfaccia con l'utente;
la parte di logica di programmazione.
In molti casi questi due componenti appaiono indistinti, ma ogni volta che l'utente interagisce con l'interfaccia (ad esempio inserendo dei dati o effettuando delle scelte su un menu) essa comunica con la logica di programmazione la quale svolge certe elaborazioni ed eventualmente fornisce una risposta ancora all'interfaccia utente.
Possiamo anche dire che ogni azione svolta con l'interfaccia utente provoca un cambiamento nello «stato» dell'applicazione, cioè alla condizione in cui si trovano, istante per istante, i dati e le variabili dell'applicazione stessa.
Questo cambiamento di stato può essere provocato anche da altri fattori indipendenti dalle azioni dell'utente e previsti direttamente nella logica di programmazione.
Il punto interessante è però il seguente: mentre nelle applicazioni tradizionali la comunicazione tra interfaccia e logica di programmazione avviene con continuità e quindi la gestione dei cambiamenti di stato non è problematica e talvolta non viene neppure affrontata in modo esplicito, nelle applicazioni Web siamo costretti ad affrontare il problema in quanto il protocollo HTTP è «privo di stato».
Questo significa che non esiste alcun meccanismo automatico che tenga traccia dei cambiamenti di stato degli oggetti dell'interfaccia utente (i moduli visualizzati con il browser sulle macchine clienti) e li comunichi alla logica di programmazione (ad esempio script PHP eseguiti sul servente) e viceversa.
Nelle applicazioni Web la comunicazione tra interfaccia e logica di programmazione non è automatica ma guidata dall'utente e talvolta può essere anche molto lenta.
Inoltre uno script della logica di programmazione (supponiamo scritto in PHP) viene attivato solo al momento della richiesta dell'utente e dell'invio dei dati e quando termina vengono persi i valori di tutti i dati e di tutte le variabili usate nell'elaborazione; anche se l'utente ha l'impressione che l'applicazione sia ancora attiva (perché vede comparire sul suo browser una qualche risposta) in effetti nessun programma è in quel momento in esecuzione ed una nuova attivazione dello script non può avere a disposizione i valori dei dati dell'elaborazione precedente.
Questo naturalmente avviene a meno che non si individui un meccanismo che permetta di mantenere lo stato nell'ambito di una applicazione che usa il protocollo HTTP facendo in modo che tutti i dati dell'applicazione (o almeno quelli che interessano) siano persistenti.
Si tratta quindi di trovare il modo di attivare e gestire una «sessione di lavoro» che consiste in tutte le interazioni che l'utente svolge dal momento in cui si collega la prima volta all'applicazione residente sul servente (eventualmente accreditandosi), al momento in cui chiude il collegamento oppure scade un contatore di tempo di inattività.
Esistono vari metodi per mantenere lo stato usando il linguaggio PHP; illustriamoli brevemente eccetto quello considerato migliore (sessioni native in PHP) che viene approfondito maggiormente:
campi nascosti nei moduli: si tratta di utilizzare controlli <input> di tipo "hidden" per comunicare all'applicazione i dati che devono essere conservati tra una attivazione e l'altra di uno script; questo metodo è utilizzabile solo in presenza di un esiguo volume di dati da rendere persistenti;
accodamento alla stringa dell'URI: si tratta di passare i dati all'applicazione accodandoli all'URI del ricevente come accade quando si invia un modulo con metodo "get"; in questo caso si è soggetti alle stesse limitazioni già discusse nel paragrafo riguardante l'invio dei dati dei moduli HTML (paragrafo 6.8);
uso di basi di dati: i valori delle variabili possono essere memorizzati in una tabella di una base di dati; anche questa soluzione ha una controindicazione: il sovraccarico di lavoro per il servente per effettuare gli accessi alla base di dati;
uso dei cookies (biscottini): i cookies sono un modo per memorizzare sul computer cliente un piccolo quantitativo di dati che devono persistere nell'ambito di una sessione di lavoro; sebbene l'idea non sia tecnicamente da scartare, è bene non fare troppo affidamento su questa soluzione perché, avendo i cookies acquisito una cattiva fama presso il pubblico dei navigatori in Internet (si può abusare del loro uso per acquisire ad esempio informazioni sulle preferenze degli utenti a loro insaputa), spesso vengono addirittura disattivati con apposite scelte nella configurazione del browser; eventualmente quindi è il caso di usarli solo per compiti utili ma non fondamentali per il funzionamento di una procedura Web (ad esempio per memorizzare le preferenze estetiche di un utente relativamente a un certo sito);
sessioni native in PHP: si tratta senza dubbio della soluzione migliore e quindi le dedichiamo un piccolo approfondimento nel prossimo paragrafo.
L'idea fondamentale che sta alla base della gestione delle sessioni in PHP è quella di memorizzare i dati, che devono rimanere persistenti nell'ambito di queste ultime, sul servente; in questo modo si elimina la necessità di comunicare i dati stessi al cliente con i conseguenti problemi di riservatezza o di ingombro.
Al cliente viene comunque assegnata una chiave chiamata «identificatore di sessione» che gli permette di identificarsi univocamente per una certa sessione e di vedersi associare i relativi dati persistenti.
In PHP la chiave di sessione si chiama SID (Session Identifier) ed è un numero intero associato ad una e una sola sessione.
Schematizzando al massimo la gestione di una sessione nativa in PHP può quindi essere così riassunta:
quando si crea la sessione (con opportuna funzione illustrata più avanti) il servente genera il relativo SID e lo comunica al cliente;
le variabili registrate per quella sessione (anche qui con apposita funzione) vengono memorizzate nella memoria di massa del servente in un file identificabile in base al numero di sessione (a volte il nome del file è proprio il SID o almeno lo contiene);
quando il cliente deve accedere alle variabili registrate per la sessione, basta che comunichi al servente il SID;
se è possibile usare i cookies il SID viene gestito sul cliente grazie ad essi, altrimenti viene passato al servente ponendolo in coda all'URI delle richieste; la cosa fondamentale è però che di tutto questo si occupa il motore PHP in modo trasparente per lo sviluppatore che si deve preoccupare solo di usare in modo adeguato le funzioni di avvio e chiusura di una sessione e di registrazione e lettura delle relative variabili.
La figura 7.28 rappresenta quanto appena illustrato.
Le funzioni da usare per gestire le sessioni in PHP sono le seguenti:
session_start(): serve ad avviare una sessione;
session_register('nome_var'): serve a registrare la variabile nome_var (da indicare senza «$» iniziale e tra apici o virgolette); le variabili di sessione registrate sono disponibili nel vettore associativo super-globale $_SESSION;
session_unregister('nome_var'): serve a eliminare la registrazione della variabile nome_var (da indicare senza «$» iniziale e tra apici o virgolette);
session_destroy(): serve a chiudere la sessione; una sessione viene chiusa automaticamente terminando l'esecuzione del browser da cui si è generata oppure dopo 1440 secondi (24 minuti) di inattività; tale valore può essere cambiato modificando nel file di configurazione /etc/php5/apache2/php.ini
il valore di session.gc_maxlifetime.
Si tenga presente che una sessione viene avviata automaticamente al momento che si esegue per la prima volta una session_register() anche in mancanza di una session_start().
Si osservi anche che la funzione session_start() deve essere invocata in ogni pagina in cui si vuole fare riferimento a quella sessione.
Le istruzioni che provocano l'avvio di una sessione devono essere posizionate in un punto dello script PHP che non interferisca con l'invio automatico di intestazioni HTTP e quindi prima di qualsiasi istruzione PHP che emetta un output e anche di qualsiasi contenuto HTML scritto esternamente al codice PHP; la cosa migliore da fare è allora definire un blocco PHP apposito proprio all'inizio del file. |
Concludiamo questa panoramica sulle sessioni in PHP con un esempio in cui gestiamo un contatore di accessi ad un sito Web (o, più in piccolo, ad una pagina).
Il valore del contatore viene memorizzato in un file, ovviamente sul servente (in questo modo accenniamo anche all'uso dei file in PHP) e letto e incrementato ad ogni nuova richiesta di scaricamento della pagina.
Se questo meccanismo fosse gestito senza uso di sessioni avremmo un inconveniente molto grave: ogni volta che la pagina viene ri-visitata senza essere usciti dalla sessione di lavoro (ad esempio con un semplice «rinfresco» oppure tornando indietro dopo avere seguito un collegamento che si origina da essa) otterremmo un incremento del contatore, cosa evidentemente non corretta (a meno che non vogliamo «gonfiare» i dati di accesso al nostro sito).
Con l'uso delle sessioni, invece, l'incremento del contatore può essere fatto solo in presenza di una sessione appena avviata e non nelle visite successive nell'ambito della stessa sessione.
Vediamo dunque il listato del file, chiamato conta_sisess.php
, che gestisce il contatore delle visite correttamente:
|
Commentiamo il listato servendoci dei numeri di riga aggiunti per questo scopo:
Lo script inizia con l'attivazione della sessione e la regitrazione della variabile $sessione (righe 2 e 3);
alla riga 4 si assegna il nome del file in cui memorizzare il valore del contatore a $nomefile; nel nome non è presente alcuna indicazione di percorso, questo significa che tale file risiede nella stessa directory in cui è memorizzato lo script;
con le righe da 5 a 8 si crea il file, se non esiste, tramite una operazione di apertura in scrittura (riga 6) con successiva chiusura; si noti la forte somiglianza tra queste funzioni di PHP per la gestione dei file e quelle analoghe del linguaggio c; la creazione del file ha successo solo se l'utente www-data (che ricordiamo essere quello con i cui privilegi vengono eseguiti i processi del servente Web) ha il permesso di scrivere nella directory in cui il file deve essere memorizzato;
rimaniamo ancora sulla riga 6 per sottolineare come la funzione di apertura di un file restituisca un valore, chiamato puntatore al file, (nel nostro caso assegnato a $fp) che poi deve essere utilizzato per tutte le successive operazioni da svolgere su quel file; in pratica con l'apertura si viene a creare un legame tra il nostro programma e il file fisico residente nella memoria di massa e tale legame è esplicitato dal puntatore al file;
nelle righe da 9 a 11 si apre il file in lettura (a questo punto esiste sicuramente), si legge il valore del contatore e si chiude il file; anche qui si possono notare forti analogie con il linguaggio c;
la riga 10 merita qualche ulteriore chiarimento: viene assegnato alla variabile $num il valore letto nel file partendo dall'inizio (il file è stato appena aperto) e per una lunghezza di quattro byte; tale valore è infatti un contatore, quindi un numero intero, e gli interi vengono memorizzati utilizzando quattro byte come in c e in molti altri linguaggi;
con le righe dalla 12 alla 14 si legge il valore della variabile di sessione, lo si incrementa facendolo transitare in $sess (anche l'operatore «++» è ripreso dal linguaggio c) e lo si memorizza ancora nella variabile di sessione;
se il valore appena incrementato è uno significa che è la prima volta che tale operazione è stata fatta e quindi deduciamo che la sessione è stata appena avviata e dobbiamo incrementare il contatore; questo è il «ragionamento» svolto nel blocco di selezione presente alle righe da 15 a 21;
in particolare a riga 17 si apre il file in scrittura; nella successiva si incrementa il valore del contatore e a riga 19 lo si scrive nel file a partire dall'inizio (il file è stato appena aperto in scrittura) utilizzando quattro byte come specificato dal terzo parametro della funzione fwrite; infine a riga 20 si chiude il file;
a riga 22 si pone in $sid l'identificativo della nostra sessione per poi visualizzarlo (questo non riguarda la gestione del contatore di accessi ed è stato aggiunto solo per mostrare l'aspetto di un SID);
le righe da 23 a 27, con una serie di print() creano la risposta in formato HTML da inviare al browser che si è collegato a questa pagina; viene anche previsto un collegamento ad un'altra pagina (chiudi_sess.php
) per poter chiudere la sessione;
importante notare, nelle righe 24 e 26, l'uso delle virgolette sia nell'ambito dell'istruzione PHP (cioè la print()) sia all'interno del codice HTML da essa creato; ovviamente queste ultime non possono essere usate liberamente, perché causerebbero errore di sintassi nell'istruzione PHP, e quindi vengono «mascherate» facendole precedere dal simbolo «\»
notiamo anche, sempre in queste istruzioni di ouput, l'uso del carattere speciale «\n» che corrisponde al codice ASCII 10 cioè a «riga nuova» o line feed (LF); serve per scrivere il sorgente HTML della pagina di risposta su più righe invece che su un'unica riga (cosa che sarebbe comunque lecita).
Nella figura 7.31 viene mostrato l'aspetto della risposta accompagnato dalla finestra di visualizzazione del relativo sorgente.
Aggiungiamo anche i listati dei file chiudi_sess.php
, da attivare, per chiudere la sessione, tramite collegamento presente nella pagina appena mostrata, e conta_nosess.php
che è la versione di pagina con contatore di accessi non corretta in quanto non gestita con le sessioni.
Per questi due file non viene mostrato l'aspetto in caso di apertura con il browser e non vengono commentate le istruzioni in quanto non contengono sostanziali novità rispetto a quanto illustrato finora.
Questo è il listato di chiudi_sess.php
:
|
Mentre questo è conta_nosess.php
:
|
Una tecnica molto diffusa, nell'ambito della applicazioni scritte in PHP, è quella di scrivere pagine che svolgono sia il compito di raccolta dati attraverso un modulo, sia quello di elaborazione invio della risposta.
Prima di tutto occorre fare in modo che lo script invii i dati a se stesso; a tale scopo occorre inserire "$_SERVER['PHP_SELF']" (variabile globale contenente il nome dello script PHP in esecuzione) come valore dell'attributo action del modulo.
Usando poi una campo nascosto del modulo come variabile flag si riesce a discriminare se lo script viene attivato per la prima volta, e allora deve emettere il modulo per l'input dei dati, oppure se è stato richiamato dal modulo, e allora deve elaborare questi ultimi e, eventualmente, emettere una risposta.
La logica di funzionamento dello script è quella rappresentata nello schema visibile nella figura 7.34, realizzato in «stile» diagramma di flusso.
|
Nell'esempio viene anche fatto uso di campi riguardanti data e ora in modo da poter illustrare alcune funzioni PHP dedicate a questo tipo di dati.
|
Vediamo le parti più significative del listato:
le righe 2,3 e 53 creano la parte di pagina HTML necessaria sia per il modulo che per la risposta;
alle righe 4 e 5 viene usata la funzione date() che prevede due parametri: un formato e una marca temporale (timestamp); una marca temporale è un numero intero che rappresenta il numero di secondi trascorsi dalle ore 00:00 del 1 gennaio 1970 (istante zero per i sistemi Unix e derivati); per ottenere la marca temporale corrente si può usare la funzione time() che non prevede argomenti, mentre con la funzione mktime(ora, minuto, secondo, giorno, mese, anno) si ottiene la marca temporale calcolata dall'istante zero a quello indicato negli argomenti;
quando nella funzione date() si indica solo il primo parametro, come nelle righe 4 e 5, si suppone che il secondo sia il valore restituito da time() e quindi si ottiene la data e ora corrente formattata secondo quanto indicato nel primo parametro;
i formati qui utilizzati sono solo due fra quelli possibili e il loro significato è del tutto intuitivo: notiamo solo che con «a» si indica l'anno di due cifre mentre con «A» di quattro, con «h» l'ora tra zero e dodici mentre con «H» tra zero e ventiquattro;
alla riga 6 si acquisisce il nome del file che è in esecuzione per usarlo per il richiamo a se stesso;
la riga 8 è quella fondamentale per la logica dello script: viene controllato se la variabile del modulo chiamata "nascosto" possiede un valore oppure no (a questo serve la funzione isset());
il controllo di riga 8 da esito positivo se lo script è stato richiamato per l'invio dei dati che quindi vengono acquisiti (righe 9-15); il ramo vero della selezione si estende fino a riga 30 comprendendo anche i controlli sui valori
il caso contrario si ha quando lo script è stato avviato per la prima volta e in tal caso non si fa niente (il ramo falso della selezione è vuoto);
nelle righe da 12 a 14 vengono estratti dalla data inserita nel modulo i tre componenti giorno, mese e anno con l'uso della funzione substr() che serve a estrarre una sottostringa da una stringa e prevede tre parametri: la stringa, il byte di partenza, la quantità di byte da estrarre (si tenga presente che il primo byte di una stringa è quello di posto zero);
in questa parte dello script si nota bene come il linguaggio PHP operi le conversioni automatiche di tipo delle variabili: $g, $m, $a sono stringhe e vengono fornite come parametri ad una funzione che si aspetta numeri; siccome però il loro contenuto è effettivamente numerico, il tipo viene convertito automaticamente e non si ha alcuna segnalazione di errore (cosa che invece accadrebbe se fossimo in presenza di linguaggi più rigorosi nella gestione delle variabili come il linguaggio c).
nelle righe da 16 a 29 ci sono i controlli sui valori in arrivo dal modulo con il banale uso di un flag (variabile $controlli);
in particolare a riga 26, per il controllo sulla data, viene usata un'altra funzione riguardante le date: checkdate() che serve a controllarne la validità; i parametri, come si vede, devono essere passati nell'ordine usato negli Stati Uniti: mese, giorno, anno; se la data è valida la funzione restituisce vero altrimenti restituisce falso;
da riga 32 a riga 52 c'è l'altra selezione fondamentale per lo script: se il campo nascosto è settato e i controlli sono andati bene, viene emesso un riepilogo dei dati inseriti seguito da un collegamento per il ritorno al modulo iniziale (righe da 33 a 38); in caso contrario viene emesso il modulo in cui i campi di input sono eventualmente precaricati con i valori precedenti (righe da 40 a 52);
questa seconda eventualità può infatti verificarsi in due casi: prima esecuzione dello script, e allora i campi sono vuoti, oppure errore nell'input, e allora i campi contengono i valori immessi precedentemente.
Nelle due successive figure 7.36 e 7.37 vediamo il caso in cui si hanno errori nell'input e quello in cui l'immissione si conclude positivamente.
Come per tutti gli altri linguaggi di programmazione, anche programmando in PHP è possibile commettere tre tipi di errori:
errori di sintassi: si sbaglia la scrittura di una istruzione o di una funzione; il motore PHP rileva l'errore e l'esecuzione dello script neanche inizia;
errori a tempo di esecuzione (runtime): si manifestano al momento che il codice viene eseguito (esempio tipico è la divisione per zero); possono essere fatali se interrompono l'esecuzione dello script, oppure non fatali;
errori logici: lo script funziona regolarmente ma non produce i risultati aspettati (ad esempio se si inverte la logica di funzionamento di una selezione a due vie); questi errori non vengono ovviamente segnalati dal motore PHP, deve essere il programmatore ad individuarli con una attenta attività di verifica del comportamento dei programmi.
Nelle due successive figure, 7.38 e 7.39 vediamo quello che appare nella finestra del browser rispettivamente in caso di un errore di sintassi e di un errore a tempo di esecuzione (si vuole aprire un file che non esiste).
|
Come si vede, nel secondo caso l'errore non è fatale e lo script prosegue ugualmente fornendo un risultato ovviamente non corretto.
Quando una procedura scritta in PHP viene resa attiva presso gli utenti (si dice che passa «in produzione»), è lecito aspettarsi che tutti gli errori di sintassi siano stati eliminati; gli errori a tempo di esecuzione sono invece più subdoli perché possono manifestarsi solo in certe condizioni (il file da aprire esisteva fino a ieri e oggi non esiste più); in questo caso un buon programmatore dovrebbe prevedere opportuni controlli all'interno dello script in modo da intercettare le possibili situazioni di errore gestendole con opportuni messaggi all'utente («L'archivio xyz, fondamentale per la procedura si è danneggiato; contattare l'amministratore del sistema»).
Nell'ambito della gestione degli errori possono essere proficuamente utilizzate i comandi break, per forzare l'uscita da un blocco di istruzioni (ad esempio da un ciclo), e exit per forzare la conclusione dello script.
Se lo sviluppatore è ragionevolmente certo di avere previsto la gestione di tutti gli errori a tempo di esecuzione della sua procedura (o almeno dei più probabili), può essere opportuno disabilitare la visualizzazione sul browser dei messaggi di errore PHP che può generare sconcerto nell'utente oltre che fornirgli informazioni inopportune.
Per fare questo occorre intervenire nel file di configurazione /etc/php5/apache2/php.ini
per cambiare la riga:
|
ponendo il valore a Off.
Questa modifica fa si che, in caso di errore, l'utente riceva una pagina bianca; ciò probabilmente non fa diminuire il suo sconcerto, ma almeno evita che gli vengano visualizzate informazioni inopportune.
Avendo disattivato la visualizzazione dei messaggi di errore può essere opportuno attivare la loro registrazione in un file apposito del servente; per fare questo occorre (sempre nel file di configurazione) cambiare la riga:
|
ponendo il valore a On e togliere il commento (che in questo file si ottiene con il «;») alla riga:
|
inserendo il nome del file desiderato (ad esempio /var/log/php.log
) al posto di filename; il file in prescelto deve essere scrivibile dall'utente www-data per i motivi ormai più volte spiegati.
Rimanendo nella sezione di gestione degli errori del file di configurazione, può servire intervenire sulla riga della variabile error_reporting per alterare il livello di errori che vengono segnalati; a tale proposito sono presenti nel file molte righe commentate che spiegano in dettaglio i valori che possono essere assegnati.
Quando si realizzano applicazioni Web di una certa portata, può essere molto utile definire una volta per tutte alcune caratteristiche comuni a tutte le pagine del sito oppure porzioni di codice da utilizzare in punti diversi dell'applicazione stessa; per questo motivo sono presenti in PHP due funzioni con le quali si possono caricare in un uno script porzioni di codice o di sorgente HTML.
Le due funzioni sono include() e require(); entrambe caricano, al momento dell'esecuzione,il file indicato come argomento e segnalano un problema nel caso esso non esista; la require() in tale situazione blocca l'esecuzione, la include() invece prosegue comunque.
Al fine di evitare possibili problemi dovuti alla inclusione successiva di uno stesso file, è talvolta utile usare le funzioni include_once() e require_once() che si comportano come le precedenti alla prima inclusione ma ignorano tentativi di caricamento successivi.
I file da includere possono avere dei nomi arbitrari, ma c'è la consuetudine di assegnare .html a file contenenti HTML e estensione .inc a file con codice PHP; quest'ultima scelta può essere pericolosa perché, in caso di errata configurazione del servente Web, i programmi di navigazione potrebbero visualizzare il contenuto di tali file, mostrando quindi eventuali dati riservati (ad esempio i parametri di connessione ad una base di dati gestita dall'applicazione scritta in PHP).
Si suggerisce quindi di assegnare l'estensione .php ai file da includere contenenti istruzioni del linguaggio.
Come esempio vediamo un tipico utilizzo della include() in cui si effettua l'inclusione di due file HTML contenenti rispettivamente la testata e la coda che si suppongono comuni a tutte le pagine del nostro sito; evidentemente l'inclusione deve essere fatta in modo analogo in tutte le pagine interessate:
|
L'inclusione di codice PHP si usa molte volte per rendere disponibili, all'interno degli script, le definizioni di una serie di funzioni che essi possono utilizzare; ovviamente qui parliamo di funzioni definite dal programmatore, che vanno ad aggiungersi a quelle predefinite nel linguaggio PHP.
Rendere disponibili le funzioni in modo centralizzato in uno o più file da includere permette una gestione più comoda delle modifiche nel caso in cui esse siano necessarie in molti script diversi; questo naturalmente non significa che la definizione di funzioni non possa avvenire direttamente all'interno degli script; nel proseguo, per comodità di esposizione, faremo proprio riferimento al caso in cui le funzioni siano definite nello stesso script in cui sono richiamate.
Dal punto di vista del motore PHP non c'è alcuna differenza rispetto al fatto che la dichiarazione di una funzione sia nello script che la usa piuttosto che in un file esterno da includere; infatti l'inclusione provoca la copia delle istruzioni contenute in quest'ultimo nello script prima che esse siano eseguite. |
Una funzione PHP è caratterizzata da un nome, un insieme di parametri opzionali e, in genere, da un valore di ritorno.
Vediamo un esempio di definizione di una funzione:
|
Nella riga 2 c'è l'intestazione della funzione con la parola riservata function seguita dal nome e dal parametro (se fossero più di uno si separano con virgole, se assenti si lasciano vuote le parentesi);
il corpo della funzione è racchiuso tra le consuete parentesi graffe (righe 3 e 14);
se il parametro contiene una stringa non vuota (riga 4), tale stringa viene invertita (righe 5-10), altrimenti non si inverte (righe 11-13);
alle righe 9 e 12 (che sono ovviamente alternative) si ha la restituzione del valore di ritorno della funzione grazie alla parola riservata return.
Una possibile invocazione della funzione può essere la seguente:
|
La variabile $a è il «parametro attuale» passato alla funzione; il valore restituito da essa è assegnato a $b.
Il passaggio dei parametri avviene per valore a meno che nella definizione della funzione non sia presente un «&» prima del nome del parametro; in tal caso il passaggio avviene per riferimento (in queste dispense si danno per scontate le conoscenze teoriche circa le due modalità di passaggio dei parametri ad una funzione).
Le variabili hanno un campo d'azione o scope coincidente con la funzione in cui sono definite oppure con la pagina se sono definite fuori da qualsiasi funzione.
Per fare in modo che una variabile definita fuori da una funzione sia visibile anche al suo interno, occorre usare, nel corpo della funzione, la parola riservata global seguita dal nome della variabile; in mancanza di ciò la variabile usata nella funzione viene ad essere a tutti gli effetti «nuova» e del tutto diversa da quella, con stesso nome, definita esternamente (anche questi concetti, presenti in tutti i linguaggi di programmazione, vengono dati per noti e non sono ulteriormente approfonditi).
Notiamo infine come una funzione possa anche non prevedere un valore di ritorno: potrebbe essere ad esempio una funzione che esegue solo una serie di print(), oppure una funzione che contiene solo del sorgente HTML (cosa possibile anche se non di uso frequente); in tal caso non è necessario return al suo interno e la sua invocazione avviene senza la presenza di una assegnazione.
La funzione header() è utile in tutti quei casi in cui si vuole alterare il comportamento del motore PHP che automaticamente provvede ad inserire, prima di qualsiasi output, l'intestazione HTTP «normale» cioè quella contenente la riga Content-Type: text/html seguita da una riga vuota.
La funzione deve essere usata prima che sia stato emesso qualsiasi output sia con le funzioni a ciò preposte del PHP sia a causa della presenza di sorgente HTML nella pagina che preceda la funzione stessa.
Grazie al suo uso è possibile alterare l'intestazione per gli scopi sotto elencati:
definire tipi di contenuti diversi da text/html; ad esempio:
|
permette di definire un output in formato png;
reindirizzare ad altra pagina; ad esempio:
|
costringere il browser a richiedere sempre l'ultima versione di una pagina senza usare quella eventualmente memorizzata nella memoria cache:
|
In questo paragrafo vengono prese in esame alcune delle funzioni che PHP mette a disposizione per lavorare con basi di dati MySQL e PostgreSQL; l'elenco completo si può trovare in molti documenti o siti, ad esempio in <http://www.php.net/manual>.
Essendo le problematiche di uso di una base di dati simili qualunque sia il software di gestione, facciamo gli esempi riferendoci solo a PostgreSQL evidenziando le differenze con MySQL riguardo alle funzioni PHP da richiamare.
|
Non vengono forniti dettagli sui parametri richiesti dalle funzioni e sui loro valori di ritorno; queste informazioni possono essere desunte dall'uso delle funzioni fatto nei prossimi esempi e poi approfondite consultando i manuali di PHP.
Nell'esempio seguente viene realizzato un modulo per inserire i dati nella tabella rubrica definita in precedenza nella base di dati fulvio in PostgreSQL e in MySQL.
Con lo stesso modulo è anche possibile effettuare un'interrogazione all'archivio specificando alcuni parametri; i dati da inserire o da usare per la ricerca vengono passati ad un file PHP che effettua l'operazione richiesta e crea una opportuna pagina di risposta.
La gestione del modulo non è rifinita: mancano molti controlli sui campi di input e le funzionalità sono molto lontane da quelle che dovrebbero essere previste in una procedura di gestione di dati via Web «reale»; d'altra parte questo esempio è inserito solo a scopo didattico ed è quindi volutamente limitato.
Il sorgente del modulo, chiamato modulo.html
è definito come segue (il file può avere estensione .html in quanto non contiene codice PHP):
|
Il modulo viene visualizzato come mostrato nella figura 7.51.
Il file "phpsql.php" che svolge le operazioni sulla base di dati è il seguente:
|
Nel caso venga richiesta una interrogazione fornendo come unico parametro il cognome Paperino si ottiene la risposta riportata nella figura 7.53.
Di seguito viene mostrato il contenuto dei due file connetti_psql.php
e connetti_mysql.php
utilizzati per la connessione alle rispettive basi di dati.
|
|
Le funzioni per la connessione alle basi di dati usate in questi due file sono di facile comprensione e il ruolo dei parametri richiesti dovrebbe apparire chiaro dal nome degli stessi.
Qualche parola in più può essere spesa per spiegare almeno alcune parti del listato di phpsql.php
completando i commenti già in esso presenti:
con il test sulla variabile $sub (riga 19) si stabilisce se l'utente ha richiesto una interrogazione o un inserimento; nel primo caso viene preparata la variabile $alt in base ai parametri di ricerca selezionati e poi viene controllata l'istruzione switch per impostare le interrogazioni appropriate alla base di dati;
a riga 58 viene eseguita l'interrogazione: il risultato viene posto in $richiesta e il numero di record estratti in $righe;
se sono stati estratti dei dati dall'archivio (controllo a riga 65) si esegue un ciclo con l'istruzione while (riga 67) tante volte quante sono le righe estratte;
ad ogni iterazione si estraggono i dati di un record (righe da 68 a 76) e si stampano a video (righe da 77 a 89);
nel caso invece l'utente abbia richiesto un inserimento (riga 99 e seguenti), si controlla che sia stato indicato almeno il cognome e che la data di nascita sia valida;
superati i controlli si inseriscono in archivio i dati provenienti dal modulo (righe da 110 a 114) controllando anche che l'operazione sia conclusa positivamente (righe da 116 a 119);
a questo punto resta solo da chiudere la connessione alla base di dati (riga 123) ed emettere sul documento di risposta la stringa che funge da collegamento per tornare al modulo di partenza.