Home / Indice sezione
 www.icosaedro.it 

 bt_ - Implementazione in PHP

Il 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.

Storico degli aggiornamenti

2005-02-21
Prima edizione dell'articolo.

Indice

Introduzione
Struttura dell'applicazione WEB
Il logout
L'API di bt_/PHP
Conclusioni
Bibliografia
Argomenti correlati

Introduzione

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_.

Struttura dell'applicazione WEB

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().

Il logout

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.

L'API di bt_/PHP

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.

Conclusioni

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.

Bibliografia

NOTA: i documenti RFC sono reperibili in www.rfc-editor.org.

Argomenti correlati

NOTA: i documenti RFC sono reperibili in www.rfc-editor.org.


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