| Home / Indice sezione | www.icosaedro.it | ![]() |
bt_ - Implementazione in PHPIl linguaggio PHP si presta bene per implementare i concetti di bt_ in modo semplice ed efficace. Qui esaminiamo un subset dell'API di bt_ che ho realizzato in questo linguaggio, e vedremo come si possono organizzare le applicazioni WEB con questo strumento. Alcuni dei termini utilizzati, come bt_file, bt_stack ecc., sono trattati estesamente nei primi due articoli della serie.
Introduzione
Struttura dell'applicazione WEB
Il logout
L'API di bt_/PHP
Conclusioni
Bibliografia
Argomenti correlati
Cominceremo presentando la struttura del programma che costitusce la nostra applicazione WEB, vedremo la suddivisione delle pagine del sito in altrettante funzioni del programma e vedremo il meccanismo del request handler. Descriveremo anche il set di funzioni che implementano in PHP il framework bt_.
bt_/PHP supporta il concetto di modularità grazie al
quale applicazioni articolate si possono scomporre in altrettanti
file distinti. Ad esempio un tipico programma gestionale potrebbe
essere scomposto in vari file i cui nomi evocativi potrebbero essere
"Fatturazione", "AnagrafeClienti", "AnagrafeFornitori", "Magazzino", ecc.
Ciascun modulo sarà costituito da tante funzioni, alcune deputate a
generare pagine WEB, altre solo di supporto al modulo specifico. bt_/PHP
dispone poi di un semplice meccanismo per invocare una data funzione
di un dato modulo: mentre "NomeFunzione" fa riferimento per default al
modulo corrente, "NomeFunzione@NomeModulo" indica esplicitamente a quale
modulo appartiene la funzione voluta.
L'applicazione WEB prototipo di questo articolo sarà monolitica,
cioè sarà costituita da un solo file. Chiameremo questo
file rh.php che sta per request handler. In
effetti questa sarà l'unica "pagina WEB" del sito. Dentro a
questo file metteremo tutte le funzioni che generano le pagine della
nostra applicazione. Nelle applicazioni reali il request handler
farà solo il suo mestiere, limitandosi solo a smistare le
chiamate verso le varie funzioni dei moduli.
Le invocazioni HTTP con metodo GET dovranno prevedere
un parametro indice i che individua
l'entrata del bt_file richiesta. Ad esempio, l'URL
https://www.unsito.it/rh.php?i=3 individua l'entrata numero
3 del bt_file. La funzione bt_Anchor() si occupa di costruire
in questo modo le ancore.
Le invocazioni HTTP con metodo POST avverranno anch'esse sempre
verso l'URL https://www.unsito.it/rh.php, ma questa volta
il parametro indice viene determinato in base al nome del bottone
premuto. Ad esempio, il bottone <INPUT type=submit name=button3
value="Annulla"> corrisponde alla entrata numero 3 del
bt_file. Non approfondiamo ulteriormente i dettagli di questo meccanismo,
ma sottolineiamo che, mentre l'HTML contempla un solo action script
deputato a ricevere il POST del form qualunque sia il bottone premuto,
con bt_ possiamo assegnare ad ogni bottone una funzione diversa.
Si pensi ad esempio quanto ciò possa tornare utile nel tipico
form di input con i classici bottoni "Salva" e "Annulla": è
evidente che i due bottoni svolgono funzioni completamente diverse,
per cui è naturale che le funzioni che li gestiscono siano diverse.
Le funzioni bt_Form() e bt_Button() si occupano di tutti i dettagli.
Fatte queste premesse, analizziamo la struttura del file rh.php.
Al codice PHP alternerò i commenti esplicativi. La parte iniziale
è comune a tutte le applicazioni WEB scritte in bt_/PHP, e si
tratta del request handler vero e proprio che gestisce la richiesta HTTP:
<?
# File: rh.php
require "bt_.php";
if( ! bt_SessionValid() ){
# Sessione non valida. Fai login:
require "Login";
bt_InitialCallForward("Indice");
} else if( bt_CallForward() ){
# Chiamata di call-forward avvenuta.
} else {
# Parametri request errati. Fail-safe:
bt_InitialCallForward("Indice");
}
exit;
Il modulo di inclusione bt_.php definisce le funzioni
dell'API di bt_ riassunte al termine di questo articolo. Immediatamente
dopo dobbiamo stabilire come proseguire basandoci sulla request HTTP.
Se la sessione non è valida occorre presentare all'utente
il consueto form di login. Non approfondiremo qui i dettagli del modulo
di Login perchè dipende dalla strategia di autenticazione scelta,
e perché non contiene codice particolarmente significativo. Diremo
solo che l'utente dovrà inserirà il nome di login e la
password e, se questi sono validi, il modulo Login attiverà
la sessione bt_ chiamando bt_Login(). L'uscita dal
modulo di login avviene solo se l'utente si è autenticato con
successo, nel qual caso la funzione bt_InitialCallForward()
provvede a chiamare la funzione principale della nostra applicazione
WEB che abbiamo chiamato Indice. La pagina indice
sarà la prima pagina WEB presentata all'utente che si è
appena autenticato.
Se invece la sessione è valida significa che l'utente
è già stato identificato e che sta proseguendo nell'
utilizzo dell' applicazione. Il bt_file e il bt_stack
memorizzati nella sessione contengono lo stato dell' applicazione. Ora
dobbiamo evadere la richiesta HTTP e determinare la prossima "pagina"
da servire. A questo scopo con bt_CallForward()
eseguiamo la call-forward indicata nella request GET o POST pervenuta.
La funzione bt_CallForward() restituisce FALSE
se i parametri della request non sono validi. In quest' ultima
eventualità abbiamo previsto un fail-safe, sempre verso la
funzione principale della nostra applicazione. E' giunto il momento di
vedere come potrebbe essere fatta questa funzione.
La funzione Indice() dovrebbe presentare la
pagina iniziale del nostro programma. Nella maggior parte dei casi si
vorranno mettere in questa pagina i richiami alle altre sotto-sezioni
dell' applicazione, e quindi non sarà altro che un elenco di
ancore:
/*. void .*/ function Indice()
{
PageHeader("Indice");
bt_Anchor("Vai al calendario", "Calendario"); echo "<p>";
bt_ReturnTo("Indice");
bt_Anchor("Vai alla rubrica", "Rubrica"); echo "<p>";
bt_ReturnTo("Indice");
bt_Anchor("LOGOUT", "Logout");
bt_ReturnTo("Indice");
PageFooter();
}
/*. void .*/ function PageHeader(/*. string .*/ $title)
{
echo "<HTML><BODY><H1>$title</H1>";
}
/*. void .*/ function PageFooter()
{
echo "</BODY></HTML>";
}
La pagina indice della nostra applicazione è molto spartana:
essa contiene l'ancora "Vai al calendario" associata alla funzione di
call-forward Calendario(), l'ancora "Vai alla rubrica"
associata alla funzione di call-forward Rubrica(),
e infine l'ancora "LOGOUT" associata alla funzione di call-forward
LogoutPage(). Per tutte le call-forw abbiamo
predisposto come call-backward la funzione Indice().
Non ci resta che implementare le funzioni rimanenti della nostra applicazione. In generale ad ogni funzione corrisponde una pagina WEB, ma naturalmente il nostro programma può contenere anche altre funzioni di supporto. Vediamo per prima la funzione di logout, che mi sembra la più semplice. Con questa funzione richiediamo conferma della effettiva volontà dell'utente:
/*. void .*/ function Logout()
{
PageHeader("Logout");
echo "Vuoi veramente terminare l'applicazione?</p>";
bt_Form();
bt_Button("Annulla", "bt_Return");
bt_Button("Logout", "LogoutConfermato");
echo "</FORM>";
PageFooter();
}
/*. void .*/ function LogoutConfermato()
{
bt_Logout();
echo "<HTML><BODY>Sessione terminata.</BODY></HTML>";
}
La pagina di logout propone due bottoni. Il bottone "Annulla" causa
l'invocazione della funzione bt_Return(), che a sua
volta estrae dalla cima dello stack la funzione effettiva da chiamare.
Per via della bt_ReturnTo() opportunamente predisposta
a suo tempo nella Indice(), in cima allo stack si
trova la Indice() stessa. In definitiva premendo
"Annulla" l'utente si ritrova nella pagina principale. Avremmo
potuto ottenere lo stesso risultato senza usare il meccanismo
della call-backward semplicemente associando il bottone "Annulla"
direttamente alla funzione Indice() invece che alla
funzione bt_Return(). Tuttavia la funzione di logout
così com'è stata progettata si presta ad essere invocata
anche da altri contesti della nostra applicazione, e non necessariamente
dalla sola pagina indice.
Il framework bt_/PHP si compone di una serie di funzioni di utilità che vengono qui sommariamente riassunte.
/*. void .*/ function bt_Login(/* int .*/ $UID)
/*. void .*/ function bt_Logout()
Per mantenere lo stato del bt_file e del bt_stack è necessario
attivare una sessione. La funzione bt_Login($UID) crea una
sessione per l'utente identificato da $UID e predispone lo stato
iniziale di bt_. E' responsabilità della applicazione presentare
una adeguata maschera di login dove l'utente può inserire il
proprio nome e la propria password. Inoltre la validazione del login, a
causa dei vari modi in cui può essere implementata, rimane a carico
dell' applicazione che importa bt_. La funzione di bt_Logout()
cancella la sessione e rimuove dalla memoria del server tutti i dati
associati. Questa funzione dovrà essere richiamata in una apposita
pagina di logout predisposta dall' applicazione.
/*. bool .*/ function bt_SessionValid()
Restituisce TRUE se la sessione è valida, cioè se il
browser ha restituito il cookie di sessione corretto. Questa funzione
viene impiegata nel request handler per stabilire quando presentare
la maschera di login. Da notare che le funzionalità di gestione
della sessione fornite con PHP non offrono un meccanismo per stabilire
se il cookie è valido e se la sessione al quale esso corrisponde
è valida; la chiamata di session_start(), infatti,
comporterebbe sempre la generazione di un cookie.
/*. void .*/ function bt_InitialCallForward(/*. string .*/ $func /*., args .*/)
Abbiamo già descritto questa funzione, il cui uso è
praticamente riservato al solo request handler.
/*. bool .*/ function bt_CallForward()
Questa funzione è il cuore del request handler: la request
proveniente dal browser viene analizzata, e la funzione di call-forward
opportuna viene chiamata. La funzione ritorna FALSE quando la request
inviata dal browser non è valida, ad esempio perché
contiene dati artefatti.
/*. void .*/ function bt_Anchor(/*. string .*/ $text, /*. string .*/ $func /*., args .*/)
Questa funzione ha due effetti: invia al browser un'ancora cliccabile
che contiene il testo $text, mentre lato server predispone la chiamata
alla funzione di call-forward $func con gli eventuali argomenti. Se
l'utente clicca sull'ancora, la funzione viene richiamata con gli
argomenti impostati. Come abbiamo detto, il nome della funzione e i suoi
argomenti non vengono inviati al client ma restano sul server, così
risparmiando banda; inoltre il client non ha la possibilità
né di vedere gli argomenti, né di alterarli.
A livello mentale il programmatore deve immaginare la funzione
di call-forward come a una freccia che va dalla pagina corrente verso
la pagina (o più in generale verso la funzione) richiamata.
Spesso questa freccia porta l'utente verso un sotto-insieme di pagine;
al termine della visita di questo sotto-insieme di pagine vorremo far
tornare l'utente a una data pagina: si tratta di una call-backward,
una funzione che possiamo impostare con bt_ReturnTo():
/*. void .*/ function bt_ReturnTo(/*. string .*/ $func /*., args .*/)
Aggiunge al bt_file la call-backward associata all'ultima call-forward
inserita con bt_Anchor() o bt_Button(). Come abbimao spiegato
nell'articolo introduttivo, la funzione di call-back viene inserita in
cima al bt_stack se l'utente ha cliccato sull'ancora o sul bottone della
corrispondente call-forward. Questo permette di stabilire dei circuiti
obbligati di visitazione delle "pagine" del sito.
/*. void .*/ function bt_StackPush(/*. string .*/ $func /*., args .*/)
Aggiunge la funzione in cima al bt_stack. Questa funzione viene usata
raramente, ma torna utile per snellire il codice soprattutto nella
validazione delle maschere di input.
/*. array[int]mixed .*/ function bt_StackPop()
Ritorna la chiamata che sta in cima allo stack della sessione di finestra.
Il valore ritornato e' un array: il primo elemento e' la funzione, gli
altri sono gli argomenti. Viene usata tipicamente in combinazione della
funzione precedente.
/*. void .*/ function bt_Return(/*. args .*/)
Invoca la funzione in cima al bt_stack della sessione di finestra
corrente. Aggiunge gli argomenti specificati, se presenti, così
implementando un meccanismo per il ritorno di valori da una finestra
all'altra.
/*. void .*/ function bt_Form()
Apre un nuovo FORM impostando il request handler come attributo "action".
/*. void .*/ function bt_Button(/*. string .*/ $text,
/*. string .*/ $func /*., args .*/)
Ha due effetti: invia al browser il bottone con la scritta $text e mette
nel bt_file la call-forward corrispondente alla chiamata della funzione
$func (con eventuali argomenti). Come abbiamo spiegato nell'articolo
introduttivo a bt_, lato client non si vedono né il nome della
funzione né gli argomenti, che restano sul server. Questo risparmia
banda, soprattutto se gli argomenti sono ingombranti; inoltre i valori
degli argomenti non sono falsificabili dal client.
/*. void .*/ function Set(/*. string .*/ $name, /*. mixed .*/ $value)
/*. mixed .*/ function Get(/*. string .*/ $name)
bt_/PHP implementa un proprio meccanismo di gestione della sessione,
e quindi non fa uso degli strumenti già predisposti da
questo linguaggio e che di solito vengono impiegati a questo scopo
(session_start(), $_SESSION[], ecc.). Questo
si è reso necessario per implementare alcune funzionalità
peculiari di questa implementazione di bt_, come la gestione delle
finestre multiple e la supervisione delle sessioni attive. Le funzioni
Set() e Get() permettono di salvare e recuperare
dalla sessione corrente dei valori. Tuttavia in bt_ è molto
raro che si abbia la necessità di salvare dati nella sessione
perché nella maggior parte dei casi i dati si propagano da una
pagina all'altra attraverso gli argomenti delle funzioni impostati con
bt_Anchor() e bt_Button(). Le applicazioni
WEB realizzate in modo "tradizionale" tendono invece a fare largo uso
di dati salvati in sessione, dove tipicamente finiscono per accumularsi
indefinitamente.
Abbiamo descritto il cuore del sistema bt_ implementato in PHP. Il linguaggio PHP si è rivelato particolarmente adatto: funzioni a numero variabile di argomenti tipizzazione debole rendono il codice particolarmente semplice e lo sviluppo di applicazioni WEB complesse diventa rapido e sicuro.
www.w3.org/TR/html4/.
NOTA: i documenti RFC sono reperibili in www.rfc-editor.org.
NOTA: i documenti RFC sono reperibili in www.rfc-editor.org.
| Umberto Salsi | Contatto | Mappa | Home / Indice sezione |