1a lezione A scuola con PC Open Web Developer ASP di Antonio Volpon 1 Da sito statico a dinamico roseguiamo il filone aperto a inizio d'anno con il corso Webmaster per affrontare questa volta la progettazione di pagine e siti dinamici realizzati con tecnologia Microsoft. Il corso, che si articola in quattro puntate, vi spiegherà tutti gli elementi essenziali per realizzare un progetto completo, inclusa l'integrazione con un database esterno. HTML è, come abbiamo approfondito nelle puntate del corso Webmaster, un linguaggio utilizzato per la costruzione di pagine Web di natura statica. Con statico in questo contesto intendiamo prevedibile: una pagina realizzata con solo codice HTML produce lo stesso risultato per ogni visitatore che vi accede. Se la realizzazione di siti Web si fermasse a un sito statico, però, quasi tutto quello che siamo abituati a vedere oggi in Internet (forum, servizi di home banking, chat) non sarebbe possibile. P Da statico a dinamico Per dinamico si intende un sito in grado di interagire con l’utente, così da rispondere in modo attivo e diverso caso per caso, per esempio riportando in cima alla pagina il nome dell’utente registrato o addirittura, come succede ad esempio per MyYahoo (http://my. yahoo.com/), personalizzando i contenuti. Ma quando vale la pena di realizzare un sito dinamico? La risposta dipende da molti fattori, come ad esempio la dimensione del sito stesso, la frequenza di aggiornamento e la necessità di aggiungere o modificare diverse sezioni in tempi brevi. Se l’unico scopo del sito è di ospitare il vostro curriculum vitae, pubblicare qualche foto delle vacanze o pubblicizzare in poche pagine l’attività della vostra società, probabilmente potete accontentarvi delle possibilità offerte da un sito statico. In questo caso realizzerete tante pagine HTML quante sono le pagine del sito, ad esempio 10 pagine contenenti ognuna 5 foto delle vostre vacanze. Ponete ora il caso che al posto di sole 10 pagine ne abbiate via via aggiunte delle altre nel corso delle stagioni: vi troverete ben presto ad ospitare sul vostro sito qualche centinaio di pagine. Nessun problema fino a quando non dovete IL CALENDARIO DELLE LEZIONI Lezione 1: Da sito statico a dinamico Le prossime puntate Lezione 2: Portare il sito sul server • Da sito statico a dinamico • Come realizzare siti dinamici • Una prima pagina ASP • Anatomia di una pagina ASP • Rendere il codice leggibile e facile da modificare: gli include ASP 1/97 Lezione 3: ASP e i database Lezione 4: Uso avanzato dei database apportare delle modifiche, ma pensate se un domani volete spostare la didascalia da sotto la foto a sopra, magari aumentando le dimensioni del carattere per simulare un titolo: non avete alcuna altra scelta se non di ripassare una per una le pagine. Realizzando un sito dinamico, invece, sarebbe sufficiente realizzare una sola “pagina tipo” (detta in gergo template), che assomiglia in tutto per tutto alle pagine realizzate precedentemente, solo che contiene testo e immagini fittizi. A questo punto è possibile sostituire al testo e all’immagine alcune istruzioni scritte in un linguaggio di programmazione, in modo da interagire con una base di dati, cioè un “contenitore” (ne parleremo approfonditamente nella terza puntata) di didascalie e foto. Quando l’utente del nostro sito richiama la pagina con le foto, gli viene servito sempre lo stesso template, ma il contenuto prelevato dalla base di dati cambierà di volta in volta (le foto di Parigi, di Londra, e così via). Il vantaggio in termini di manutenzione è evidente, perché la pagina da aggiornare è solo una, ma c’è di più. Se i dati sono ospitati in un sito dinamico, è possibile realizzare funzioni di ricerca che permettono al visitatore di recuperare le informazioni di interesse, in questo caso di accedere alle foto volute senza doverle scorrere tutte. Ad esempio http://www.vol pon.com/foto.asp contiene elenchi generati in modo del tutto dinamico ed è possibile effettuare un buon numero di ricerche. Alla fine del presente corso saremo in grado di costruire una pagina simile a questa. Come installare gli esercizi Vediamo come configurare Internet Information Services su Windows XP Professional per poter utilizzare gli esempi del corso 1 - Aprite il Control Panel dal menu Start / Settings Start e da qui selezionate Add or Remove Programs. A questo punto cliccate la voce Add / Remove Windows Components dalla barra laterale sinistra. Assicuratevi che IIS sia installato, oppure procedete all’installazione spuntando la relativa voce. Chiudete tutte le finestre, ad eccezione del Control Panel 2 - Andate sul sito di PC Open (sezione Guide pratiche) e scaricate i file del corso in una cartella del vostro disco fisso 3 - Dal Control Panel selezionate Administrative Tools 4 - Nella lista dei programmi di amministrazione selezionate Internet Information Services e apritelo 5 - A questo punto siete ai comandi dei server. Non vi resta che configurarlo perché prenda gli esempi dalla cartella che avete creato sopra. Per farlo, selezionate la voce Default Web Site con il tasto destro e aprite la finestra delle proprietà 6 - A questo punto procedete alla linguetta Home Directory e scrivete il percorso della cartella nella quale avete salvato i file (alternativamente potete sfogliare nel disco servendovi del pulsante Browse) 7 - A questo punto potete chiudere tutte le finestre, aprire un browser e digitare l’indirizzo di una pagina di esempio, http://localhost/oggi.asp. Localhost è il nome del vostro server locale, che potete usare non solo per eseguire i nostri esempi, ma per sperimentare dal vivo il mondo ASP 1a lezione 2 Come realizzare siti dinamici er dotare la pagina Web di dinamicità, in modo che il risultato prodotto dipenda da alcuni fattori, primo fra tutti l’interazione degli utenti con il sito, è necessario arricchire il codice HTML con le potenzialità date dalle piattaforme lato server. Nella settima lezione del corso Webmaster sono stati presentati alcuni approcci per la realizzazione di pagine dinamiche, con particolare riferimento a CGI (Common Gateway Interface). In queste 3 puntate affrontiamo invece lo studio di ASP (acronimo di Active Server Pages), la piattaforma Microsoft che in questi ultimi anni ha riscosso parecchio successo per diverse ragioni, prima fra tutte la relativa semplicità di apprendimento che ne ha diffuso l’utilizzo ben al di fuori dalla ristretta cerchia dei programmatori. L’idea che sta alla base di questo tipo di soluzioni è molto semplice: nel codice HTML è inserita una serie di istruzioni che il Web server è in grado di interpretare e la pagina viene salvata con una particolare estensione, normalmente ASP. Quando l’utente, utilizzando il proprio browser, accede a una pagina con questa estensione, il Web server non la preleva dal disco fisso per inviarla immediatamente al richiedente, ma la analizza alla ricerca di eventuali parti di codice ASP. Il server Web si compone di diverse componenti software, dette librerie, ognuna specializzata in un particolare compito, tra cui ce n’è una (asp.dll) che riceve dal server il codice da eseguire. Questa libreria è responsabile di interpretare ed eseguire il codice ASP e di restituire di nuovo al server il risultato dell’elaborazione (tipicamente dati provenienti da un database). Il server sostituisce quindi il codice ASP all’interno della pagina con il codice HTML prodotto dalla libreria (l’elenco dei movimenti di un conto bancario, ad esempio) e invia il risultato finale al browser dell’utente. È quindi importante sottolineare come il codice ASP non arrivi mai al browser dell’utente, ma venga eseguito esclusivamente sul la- P 2/97 to server. Questo ha delle importanti ripercussioni sulla sicurezza di una pagina: se l’utente fosse in grado di leggere nel sorgente di una pagina il codice ASP, potrebbe impossessarsi di informazioni riservate, come ad esempio le password di accesso a un database, o risalire alla configurazione delle macchine che ospitano il sito. Da quanto abbiamo detto è anche chiara la differenza tra un linguaggio “server side”, come per l’appunto sono quelli della piattaforma ASP, e un linguaggio “client side”, come è invece Javascript. Nel caso di Javascript è direttamente il browser ad eseguire il codice, e proprio per questo le potenzialità e funzionalità di questo tipo di linguaggi sono esigue se paragonate a quelle di un linguaggio interpretato direttamente dal server. Active Server Pages e Internet Information Services ASP vuol dire Microsoft e il server Web d’eccellenza di casa Microsoft è IIS (Internet Information Services), disponibile come componente gratuito in Windows 2000, XP e naturalmente Windows Server 2003. Ma il supporto per ASP può anche essere installato su Windows NT, come parte del Windows NT 4.0 Option Pack e perfino su macchine Windows 95/98, in questo caso utilizzando il Personal Web Server (una versione leggera, ma che svolge gli stessi compiti di IIS). Possono essere scaricati entrambi da Internet [[http:// www.microsoft.com/ntserver/nts/downloads/recommended/NT4OptPk/default.AS P]]. Anche se ASP è una tecnologia Microsoft, alcune società si sono sforzare di portare questa piattaforma in altre realtà, come ad esempio Sun ONE Active Server Pages [http:/wwws. sun.com/ software/chilisoft/ index.html], che consente di far girare applicazioni ASP sui server Sun. Per i dettagli sull’installazione e configurazione di ASP e IIS vi rimandiamo alla settima puntata del corso di Webmaster. Se invece state cercando qualche provider che vi dia la possibilità di sperimentare gli esercizi del corso senza dover configurare il vostro PC, date un’occhiata a quelli presenti in http://www.aspfree.com /ASP/freeasphost.ASP, molti dei quali gratuiti. Tenete comunque conto che normalmente è più comodo lavorare in locale fino a quando le pagine sembrano funzionare correttamente senza errori macroscopici, e portare successivamente l’applicazione nelle cartelle messe a disposizione dal provider. ASP e i linguaggi di scripting ASP non è un linguaggio, ma una piattaforma, un insieme di oggetti e funzionalità. Questo vuol dire che per realizzare pagine ASP potete utilizzare diversi linguaggi, e l’adozione di uno o dell’altro dipende semplicemente da quello con il quale vi sentite più a vostro agio. Se conoscete Visual Basic, ad esempio, la scelta ideale è rappresentata da Visual Basic Script, mentre se realizzate pagine HTML con codice Javascript, potreste preferire Jscript. Indipendentemente dal linguaggio utilizzato, comunque, i risultati non cambiano minimamente. L’unica accortezza che vi suggeriamo di adottare è di non usare, anche se è tecnicamente possibile, linguaggi diversi in una pagina ASP, per evitare di sprecare importanti risorse, visto che ASP deve caricare in memoria un interprete diverso per ogni tipo di linguaggio utilizzato. Visual Basic Script (abbreviato spesso con VBScript) è I principali oggetti ASP Application: consente di definire dati e informazioni comuni a tutta l’applicazione Web. Il copyright del sito, che sarà comune a tutte le pagine, potrebbe essere definito grazie a questo oggetto AspError: in caso di errore, dà al programmatore la possibilità di accedere ai dettagli dell’ultimo errore che si è verificato ObjectContext: viene impiegato per creare pagine Web che sfruttano le transazioni, e il suo uso va al di fuori dello scopo di questo corso. Basti sapere che una transazione è utilizzata per raggruppare al suo interno più operazioni atomiche ed è impiegata, nel caso di errori o situazioni non attese, per riportare l’applicazione allo stato precedente Request: quando l’utente interagisce con la pagine ASP, le informazioni inviate passano per l’oggetto Request, che viene interrogato per ottenere i dati inviati dal browser verso il server Response: può essere considerato l’antagonista dell’oggetto request. Se quest’ultimo si preoccupa di ospitare i dati inviati dagli utenti, response invia informazioni dal server al browser, un po’ come la funzione print del Basic stampa caratteri a video Server: svolge alcune funzioni di utilità, come ad esempio definire il tempo massimo di esecuzione di uno script (prima di andare in timeout per preservare risorse) e porta con sé alcune informazioni relative al browser dell’utente e al sito di provenienza Session: consente al programmatore di salvare e recuperare informazioni di un particolare utente nel corso della sua navigazione. Diversamente dall’oggetto Application, che contiene informazioni comuni a tutta l’applicazione, Session contiene quelle di un solo utente. Si presta quindi molto bene per ospitare dati come gli elementi di un carrello elettronico, il nome e cognome del visitatore, e così via. 1a lezione un sottoinsieme di Visual Ba- sic del quale eredita diverse funzionalità, ma si differenzia per alcuni importanti aspetti, prima di tutto per il fatto che si tratta di un linguaggio completamente interpretato, e quindi dalle prestazioni di esecuzione decisamente inferiori. In questa sede utilizzeremo proprio VBScript per realizzare pagine ASP. Sia Visual Basic, sia VBScript sono linguaggi “case insensitive”, il che vuol dire che potete scrivere le parole chiave del linguaggio, i nomi delle variabili e le espressioni indifferentemente in maiuscolo, minuscolo o una combinazione dei due: non fa alcuna differenza. Scrivere pagine ASP Come per le pagine HTML, anche per scrivere pagine ASP avete due scelte: utilizzare un semplice editor di testo oppure affidarvi a qualche programma più evoluto, che evidenzi le parole chiave del linguaggio o vi aiuti addirittura nella stesura del codice, come Visual Interdev di Microsoft [http://msdn. microsoft.com/ vinterdev/default.asp] (da qualche tempo incluso in Visual Studio .NET). La soluzione migliore è forse quella di utilizzare uno strumento che consenta sia di sviluppare codice HTML, sia di integrarlo con codice ASP. Tra i prodotti sul mercato vale la pena di ricordare Dreamweaver MX di Macromedia [http:// www.macrome dia.com/software/dreamwea ver/] e l’ultima versione di TopStyle [http:// www.bradsoft. com/topstyle/], entrambi sca- ricabili in versione di prova. Per svolgere gli esempi di questo corso, comunque, un semplice editor di testo è più che sufficiente. Gli esempi del corso Cercheremo di accompagnare con diversi esempi il nostro viaggio nel mondo della tecnologia ASP, così da mettervi subito in condizione di capire quali sono i vantaggi di questa piattaforma rispetto alle semplici pagine HTML, e per fornirvi qualche spunto nel realizzare i vostri prossimi progetti. Al termine delle tre puntate avremo realizzato la struttura di un semplice sito fittizio per il signor Mario Rossi, composto da Home Page, elenco delle foto delle vacanze (prelevate da database) e possibilità di inviare commenti a Mario con un form. Nel corso delle puntate non ci preoccuperemo della resa visiva delle pagine, cioè di creare pagine belle da vedere. Preferiamo concentrarci sul codice “nudo e crudo”, per rendere gli esempi più semplici da capire e mirati, data anche la facilità con cui il numero di righe in una pagina ASP tende ad aumentare con l’inserimento di tag HTML. Lasciamo al lettore la possibilità di personalizzare ed estendere quanto riportato su queste pagine. Dobbiamo però cominciare con ordine, e introdurre per prima cosa qualche concetto di base, visto che realizzare pagine ASP, per quanto si tratti di una tecnologia semplice e al tempo stesso potente, è in realtà costruire dei veri e propri programmi. 3 Una prima pagina ASP rima di entrare nel dettaglio delle funzionalità di VBScript, vediamo un primo esempio di pagina ASP che ci servirà per gli esempi futuri (listato 1). P L1 Questo semplice esempio (che ha solo scopo didattico), produce una pagina HTML con un elenco di frasi del tipo “Sono arrivato a... “ da 1 a 10. Nulla di eccezionale, ma che comunque ci introduce al mondo della programmazione. Nel codice della pagina, infatti, è presente una sola frase “Sono arrivato a”, mentre nella finestra del browser il testo viene ripetuto 10 volte, cosa impossibile 3/97 se avessimo realizzato una semplice pagina HTML. Il codice ASP vero e proprio si trova racchiuso tra <% e %>. Il processore ASP, nell’incontrare questi tag, sa che il loro contenuto non è un semplice codice HTML, da restituire così com’è alla pagina, ma una serie di istruzioni da eseguire. Non c’è limite al numero di volte in cui inserire i tag <% %>, ma sempre per motivi di prestazione è buona norma isolare il più possibile il codice ASP dal resto della pagina HTML. Non solo, così facendo il codice risulta notevolmente più chiaro da leggere e modificare, soprattutto se chi realizza la pagina HTML non è la stessa persona che programma anche il codice ASP. Per realizzare esempi più complessi, e soprattutto più utili rispetto al precedente, è ora necessario analizzare più da vicino le potenzialità di VBScript. Fondamenti di VBScript Abbiamo detto che una pagina ASP è un insieme di HTML con righe di codice interpretate, e che in questo corso utilizzeremo VBScript quale linguaggio per costruire la nostra applicazione.Vediamo allora le principali strutture messe a di- sposizione da VBScript, e come vengono utilizzate per costruire pagine ASP. Nel costruire pagine dinamiche, per quanto una sia diversa dall’altra, un programmatore ha normalmente alcune esigenze ricorrenti. Se ripensiamo all’elenco di foto delle vacanze, realizzate con un unico template, chi sviluppa ha bisogno di: 1. memorizzare il titolo della foto prelevato dalla base di dati (per poi compilare il template) 2. ripetere più volte il template (cioè, “ciclare” per tutte le foto di interesse) 3. decidere, in base all’input dell’utente, quali foto visualizzare VBScript, come molti linguaggi di programmazione, rende disponibili una serie di funzionalità che il programmatore può adottare per queste necessità. Una variabile, come vedremo tra poco, viene utilizzata proprio allo scopo di salvare informazioni di volta in volta diverse, come il titolo della foto nel nostro caso. Per ripetere un template sono impiegati i cicli, cioè dei costrutti (un costrutto è una serie di istruzioni, che solitamente hanno senso solo nella loro complessità) che ripetono una serie di istruzioni fino al verifi- carsi di una condizione limite. Per decidere come proseguire in seguito all’input dell’utente, infine, sono impiegate le espressioni condizionali. Vediamo nel dettaglio l’uso di queste strutture di programma. Variabili Una variabile, così come un documento salvato sul computer, è un contenitore di informazioni. Se realizzate un documento Word e lo salvate su disco fisso, questo è composto da due dati: il nome con cui avete salvato il documento, e il suo contenuto (ad esempio telefoni.doc è un documento che contiene l’elenco dei numeri telefonici dei vostri amici). Allo stesso modo, una variabile è l’unione di due elementi: un nome e un contenuto. Un’istruzione di questo tipo, ad esempio: telefono = “1234 567890” definisce una variabile, il cui nome è telefono, e il cui contenuto è la stringa (ovvero, l’insieme di caratteri) 1234 567890 (prestate anche attenzione al fatto che i doppi apici non sono parte del contenuto, ma servono da delimitatore). Le variabili sono un elemento fondamentale dei linguaggi 1a lezione di programmazione, e il motivo è evidente: sono utilizzate per memorizzare valori che dipendono dall’input dell’utente. Pensate a un programma che richiede d'inserire un numero, e lo moltiplica per due. Poiché non è dato sapere a priori il valore inserito dall’utente, useremo una variabile, ed effettueremo le operazioni con essa (vedi l'esempio 1). E1 riabile è un contenitore di valori, e che è possibile eseguire operazioni tra variabili. Tali operazioni, il cui risultato viene anch'esso assegnato a una variabile, sono dette espressioni, e sono composte da valori (come 2, “1234 567890”), variabili (come telefono) e operatori (+, *). Il risultato di un’espressione dipende però dal tipo di dato con il quale opera, e in dipendenza di esso i risultati possono essere diversi. L'espressione riportata nell'esempio 3 assegna alla vaE3 Anche se vedremo più avanti come riconoscere il valore inserito dall’utente, l’esempio precedente ci fa capire che è anche possibile assegnare a una variabile il risultato di un’operazione che coinvolge altre variabili. Tornando all’esempio di sito con foto, useremo alcune variabili che di volta in volta contengono il titolo della foto e la didascalia. Ci sono due modi per creare una variabile in VBScript. Il primo è chiamato dichiarazione implicita, e consiste nell’usare direttamente la variabile, ad esempio strSaluto = “Hello world” È anche possibile dichiarare esplicitamente la variabile prima dell’uso, con una forma del tipo riportata nell'esempio 2. E2 Questa seconda modalità è preferibile perché, quando viene utilizzata insieme alla direttiva Option Explicit, limita i problemi se digitate erroneamente i nomi delle variabili (come ad esempio strSluto al posto di strSaluto). Nel caso di dichiarazione implicita, infatti, le variabili vengono create automaticamente, ed è così più difficile accorgersi di aver commesso un errore, in quanto l’esecuzione della pagina non viene interrotta. Con Option Explicit, una direttiva che è possibile inserire in testa ad ogni pagina ASP, ogni variabile deve invece essere dichiarata, pena la non esecuzione della pagina. Tipi di dato e operatori Abbiamo detto che una va- 4/97 riabile c il valore 5. L'espressione invece riportata nell'esempio 4 produce come risulE4 tato 23, l’unione di 2 e 3. La differenza sta nel tipo di dato delle variabili. Nel primo caso si tratta di numeri, nel secondo caso, che utilizza stringhe (si distinguono grazie alla presenza dei doppi apici), è stata eseguita una concatenazione (ne riparleremo tra breve). Solitamente, ogni linguaggio di programmazione dispone di un certo numero di tipi di dato che è possibile e necessario impiegare nella costruzione dei programmi, ma in VBScript, e questa è un’altra differenza rispetto a Visual Basic, esiste un solo tipo Variant, ossia un tipo di dato particolare, nel senso che di volta in volta può rappresentare una stringa, un intero, una data, eccetera, in base al contesto nel quale viene utilizzato. Nell'esempio 5 il tipo E5 una variabile, come nell’esempio del sito con foto, dove è necessario ospitare più titoli e descrizioni. In questo caso si parla di array, e la dichiarazione è del tutto simile a quella di una variabile, come nell'esempio 6. E6 si è deciso di visualizzare 5 foto per pagina, un’espressione condizionale potrebbe venire impiegata per stabilire quando è il momento di spostarsi su una nuova pagina, con qualcosa del tipo elencato nel listato 4. L4 Espressioni condizionali Capita spesso che l’esecuzione di una riga di codice del programma dipenda dalla verifica di una condizione. Pensate a un sistema Bancomat: se il codice inserito è corretto, il sistema procede con il menu delle operazioni, altrimenti avverte dell’errore e richiede nuovamente l’inserimento del codice. Lo stesso si verifica in una pagina Web: in uno dei prossimi esempi vedremo come far cambiare l’aspetto di una voce di menu in dipendenza della scelta dell’utente. Anche in VBScript, come in quasi tutti i linguaggi, è possibile accertarsi del risultato di una condizione per proseguire in un modo o in un altro il flusso del programma. L'espressione riportata nel listato 2 verifica L2 quale tra le due variabili x e y ha un valore maggiore, e assegna di conseguenza la variabile strRisultato a uno solo dei due possibili valori. Se le condizioni da verificare sono più di due, è possibile impiegare una versione estesa rispetto a if...then...else, che prende il nome di if...then...elseif come indicato nel listato 3. L3 di dato è sempre Variant, ma rappresenta una data. Cicli Immaginate di acquistare alcuni testi da una libreria on line, come ad esempio Amazon. La procedura di acquisto termina normalmente con un riepilogo del vostro ordine, e molto probabilmente vi troverete in una pagina che presenta una tabella con l’elenco dei libri scelti. La pagina deve essere in grado, in dipendenza del numero di libri, di allungarsi e di accorciarsi secondo le esigenze (c’è chi acquista un solo prodotto, chi ne approfitta per rimpinguare l’intera biblioteca). Il programmatore che ha realizzato la pagina si è quindi preoccupato di ripetere un’operazione per più di una volta, fino al verificarsi di una condizione limite. In questo caso entrano in gioco i cicli, che in VBScript possono essere realizzati ricorrendo ai costrutti for...next, do...while o while...wend. Con il ciclo riportato nell'esempio 7 la variabile y vale E7 1,3,6,10,15... Il significato del ciclo è: incrementa la variabile “i” di una unità fino a che raggiunge il limite di 10. Nel caso riportato nell'esempio 8 il ciclo viene eseguito fintantoché la variabile “i” è inferiore o uguale a 5. E8 Array Negli esempi precedenti, a ogni variabile è stato associato un solo valore. Capita però che sia utile assegnare più valori a Nel caso del sito con l’elenco di foto delle vacanze, in cui 1a lezione Se estendiamo questo esempio, lo possiamo utilizzare per il nostro sito di foto on line, che prevede di suddividere le foto in pagine che ne contengono 5. Anche se ci manca qualche nozione sui database per poter scrivere il codice completo, questo avrà una forma simile a quanto riportato nell'esempio 9. zione. Per concatenare una stringa si utilizza l’operatore &, come nell’esempio 10. E9 Abbiamo per prima cosa definito due array, e abbiamo popolato il primo con l’elenco di città. Successivamente abbiamo valorizzato delle stringhe concatenando a un testo fisso il nome delle due città. Poiché il codice ASP è ospitato in HTML, nulla ci vieta di costruire stringhe che contengano tag, come nell’esempio seguente 11. Concatenare le stringhe Un’operazione spesso usata nel costruire pagine ASP con VBScript è la concatenazione di stringhe, ossia produrre una variabile stringa che è il risultato dell’unione di altre stringhe (o meglio, come dicevamo, di altre variabili di tipo Variant). Pensate al nostro esempio di foto on line. In testa alla pagina potreste voler visualizzare un testo in questa forma: “foto scattata a” seguito di volta in volta da un dato proveniente dalla base di dati. Per farlo avete bisogno di costruire una stringa composta da due parti, una fissa e una ogni volta diversa. Questa operazione prende il nome di concatena- E12 E10 E11 Per il browser non c’è nessun problema nel ricevere questa stringa, in quanto l’interprete ASP ha precedentemente risolto l’istruzione e l’ha convertita nel corrispettivo codice HTML, in modo del tutto trasparente per il client. Procedure Come gran parte dei lin- guaggi, anche VBScript dà allo sviluppatore la possibilità di accorpare più istruzioni in procedure, così da rendere il codice maggiormente leggibile e soprattutto riutilizzabile. Ne esistono di due tipi: Sub e Function. La prima è una procedura che, al termine dell’esecuzione, non restituisce un valore frutto dell’elaborazione, ma si limita a restituire il controllo al codice chiamante. Nel prossimo esempio vediamo invece la procedura Function che in questo caso accetta in input due stringhe e ne restituisce la concatenazione, come appare nell'esempio 12. Commenti Come per quasi tutti i linguaggi, anche VBScript prevede la possibilità d'inserire commenti nel codice. Per farlo esistono due sintassi equivalenti, la prima prevedere l’uso dell’apice singolo ‘, la seconda della parola chiave rem, entrambi inseriti all’inizio della riga da commentare (vedi l'esempio 13). E13 Questa veloce introduzione al mondo di VBScript è sufficiente per questo corso ASP. Vi consigliamo però di scaricare dal sito Microsoft il file di riferimento del linguaggio, totalmente gratuito, che vi aiuterà più di una volta mentre realizzate le vostre applicazioni. Lo potete trovare partendo da questo indirizzo: http:// msdn.microsoft.com/scrip ting/. 4 Anatomia di una pagina ASP ettiamo in pratica quanto appreso fino a qui e costruiamo un secondo, semplice esempio di pagina ASP (vedi il listato 5). Lo scopo di questa pagina è visualizzare la data e ora attuali. La direttiva language, che compare in testa alla pagina, istruisce il server Web relativamente al linguaggio utilizzato in questa pagina, in questo caso VBScript. Abbiamo già introdotto il ruolo della direttiva Option Explicit, un comodo controllo che possiamo inserire per cautelarci da eventuali errori di ortografia, così da utilizzare correttamente i nomi delle variabili in tutto il codice che scriviamo. Dim è la parola chiave utilizzata per definire le variabili che vengono utilizzare poco sotto, M 5/97 e che ospitano il mese, l’anno, il giorno, le ore e i minuti correnti. Poco sotto sono infatti utilizzate alcune funzioni che operano sulle date: la prima, now(), restituisce la data e ora corrente, mentre tutte le altre ne estraggono una parte (l’anno, il mese, il giorno e l’ora). La riga che ha il compito di visualizzare (write) una stringa composta dalla data e l’ora è quella composta dall’istruzione response.write, che vedremo meglio più avanti. Il risultato della pagina inviata al browser è quello presentato nella figura 1. Come dicevamo precedentemente, il server si occupa di eseguire il codice della pagina ASP e di restituire al browser il risultato dell’operazione. In effetti, se guardiamo il codice HTML giunto al browser (cosa che è possibile fa- L5 re in Internet Explorer 6 dal menu Visualizza - Sorgente), otteniamo il listato 6. Come vedete, il codice ASP è sparito. In realtà, è il server ad aver interpretato e sostituito le parti comprese tra <% e %>. Esiste un altro modo per aprire e chiudere una parentesi F1 1a lezione di codice all’interno della pagi- na, e si ottiene utilizzando i tag <script></script> insieme all’attributo runat=”server”. Vediamo come cambia l’esempio utilizzando i costrutti elencati nel listato 7. Attenzione però: benché il risultato sulla pagina sia simile a quello che si otterrebbe utilizzando i tag <% e %>, in realtà il codice racchiuso tra <script> e </script> viene interpretato alla fine della pagina, il che vuol dire dopo che è stato chiuso il tag <html>. Per questo motivo il tag <script> viene di norma utilizzato per racchiudere la definizione di procedure (sia sub, sia function) a loro volta richiamate da codice racchiuso da <% e %>. È possibile includere diverse sezioni di codice all’interno di una pagina, per esempio la presenza di tag HTML con codice di programma. Supponiamo di dover decidere, in base all’ora di visita dell’utente, se salutarlo con un “buongiorno”, oppure con un “buonasera”. In questo caso sfruttiamo il contenuto del listato 8. Una piattaforma orientata agli oggetti ASP è una piattaforma che funziona secondo un modello a oggetti a cui il programmatore fa riferimento nella costruzione delle pagine. Un oggetto, nel caso di ASP, è una struttura software definita all’interno di una pagina, che permette di svolgere particolari compiti, come estrarre i dati inviati dall’utente, inviare stringhe di testo al browser o mantenere informazioni in memoria; “re- L8 sponse”, che abbiamo incontrato nell’esempio poco fa, è un oggetto ASP. Interagire con l’utente Affrontiamo ora una problematica comune a tutti i siti dinamici: come scambiare informazioni con i visitatori del sito. Possiamo impiegare un form HTML, che consente di realizzare una pagina con campi che l’utente può compilare e inviare. In particolare, nell’esempio del nostro corso, si vuol dare la possibilità ai visitatori di inviare commenti e che forniscano una descrizione di loro stessi. Per il momento ci limiteremo a stampare i dati a video, ma nella terza puntata vedremo come è possibile memorizzare queste informazioni in un database. Costruiamo un semplice form per inserire il nome e cognome dell’utente, senza preoccuparci della resa visiva, e quindi senza adottare tabelle di layout o fogli di stile, ma cercando invece di rendere il codice leggibile. Per prima cosa proviamo a farlo in HTML, così da ottenere qualcosa di simile alla figura 2 Il codice HTML del form è riportato nel listato 9. Nell’esempio sono state inserite due caselle di testo (tag input di tipo text) per contenere il nome e cognome della persona. Prestate particolare atL6 tenzione al valore dell’attributo name (txt_nome e txt_cognome), utilizzato dal codice ASP allo scopo di estrarre i valori inseriti dall’utente. È inoltre presente un tag input di tipo submit, che viene rappresentato sulla pagina come un pulsante da premere per inviare i dati inseriti. In questa pagina non è necessario inserire nessuna riga dere come è stata realizzata consultando il listato 10. Dopo aver dichiarato due variabili per contenere il nome e cognome del visitatore, queste sono valorizzate utilizzando l’oggetto request, che come abbiamo visto poco fa consente al programmatore ASP di accedere ai dati inseriti dagli utenti. Estrarre il nome e cognome è davvero semplice, L9 L10 di codice ASP. Essa si limita infatti ad accettare il nome e cognome del visitatore, ma demanda a un’altra pagina le operazioni da eseguire sui dati (nel nostro caso, è sufficiente visualizzarli da qualche parte). Per capire quale pagina si occupa di ciò, basta guardare il valore dell’attributo action presente nella prima riga del form, che indica a chi passare il controllo insieme alle informazioni inserite. Nel nostro caso la pagina si chiama visnomecognome.asp e non ci resta che ve- poiché si utilizza una sintassi del tipo request.form (nome_controllo), dove nome_controllo è il valore dell’attributo name del campo presente nel form. Il risultato finale è presentato nella figura 3. F3 L7 F2 Post e get Esistono due possibilità per inviare i dati a una pagina Web. Il primo, che abbiamo visto nell’esempio precedente, si chia- 6/97 1a lezione ma “post” e si realizza utiliz- zando un form il cui attributo method ha come valore “post”. Una seconda possibilità è di utilizzare il metodo “get”, valorizzando di conseguenza l’attributo method. Ma in cosa differiscono le due possibilità? Con get, i dati vengono non solo inviati alla seconda pagina, ma anche visualizzati nella barra indirizzi del browser, un po’ quello che succede quando utilizziamo Google per effettuare una ricerca (figura 4). Il vantaggio, in questo caso, è che possiamo aggiungere la pagina ai preferiti e ritornarci in futuro senza dover reinserire il termine di ricerca. Visti i vantaggi dati dal metodo get, sembrerebbe inutile poter disporre di un’ulteriore modalità. In realtà, il metodo get presenta due importanti limitazioni: è possibile inviare solo 1 o 2 Kbyte, visualizzare in chiaro dei dati sulla barra degli indirizzi non è accettabile per informazioni sensibili. Quando s’inviano password o codici utente, perciò, è molto meglio impiegare il metodo post, che non ha limiti di lunghezza e che non lascia alcuna traccia. Se si utilizza il metodo get, la sintassi da utilizzare è request.querystring(nome_campo). Altri controlli HTML nei form L’esempio che abbiamo realizzato fino a qui è alquanto semplice, ma basta poco di più per realizzare form completi, utilizzando non solo caselle di testo, ma anche caselle di selezione, checkbox e radio button. Poiché si tratta di elementi HTML, vi rimandiamo al corso Webmaster per una descrizione approfondita (vedi la settima lezione pubblicata sul numero di maggio e riportata in PDF sul numero di settembre). Esistono inoltre diverse risorse on line dedicate all’argomento, F4 come ad esempio questo tutorial in inglese [http://mastercgi.com/howtoinfo/formtutorial.shtml] o questo in italiano [http://www.html.it/guida/index.html#forms] Cerchiamo quindi di estendere l’attuale form, includendo la possibilità di specificare l’età, il sesso, gli hobby e alcune note. Il risultato è visibile in figura 5. Analizziamo il codice della pagina di risposta, nel listato 11, mentre tralasciamo il codice del form, del tutto simile all’esempio precedente. L’unica novità è introdotta dai checkbox relativi agli hobby, che prevedono la possibilità di una selezione multipla. In questo caso non è più sufficiente estrarre il valore del campo, che diventa infatti una collezione di valori, ed è opportuno ricorrere al costrutto for each, che consente di iterare tra tutte le corrispondenze degli hobby scelti dal visitatore e di visualizzarli su linee diverse della pagina. Poiché for each lavora con oggetti di tipo collezione, e poiché l’intero form può essere considerato una collezione di valori, è possibile sfruttare lo stesso costrutto per estrarre tutti i valori di un form. Vediamo il listato 12. In questo caso viene estratto per prima cosa il nome del campo del form, seguito dal valore. Scriviamo request.form (campo) e non, request.form (“campo”), in quanto non vogliamo accedere al contenuto dell’elemento “campo” del form (che non esi- L12 L13 ste), ma piuttosto al valore che la variabile campo contiene a ogni iterazione. Inviare dati alla pagina: l’oggetto response L’oggetto response visualizza sulla pagina il risultato delle operazioni di elaborazione. Il metodo più usato dell’oggetto response è effettivamente write, che invia al client una stringa di caratteri. Visto che è una delle operazioni più diffuse in una pagina ASP, esiste anche un modo più veloce per inviare dati al client, e consiste nell’utilizzare il costrutto <%=espressione%>. In particolare, le 2 righe di codice mostrate nell'esempio 14 sono del tutto equivalenti. Attenzione però, nel secondo caso è imL11 possibile inserire più linee di codice all’interno di <%=%>. In questo corso ne presentiamo un altro che si rivela spesso molto utile, il metodo redirect. Response.redirect invia invece il browser dell’utente a un’altra pagina, magari in base alla selezione della lingua preferenziale. Per farlo è sufficien- te una porzione di codice simile a quanto riportato nel listato 13. Per ogni lingua sono state create delle cartelle che ospitano le pagine ASP e, in base alla selezione dall’utente, il browser viene indirizzato nella directory corretta. Abbiamo introdotto un nuovo costrutto, select case, molto utile quando si vuole confrontare il valore di una variabile con un elenco di possibilità. L’alternativa sarebbe stata quella di utilizzare una lunga, e poco chiara, lista di if, elseif, end if. F5 E14 7/97 1a lezione 5 Rendere il codice leggibile e facile da modificare: gli “include ASP” ensate a una problematica concreta: volete aggiungere al sito che stiamo sviluppando per Mario Rossi una barra che contenga alcune voci di menu con l’elenco delle sezioni principali. Non siete però certi che il numero delle sezioni rimanga invariato nel tempo, magari perché non sapete quali avranno più successo e quali, invece, abbandonare in futuro. Se nel frattempo avete realizzato diverse pagine, e inserito in ciascuna il menu, il lavoro di aggiornamento diventerà ogni giorno più impegnativo. Per evitare tale genere di problematiche, potete realizzare file che contengono parti di codice o di pagina da riutilizzare in più punti, e includerli secondo necessità. Tutto ciò sarebbe possibile anche senza ricorrere a IIS, utilizzando i file di tipo SSI (Server Side Include), ma in questo modo potete non solo riutilizzare il codice HTML, ma intere porzioni di codice. Proviamo allora a costruire una pagina che includa codice proveniente da una seconda, al solo scopo di visualizzare la data corrente. Ecco per prima cosa la pagina da includere, che chiameremo copyright.asp, come illustrato nel listato 14. A questo punto proviamo a costruire una semplice pagina che includa copyright.asp, come riportato nel listato 15. Se provate a eseguire la pagina, otterrete il risultato di figura 6. Come vedete, oltre al contenuto della pagina chiamata direttamente, è stato eseguito il codice di copyright. asp, nel punto in cui è stata in- P F6 8/97 L16 L15 serita la direttiva #include file. Esistono due tipologie di inclusioni. La prima, quella riportata nell’esempio, cerca il documento da includere rispetto alla posizione del file chiamante. In tal caso, quindi, il file chiamante e copyright.asp si trovano nella stessa cartella. Se l’include avesse invece avuto una forma del tipo <!- - #include file="car tella/copyright.asp"--> il file chiamante si sarebbe trovato allo stesso livello della directory “cartella”. La seconda tipologia di inclusione prevede l’utilizzo della direttiva: <!- - #include virtual="copyright.asp"- -> con virtual al posto di file. In tal caso, al momento di includere il file, IIS non si basa sulla directory corrente, ma bensì sulla “root directory” del sito. La root directory è la cartella principale che contiene i file della vostra applicazione Web, indipendentemente dal fatto che abbiate creato altre sottocartelle. Un uso accorto ed efficace della tecnica degli include vi permette di risparmiare un bel po’ di lavoro ed è utile, non appena avete finito di costruire il template HTML della pagina, spendere un po’ di tempo per capire dove sia meglio effettuare i “tagli” che diventeranno include, così da rendere il codice più leggibile e riutilizzarlo più volte in contesti diversi. Ricordatevi che gli include possono contenere non solo il codice HTML, ma quasi sempre anche codice ASP. Per tale motivo, parti di pagina che potrebbero non sembrare candidate a diventare un include, spesso lo sono. Ritornando all’esempio del menu, come ci comportiamo se l’esigenza è di evidenziare la voce di menu con la sezione corrente, e lasciare le altre voci invariate? La soluzione più semplice potrebbe sembrare quella di realizzare include diversi per ogni sezione, ognuna con la voce di sezione di un colore diverso. Tale soluzione aggiunge pochi vantaggi, in quanto è comunque necessario gestire e aggiornare tanti include quante sono le sezioni. In realtà, è possibile utilizzare un solo include e sfruttare alcune righe di codice VBScript. Il risultato finale è quello della figura 7. Si tratta di realizzare un include per il menu a sinistra sulla pagina che evidenzi in grassetto la sezione corrente (vedi il listato 16).Notate come sono stati costruiti i link per ogni sezione: oltre al nome della pagina ASP di destinazione compare un parametro, il cui valore indica la sezione di destinazione. In questo modo, quando il visitatore clicca su un link del menu, oltre a richiedere il caricamento della pagina corrispondente, invia un parametro con il nome della sezione. A questo punto, L14 utilizzando una condizione, il codice ASP dell’include verifi- F7 ca se il parametro passato (salvato nella variabile strSezione) corrisponde a quello della sezione che sta per essere visualizzata. In caso affermativo, la sezione compare in grassetto e senza link (non serve metterlo, visto che siamo già al suo interno). L'intestazione, i piè di pagina, i menu, la casella di ricerca e il logo sono ottimi candidati per diventare include. Per concludere l’esempio, copiamo il codice del form nella pagina scrivimi.asp la cui unica funzione consiste nel visualizzare i dati inseriti. Per il momento il sito di Mario Rossi offre poche possibilità: una home page e la navigazione tra le diverse sezioni. Lo abbiamo però costruito in modo che sia facile modificarlo ed estenderlo. Nella prossima puntata vedremo come. Web Developer ASP - Lezione 1 esempio 1 numero = <valore inserito dall’utente> moltiplicazione = numero * 2 esempio 2 Dim strSaluto strSaluto = “Hello world” esempio 3 a = 2 b = 3 c = a+b esempio 4 a = “2” b = “3” c = a+b esempio 5 Dim datOggi datOggi = now() esempio 6 dim foto(3) foto(0) = “Foto di Parigi” foto(1) = “Foto di Londra” foto(2) = “Foto di Roma” esempio 7 y = 0 For i = 1 to 10 y = y + i Next i esempio 8 i = 0 while i <= 5 i = i + 1 wend esempio 9 i = 0 while i <= 5 ...qui va il codice che visualizza la foto... i = i + 1 wend 9/97 esempio 10 Dim foto(2), luogo(2) luogo(0)=”Venezia” luogo(1)=”Firenze” stringa(0) = “Foto scattata a “ & luogo(0) stringa(1) = “Foto scattata a “ & luogo(1) esempio 11 stringa = “<b>Questo testo è in grassetto</b>” esempio 12 Function ConcatenaStringhe(stringa1 as String, stringa2 as String) ConcatenaStringhe=stringa1 & stringa2 End Function Una riga di codice che richiama questa funzione potrebbe agire come segue: Dim strStringa1, strStringa2, strContatenata strStringa1 = “Pc “ strStringa2 = “Open” strConcatenata = ConcatenaStringhe(strStringa1,strStringa2) esempio 13 ‘Questa riga è stata commentata esempio 14 <% response.write “Gentile ” & nomeutente “, hai concluso l’operazione con successo” %> <%=“Gentile ” & nomeutente “, hai concluso l’operazione con successo” %> 10/97 Cliccate qui per accedere alla versione elettronica dei listati. Si aprirà una pagina Web con i link ai listati delle quattro puntate del corso. Cliccate sul link desiderato e selezionate "Salva" dalla finestra visualizzata da Internet Explorer per indicare dove volete salvarli. Gli esempi sono in formato ASP e perciò non direttamente visualizzabili nel browser a meno di avere installato o attivato il servizio di Internet Information Server sul vostro PC, nella versione per client Windows XP. Listato 1 primapagina.asp <html> <head><title>La mia prima pagina ASP</title></head> <body> Questo testo non è codice <br> <% for i = 1 to 10 response.write "Sono arrivato a " & i & "<br>" next %> </body> </html> 11/97 Listato 2 If x > y then strRisultato = “x è maggiore di y” else strRisultato = “y è maggiore o uguale a x” end if 12/97 Listato 3 If x > y then strRisultato = “x è maggiore di y” elseif x = y then strRisultato = “y è uguale a x” else strRisultato = “y è maggiore di x” end if 13/97 Listato 4 If numeroFotoPagina <= 5 then ... <qui va il codice per visualizzare l’elenco delle foto> ... else ... <cambia pagina> ... end if 14/97 Listato 5 OGGI.ASP <%@ language="VBScript" %> <%Option Explicit%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>La mia prima pagina ASP</title></head> <body> <% Dim anno,mese,giorno,data,ore,minuti anno = year(now()) mese = month(now()) giorno = day(now()) ore = hour(now()) minuti = minute(now()) response.write ("Oggi è il " & giorno & "/" & mese & "/" & anno & ", ore " & ore & ":" & minuti) %> </body> </html> 15/97 Listato 6 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>La mia prima pagina ASP</title></head> <body> Oggi è il 18/8/2003, ore 23:38 </body> </html> 16/97 Listato 7 OGGI2.ASP <%@ language="VBScript" %> <%option explicit%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>La mia prima pagina ASP</title></head> <body> <script language="VBScript" runat="server"> Dim anno,mese,giorno,data,ore,minuti anno = year(now()) mese = month(now()) giorno = day(now()) ore = hour(now()) minuti = minute(now()) response.write ("Oggi è il " & giorno & "/" & mese & "/" & anno & ", ore " & ore & ":" & minuti) </script> </body> </html> 17/97 Listato 8 DATAUTENTE.ASP <% if hour(now()) < 16 Then %> <b>Buongiorno!</b> <% else %> <b>Buonasera!</b> <% end if %> 18/97 Listato 9 NOMECOGNOME.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Un form</title> </head> <body> <b>Inserisci il tuo nome e cognome</b> <form action="visnomecognome.asp" method="post"> Nome: <input type="text" name="txt_nome"> <br> Cognome: <input type="text" name="txt_cognome"> <br> <input type="submit" value="Invia"> </form> </body> </html> 19/97 Listato 10 VISNOMECOGNOME.ASP <%@ language="vbscript" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>Il risultato del form</title></head> <body> <% Dim nome, cognome nome = request.form("txt_nome") cognome = request.form("txt_cognome") response.write ("Ciao <b>" & nome & " " & cognome & "</b>!") %> </body> </html> 20/97 Listato 11 VISDATICOMPLETI.ASP <%@ language="VBScript" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>Il risultato del form</title></head> <body> <% Dim nome, cognome, sesso, eta, hobby, note nome = request.form("txt_nome") cognome = request.form("txt_cognome") sesso = request.form("rad_sesso") eta = request.form("sel_eta") note = request.form("txa_note") response.write response.write response.write response.write ("Nome: " & nome & "<br>") ("Cognome: " & cognome & "<br>") ("Sesso: " & sesso & "<br>") ("Età: " & eta & "<br>") For Each hobby in request.form("chk_hobby") response.write ("Hobby: " & hobby & "<br>") Next response.write ("Note: " & note & "<br>") %> </body> </html> 21/97 Listato 12 FOREACH.ASP <%@ language="VBScript" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>Il risultato del form</title></head> <body> <% Dim campo For Each campo in request.form response.write (campo & ": " & request.form(campo) & "<br>") Next %> </body> </html> 22/97 Listato 13 LINGUA.ASP <%@ language="VBScript" %> <%option explicit%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>Response.redirect</title></head> <body> <% Dim strLingua strLingua=request.querystring("lingua") select case strLingua case "it" response.redirect "/it/default.asp" case "fr" response.redirect "/fr/default.asp" case else response.redirect "/en/default.asp" end select %> </body> </html> 23/97 Listato 14 COPYRIGHT.ASP <%= "Copyright &copy; 2003 Mario Rossi - Oggi è il " & day(now()) & "/" & month(now()) & "/" & year(now())%> 24/97 Listato 15 INCLUDEFILE.ASP <%@ language="VBScript" %> <%option explicit%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>Il sito di Mario Rossi</title></head> <body> <h3>Questo è il sito di Mario Rossi</h3> <h4>Ci trovate alcune foto e il mio weblog</h4> <!--#include file="copyright.asp"--> </body> </html> 25/97 Listato 16 INCLUDEMENU.ASP <% Dim strSezione strSezione = request.querystring("sezione") %> <table width="100"> <tr> <td><h3>Menù</h3></td> </tr> <tr> <td> <% If strSezione = "" Then %> <b>Home</b> <% Else %> <a href="menuasp.asp">Home</a> <% End If%> </td> </tr> <tr> <td> <% If strSezione = "foto" Then %> <b>Foto</b> <% Else %> <a href="foto.asp?sezione=foto">Foto</a> <% End If %> </td> </tr> <tr> <td> <% If strSezione = "scrivimi" Then %> <b>Scrivimi</b> <% Else %> <a href="scrivimi.asp?sezione=scrivimi">Scrivimi</a> <% End If %> </td> </tr> </table> 26/97 2a lezione A scuola con PC Open Web Developer ASP di Antonio Volpon 1 La natura senza stato del Web a scorsa puntata ci siamo lasciati dopo aver imparato perché è utile costruire i siti Web ricorrendo ad un linguaggio lato server, e abbiamo cominciato ad esplorare il mondo di ASP, la piattaforma Microsoft per lo sviluppo di siti dinamici. Lo scopo della nostra esplorazione, e più in generale di questo corso, è quella di aiutare Mario Rossi a costruire un proprio sito personale, un insieme di pagine con la presentazione dell’autore, una sezione con le foto e la possibilità di inviare qualche commento. La versione del sito finora realizzata è allo stato embrionale, ma va detto che ci siamo concentrati più che altro sulle basi di Visual Basic Script, il linguaggio che utilizziamo per costruire pagine ASP. Abbiamo poi introdotto il ruolo di alcuni oggetti, punti cardine per poter interagire con i dati inseriti dagli utenti: l’oggetto request e response. In questa puntata, partendo dagli esempi già visti, introdurremo il ruolo di altri importanti oggetti, come application e session, fondamentali quando è necessario memorizzare le informazioni per tutto il tempo di comunicazione con l’utente. L La comunicazione fra il browser e il server Per introdurre i concetti di questa puntata è necessario che ci soffermiamo ad analizzare da vicino il funzionamento della comunicazione tra un browser e il server Web che ospita le pagine ASP. Se ricordate quello che abbiamo detto la scorsa puntata, il browser, su richiesta dell’utente, contatta il server Web, il quale verifica l’esistenza della pagina richiesta, la esegue, e restituisce il risultato al browser. La comunicazione tra il browser e il server inizia con la richiesta della pagina e termina con la ricezione dell’ultimo carattere della risposta. Supponete ora che lo stesso utente richieda una seconda pagina allo stesso server Web. La probabilità che questo si verifichi è in effetti elevata (difficilmente navighiamo in Internet visitando solo la home page dei siti). La situazione non cambia. Anche in questo caso la comunicazione è di tipo “mordi e fuggi”: inizia con la richiesta e termina con la sua esecuzione. Questo tipo di connessione si chiama per l’appunto stateless (senza stato) in quanto il server e il client ristabiliscono IL CALENDARIO DELLE LEZIONI Lezione 1: Da sito statico a dinamico Lezione 2: Campi nascosti in un form • La durata delle sessioni e delle applicazioni • La gestione degli errori Le prossime puntate Portare il sito sul server • La natura senza stato del Web • I cookie • Dai cookie alle sessioni • L’oggetto “application” 27/97 ogni volta la comunicazione. Il fatto che la connessione tra il browser e il server Web duri solo per lo stretto necessario ha delle importanti conseguenze, prima fra tutte l’incapacità del server di sapere che lo stesso utente sta richiedendo pagine diverse. Immaginate di dover acquistare un libro on line. Difficilmente riuscirete a completare questa operazione in un’unica pagina, molto più probabile che vi capiti di scegliere il libro da un elenco, lo aggiungiate al carrello, procediate all’acquisto inserendo i vostri dati e il numero di carta di credito e riceviate conferma del buon esito dell’operazione. Ma se il server chiude la comunicazione ogni volta, com’è possibile che si ricordi di voi, e soprattutto dello stato con il quale vi eravate lasciati? In effetti sono state sviluppate alcune metodologie per cercare di arginare i problemi derivati dalla mancanza di stato della connessione, e ne analizziamo ora i due principali. Lezione 3: ASP e i database Lezione 4: Uso avanzato dei database In uno degli esempi della scorsa puntata l’utente del sito di Mario Rossi aveva la possibilità di comunicare le proprie impressioni riguardanti il sito utilizzando un form, simile a quello di figura 1. Immaginate che l’invio dei dati non sia l’ultima interazione che l’utente svolge con il sito, ma che vogliate successivamente chiedergli, nel caso selezioni come 1 Hobby la voce “musica”, qual è il cantautore preferito. In questo modo, al pari dell’acquisto su internet, l’interazione tra il browser e il server non avviene più su di un’unica pagina, ma con due pagine distinte. Poiché la comunicazione viene ogni volta interrotta, dobbiamo far sì che il browser “ricordi” al server come era terminata la comunicazione precedente, così che i dati già inseriti non vengano perduti. Per farlo integriamo la seconda pagina con alcuni campi nascosti nel form, che compileremo con i dati già inseriti (listato 1 contenuto nel CD Guida). Come possiamo vedere dal listato, per primo è inserito un controllo che verifica il contenuto della collezione degli hobby selezionati dall’utente. In particolare, poiché è possibile selezionare più di hobby, vengono man mano verificati tutti quelli selezionati: se uno di questi è “Musica”, il valore di una variabile di supporto pasI listati citati nell’articolo sono nel CD Guida nella sezione “Corsi Open Master” 2a lezione 2 sa da false (falso) a true (vero). A questo punto la pagina visualizza due elementi diversi, a seconda della selezione. Nel caso non sia stata selezionata la voce Musica, la condizione è false e all’utente viene presen- tata una semplice risposta. Se invece l’utente ha espresso il suo interesse per la musica viene presentato un altro form, nel quale si chiedono ulteriori informazioni, ad esempio il nome del gruppo o del cantante preferiti. Come abbiamo detto prima, però, questa pagina è slegata dalla precedente, e il server Web non è in grado di mantenere la comunicazione. Senza prendere degli oppor- tuni provvedimenti, non siamo in grado di sapere a quale utente del sito appartiene la preferenza per un cantante o un gruppo. Per ovviare a questa problematica nel sorgente della pagina sono stati inseriti dei campi input, come quelli normalmente utilizzati per richiedere informazioni all’utente. In questo caso l’attributo type è però valorizzato con hidden, ad indicare che nella pagina questi controlli non saranno visibili. A prima vista potrebbe sembrare che controlli non visibili siano di poca utilità, ma il nostro scopo è semplicemente di usarli e completarli con i da- ti che l’utente ha inserito nella pagina precedente. Ce ne rendiamo conto se osserviamo il sorgente della pagina inviata al browser, simile a quello presente nel listato 2. Il funzionamento di un campo nascosto è del tutto simile a quello di un campo usato per effettuare una selezione. Quando l’utente indica il nome del cantante o del gruppo e preme Invia, al server non viene inviata solo quest’ultima informazione, ma anche i dati relativi all’utente precedentemente compilati. Ecco perché la pagina di risposta (figura 2) è in grado di elencare tutte queste informazioni. di risposta di Mario Rossi potrebbe richiedere al browser di memorizzare il nome di Giorgio. Le successive pagine del sito di Mario Rossi sono in grado di interrogare il browser di Giorgio chiedendo di verificare se per caso, in passato, sia stato memorizzato il nome dell’utente, e in caso affermativo di inviare questa informazione al server. Il cookie rappresenta quindi un tipo di informazione che non si perde ogni volta che viene chiusa la comunicazione tra browser e server, poiché viene memorizzata nella macchina dell’utente e inviata ogni volta che il server ne faccia richiesta. Per vedere come cambia l’esempio precedente se decidiamo di utilizzare un cookie al posto dei campi nascosti potete osservare l’esempio del listato 3. In questo caso i campi nascosti sono sostituiti dall’istruzione response.cookie(variabile) = valore, che ha lo scopo di far memorizzare al browser una variabile e il relativo contenuto. Nella pagina di risposta (listato 4), vediamo invece che la semplice istruzione request.cookie(variabile) serve per estrarre il contenuto della variabile. perduto quando l’utente chiude il browser. Ad ogni cookie è però possibile associare una data di scadenza, che indica il tempo per il quale il browser memorizza (tipicamente su disco fisso) questa informazione. Questo tipo di cookie è utile in 2 I cookie mpiegando i campi nascosti abbiamo aggirato il limite della comunicazione Web senza stato, ma anche questa soluzione porta con sé alcune problematiche. Nel caso della libreria on line di cui parlavamo precedentemente, utilizzare dei campi nascosti potrebbe rivelarsi una soluzione poco pratica, perché sono molte le informazioni da memorizzare nel corso delle selezioni. L’ultima pagina, quella di acquisto effettivo, dovrebbe contenere tanti campi nascosti quante sono le informazioni da salvare, con il rischio di commettere qualche errore nella costruzione del codice e soprattutto di appesantire inutilmente la pagina. Per questo motivo esiste una diversa soluzione a questo problema, a cui si ricorre utilizzando le sessioni e i cookie. Vediamo di capire come operano. Ogni browser Web (a meno che l’utente non decida di limitare questa funzionalità modificando le opzioni del browser) ha la possibilità di salvare sul computer dell’utente alcune informazioni (chiamate cookie) su richiesta del server. Si tratta di un semplice file nel quale gli sviluppatori del sito possono memorizzare alcune informazioni, ad esempio il nome dell’utente. Poniamo che Giorgio visiti il sito di Mario Rossi, e che compili il form indicando il suo nome. La pagina I 28/97 Cookie temporanei e a scadenza Il tipo di cookie che abbiamo utilizzato nell’esempio precedente è di tipo temporaneo: il contenuto delle variabili viene La privacy e gli utenti Da quello che abbiamo appena visto è facile capire come i cookie siano un ottimo strumento per memorizzare e successivamente reperire informazioni circa i nostri utenti. Va però detto che nel corso degli anni ai cookie è stata associata una nomea poco edificante, tutto questo proprio perché sono usati per memorizzare le preferenze degli utenti, oltre che dati personali e sensibili. Cercate quindi di limitare l’uso dei cookie per le situazioni in cui il loro impiego faciliti realmente la navigazione dell’utente, ed evitate di memorizzare dati che possano in qualche modo lederne la privacy. Ricordate inoltre che ogni browser che si rispetti dà all’utente la possibilità di disabilitare i cookie (figura 3), per cui non fate affidamento sul fatto che sia sempre possibile salvarli sul computer del visitatore: un sito che si rispetti deve poter funzionare anche senza ricorrere ai cookie. 3 2a lezione situazioni in cui l’utente visita spesso un sito e non vuole inserire ogni volta alcuni dati ricorrenti, come ad esempio quelli di autenticazione. Un’altra situazione è data dai siti che riescono in questo modo a capire quante volte ogni singolo utente torna a vi- sitare il loro sito. Si tratta di un’informazione molto interessante in termini di marketing Web, perché misura non solo il numero di pagine visitate, ma fornisce una stima molto verosimile legata al singolo visitatore. Il caso del nostro Mario Rossi è però molto più semplice: a Mario inte4 ressa semplicemente presentare una scritta sulla home page che saluti il visitatore affezionato, come vediamo in figura 4. Il listato 5 affronta questa problematica. Abbiamo introdotto una modifica alla home page del sito di Mario Rossi, così che distingua l’utente alla prima visita rispetto all’utente abituale. Come prima cosa verifichiamo se è stato salvato un cookie chiamato numerovisite. Se così non è, prepariamo una stringa contenente il messaggio per il nuovo visitatore. Se è un utente abituale questo ha un cookie memorizzato sul computer e ne estraiamo il valore, cioè il numero di volte che l’utente ha visitato questa pagina. In ognuno dei due casi salviamo una copia del cookie sulla macchina dell’utente incrementando di 1 il valore corrente. Subito dopo, con il metodo Expired della collezione cookies andiamo ad indicare la data di sca- denza del cookie, in notazione inglese (e quindi il 31 dicembre del 2004). Dopo questa data il cookie sarà cancellato definitivamente dalla macchina. Per provare il funzionamento visualizzate la pagina sul vostro browser e ricaricatela per alcune volte: vedrete aumentare il contatore. Adesso chiudete tranquillamente il browser e successivamente provate a caricare nuovamente la pagina: vi accorgerete che l’informazione sul numero di visite non riparte da zero, ma dall’ultimo valore salvato. È evidente che il cookie è stato memorizzato nel vostro computer e non è andato perso con la chiusura del browser. 3 Dai cookie alle sessioni inora abbiamo parlato della mancanza di stato nella comunicazione tra server e client e di quali accorgimenti è possibile adottare per superare questo limite (campi nascosti in un form e cookie). La tecnologia ASP, insieme a IIS (Internet Information Services) rende disponibile un’altra interessante possibilità, che si basa sull’uso di cookie temporanei: le sessioni. Di norma, quando un utente richiede la prima pagina di un sito realizzato in ASP, il server IIS tenta di inviare un cookie di sessione. Il contenuto del cookie non è nient’altro che una lunga stringa generata dal server in modo casuale, in modo da limitare al massimo la possibilità che due utenti del sito utilizzino contemporaneamente la stessa stringa. A questo punto il server ha la possibilità di salvare in una propria area di memoria quelle informazioni riguardanti l’utente che è comodo avere sempre a disposizione (come il suo nome utente, il carrello elettronico e così via). Etichetta questa area di memoria con la stessa stringa che ha inviato all’utente. Ogni volta che l’utente richiede una pagina del sito il server interroga il browser e riceve il contenuto del cookie (chiamato cookie di sessione), ed estrae le informazioni che sono state etichettate con la F 29/97 stessa stringa. È un po’ come se l’utente disponesse dell’unica chiave in grado di aprire la serratura di un lucchetto che custodisce i proprio dati. Il vantaggio di usare le sessioni invece dei soli cookie temporanei è che le informazioni non sono salvate sul computer dell’utente, dove esistono dei limiti di dimensioni per i dati che è possibile memorizzare, ma direttamente sul server, soluzione che migliorare le prestazioni. L’unica informazione che il browser dell’utente deve recepire è la stringa generata casualmente, e nient’altro. Le sessioni in ASP Ma come si usano le sessioni in ASP? Vediamo un esempio, che trovate nella cartella cookie degli esempi inclusi nel CD Guida che accompagna la rivista. Si tratta di una variazione della pagina che finora abbiamo realizzato per Mario Rossi. In particolare, se eseguite il file personalizza.asp (riportato nel listato 6), vi trovate di fronte ad un form per modificare il colore di sfondo dell’intero sito (il form lo abbiamo riportato in figura 5). Selezionate a questo punto un colore e inviate i dati: come era lecito aspettarsi, il colore di sfondo è stato variato secondo la vostra scelta. Non solo: se selezionate altre sezioni dalla barra di navigazione posta sulla sinistra (in figura 6 presentiamo la sezione che conterrà le foto di Mario Rossi), il colore selezionato viene mantenuto. Passiamo ad analizzare il codice di personalizza.asp per capire come è stata realizzata. Lasciamo stare per un attimo cosa succede all’inizio della pagina e concentriamoci sul codice che segue l’inclusione di includemenu.asp. Qui è presente un form contenente l’elenco dei colori disponibili. La action del form, che come abbiamo visto la scorsa puntata serve per indicare la pagina a cui dirigersi una volta premuto il pulsante di invio, contiene una particolarità. L’action corrisponde infatti alla stessa pagina personalizza.asp, il che vuol dire che dopo aver inviato i dati del form viene ricaricata la stessa pagina. Potrebbe a prima vista sembrare che questa operazione vanifichi tutti i propositi di estrarre il colore selezionato, ma non è così. Se guardate quello che suc- 5 6 cede proprio prima del form, noterete la presenza di una condizione, la quale si preoccupa di verificare in quale dei due possibili stati (prima di inviare il form, dopo aver inviato il form) si trova la pagina. Viene in particolare estratto il valore del campo colore: se il contenuto è una stringa vuota vuol dire che la pagina è stata selezionata digitandone il link nella barra degli indirizzi del browser o semplicemente selezionando un link dal menu sulla sinistra, altrimenti è caricata do- 7 po aver inviato il form. Nel primo caso si invita l’utente a selezionare il colore (Seleziona un colore di sfondo), nel secondo caso lo avvertiamo della selezione compiuta (Ho cambiato il colore di sfondo di tutte le sezioni secondo la tua scelta). La tecnica che abbiamo appena visto, dove la pagina di partenza e di destinazione di un form è la medesima, viene spesso usata da chi sviluppa siti Web. I vantaggi di questo tipo di soluzione sono diversi. Per prima cosa la pagina da gestire è unica: se un domani volete aggiungere un nuovo campo, dovete aggiornare una sola pagina. Non solo: se avete necessità di controllare i dati inseriti dall’utente, e questo commette qualche errore, potete agevolmente presentare dopo l’elenco degli errori il form di partenza, come tra l’altro succede nel nostro caso (anche se con un include avreste probabilmente potuto ottenere lo stes- so risultato). Rimane a questo punto da vedere come viene memorizzato il valore del colore per tutte le pagine del sito. In testa alla pagina, poco dopo il titolo, viene replicata la stessa condizione. In questo caso lo scopo è diverso: abbiamo utilizzato un cookie, che viene memorizzato poco dopo aver cambiato il colore di sfondo. La sintassi d’uso è semplicissima: si tratta di indicare un nome da passare all’oggetto Session e di specificare un valore (come nell’esempio, dove viene utilizzato Session(“colore”) = valore). Dopo aver compilato il form, il valore della variabile colore memorizzata nella sessione viene utilizzato per modificare l’attributo bgcolor del tag body, così da cambiare il colore di sfondo della pagina. Tutte le altre pagine del sito non devono far altro che includere la stessa porzione di codice poiché la sessione viene ereditata da tutte le pagine di navigazione dell’utente. La durata delle sessioni Come sappiamo, non appena è stata inviata all’utente la pagina richiesta, la comunicazione termina. Quando l’utente richiede una seconda pagina, il meccanismo non cambia. Se il server mantiene in sessione i dati dell’utente, deve però aver modo di liberare la memoria riservata quando l’utente ha richiesto l’ultima pagina del sito, per esempio chiudendo il browser o proseguendo la navigazione in un altro sito. In realtà il server non ha modo di sapere l’ultima pagina che l’utente richiederà, ma si comporta in un altro modo. Se non riceve richieste dal browser per un po’ di tempo ipotizza che l’utente abbia abbandonato il sito, e di conseguenza elimina la sessione (timeout). Il tempo durante il quale il server “aspetta” un’ulteriore richiesta è configurabile sia come parametro da script (con l’istruzione session.timeout = minuti), sia come voce nella maschera di Internet Information Services (figura 7). Da questo ne consegue che se l’utente non utilizza il sito per un certo lasso di tempo (diciamo che va a prendersi un caffé, oppure sta compilando un form che gli richiede di ricercare alcuni dati integrativi), al suo ritorno la sessione potrebbe essere scaduta, e tutte le informazioni memorizzate sono di conseguenza perse. Per questo motivo, in base al tipo di sito e soprattutto alla complessità delle pagina, il tempo di timeout delle sessioni deve essere attentamente valutato. Più aumenta la complessità di compilazione delle pagine e più tolleranti è necessario essere nei confronti dei nostri visitatori. 4 L’oggetto application bbiamo appena visto che l’oggetto session è un ottimo aiuto quando vogliamo memorizzare informazioni sulla navigazione e sulle scelte dell’utente. Per ogni visitatore del sito viene salvata una copia delle variabili usate per la sessione, sincronizzate con il browser dell’utente per mezzo della stringa casuale. Ma dove possiamo invece salvare e recuperare alcune informazioni comuni a tutti gli utenti del sito, come ad esempio il copyright, piuttosto che i parametri di connessione a una base di dati, oppure alcune costanti da A 30/97 usare in tutte le pagine? Per questi scopi esiste un altro oggetto, simile in tutto e per tutto all’oggetto session, ma che si occupa di memorizzare informazioni condivise: l’oggetto application. Supponiamo che non vogliate dare a tutti la possibilità di modificare il colore di sfondo delle pagine, ma solo ad alcuni utenti registrati. Modifichiamo allora la pagina di personalizzazione perché richieda un nome utente ed una password. Come per tutti gli altri esempi, trovate i file di questo esercizio nel CD allegato, sotto la cartel- la Application. Aprite con il browser l’indirizzo del file menuasp.asp, la pagina di partenza dell’esercizio. La situazione dovrebbe essere quella di figura 8. Nulla sembra cambiato rispetto agli esempi precedenti, ma se provate a selezionare la voce Personalizza dal menu di sinistra, noterete che a questo punto vi viene chiesto di inserire un nome utente e password per l’autenticazione (figura 9). Se provare ad inserire alcuni valori casuali e procedete, il sistema nega l’accesso alla pagina di configurazione. Adesso tor- 2a lezione 8 nate con il browser alla pagina di menù e riprovate a selezionare la voce Personalizza, ma questa volta inserite i valori corretti per poter procedere: Mario con nome utente e foo come password (senza le doppie virgole). A questo punto avete accesso alla pagina di personalizzazione e potete, analogamente all’esempio precedente, modificare il colore di sfondo che vi accompagnerà per tutta la navigazione di questo piccolo sito. L’analisi del codice Analizziamo il codice che rende possibile tutto questo. Per prima cosa verifichiamo il contenuto di menuasp.asp, la prima pagina che visualizzia- mo nella finestra del browser (listato 7). L’unica piccola, ma fondamentale modifica è data dall’uso in testa alla pagina di due variabili di applicazione: utente e password. Lo scopo di queste due variabili è contenere gli unici valori per i quali sarà garantito l’accesso alla pagina di configurazione. Poiché le variabili di applicazione sono disponibili a tutte le pagine del sito e a tutti gli utenti, una volta che le abbiamo definite in questa pagina, ogni altra pagina del sito è in grado di accedere al loro contenuto. Non è la situazione ottimale, ma vedremo in seguito come migliorarla. Passiamo adesso alle altre pagine. È bene notare che il link alla voce personalizza presente nel menu di sinistra non conduce più, come nell’esempio precedente, alla pagina personalizza.asp, ma a loginpersonalizza.asp. Si tratta della pagina che contiene il form per l’autenticazione (listato 8). È una pagina semplicissima, che non contiene alcuna nuova linea di codice rispetto a quello che già sappiamo realizzare. Diamo solo un’occhiata all’attributo action del form, che conduce alla pagina personalizza.asp. Il percorso è quindi questo: dal menu a sinistra si procede alla pagina loginpersonalizza.asp e una volta inserito il nome utente e la password si passa a personalizza.asp. Da quanto detto è chiaro che sarà personalizza.asp a verificare se l’utente ha le carte in regola per essere autenticato o meno, per cui passiamo ad analizzarne il contenuto (listato 9). L’unica modifica rispetto alla versione precedente della pagina si trova all’inizio: per prima cosa memorizziamo in sessione il nome utente e la password inviati dall’utente dopo la compilazione del form. A questo punto confrontiamo i valori inseriti dall’utente con quelli presenti nelle variabili salvate nell’oggetto Application: se i valori coincidono l’u- 9 tente ha fornito correttamente gli estremi per l’autenticazione. La condizione che verifica questa situazione (che comincia con if Session("utente") = Application("utente")) termina molte righe dopo, in particolare dopo il form per la scelta del colore. Questo vuol dire che solo nel caso di autenticazione andata a buon fine presentiamo all’utente la possibilità di variare il colore di sfondo. Alla fine della pagina vediamo invece cosa succede se questo non si verifica, cioè se l’utente ha fornito dei dati non corretti ai fini dell’autenticazione. In questo caso visualizziamo semplicemente un’indicazione della mancata autorizzazione (Attenzione: accesso non consentito). 5 La durata delle sessioni e delle applicazioni bbiamo visto precedentemente che la durata delle sessioni dipende dal valore di timeout con cui abbiamo configurato IIS oppure specificato esplicitamente nella pagina ASP. Ma quanto durano gli oggetti salvati nell’oggetto Application, che sono comuni a tutti gli utenti? In questo caso la loro vita termina quando viene fermato e poi riavviato il servizio di IIS, cioè quando il sistemista decide esplicitamente di far ripartire il sito Web. La A 31/97 stessa cosa avviene per le sessioni: anche queste sono eliminate in caso di riavvio del servizio IIS. Ce ne rendiamo conto con un semplice esempio. Lanciate l’ultimo esercizio che abbiamo realizzato e cambiate il colore di sfondo delle pagine. A questo punto aprite la console di Internet Information Services (in Windows 2000 Professional la trovate partendo dal Control Panel, selezionando Administrative Tools e successivamente Internet Information Services). 10 Selezionate l’icona del vostro computer nel pannello di sinistra e attivate il menu contestuale con il tasto destro del mouse (la situazione dovrebbe essere simile a quella riportata in figura 10). La voce All Tasks contiene la sottovoce Restart IIS, che potete selezionare, in modo da arrivare alla situazione riportata in figura 11. Confermate la selezione e dopo qualche secondo il server verrà riavviato. Se a questo punto ritornate alla finestra del browser, e navigate utilizzando il menu di sinistra, noterete che il colore di sfondo ritorna quello precedente alla sezione. Questo si verifica perché riavviando il server le variabili memorizzare in sessione e nell’oggetto Application sono state eliminate, con conseguente perdita di tutti i riferimenti al colore di sfondo e all’utente registrato. 11 Aggiornamenti concorrenti È necessario prestare particolare attenzione quando si modificano le variabili memorizzate con l’oggetto application. Mentre la sessione è diversa per ogni utente, gli oggetti salvati a livello di applicazione sono condivisi da chiunque visiti il sito: cosa succede se 2 utenti tentano di cambiare contemporaneamente il valore dell’oggetto application? Buona norma sarebbe indicare ad ASP che solo un utente alla volta può modificare il valore delle variabili di applicazioni. Per farlo si usano due semplici istruzioni: Application.Lock poco prima di modificare il valore e Application.Unlock subito dopo. Usare il file global.asa L’esercizio che abbiamo appena realizzato soffre in realtà di un piccolo, ma fondamentale difetto. Fino a quando un utente non visita la pagina menuasp.asp il nome utente e password di Mario non sono memorizzati nelle corrispettive variabili dall’oggetto Application. Questo vuol dire che se fermate il servizio IIS come abbiamo visto poco fa (per cancellare il contenuto di tutte le variabili) e aprite per prima cosa la pagina loginpersonalizza.asp (o qualsiasi altra ad eccezione di menuasp.asp), nell’oggetto application non sono memorizzati i valori Mario e foo. Per rendervene conto compilate con i dati corretti il form e premendo Invia. Non c’è nulla da fare: anche inserendo i valori per cui vi aspettereste l’autenticazione, la risposta della pagina sarà sempre negativa. Potreste pensare che non si tratta poi di un problema grave: in fondo è la prima pagina del sito quella da cui ogni utente comincia l’esplorazione. In realtà non è vero: anche se le home page sono solitamente le pagine più viste di un sito, l’utente può teoricamente cominciare la navigazione da qualsiasi punto. Motori di ricerca Provate a fare una ricerca su Google per un argomento di interesse: non è detto che il motore di ricerca vi conduca alla home page del sito. Il problema che dobbiamo affrontare è quindi il seguente: le variabili dell’oggetto application (e, a volte, anche quelle dell’oggetto session) dovrebbero essere memorizzate indipendentemente dalle pagine del sito. Potremmo pensare di inserire questi valori in ogni pagina: in questo modo saremmo certi che, indipendentemente dalla prima pagina richiesta dal browser utente, le variabili siano lette correttamente. In realtà la situazione è impraticabile, soprattutto perché i costi in termini di gestione sarebbero elevati nel caso di siti con decine di pagine: cosa fare se a un certo punto avete bi- 32/97 sogno di un’altra variabile? La tecnologia ASP ci viene fortunatamente incontro e offre la possibilità di impiegare in un unico file tutte le variabili che vogliamo includere negli oggetti application e session. Questo file, che si dovrà chiamare global.asa è letto ogni volta che IIS parte, e le variabili sono memorizzate rispettivamente negli oggetti application e session. Modifichiamo quindi l’esempio per includere questo tito di soluzione, prelevando i file dalla cartella globalasa del CD Guida. Perché la prova funzioni correttamente è necessario copiare il file global.asa dalla cartella appena indicata nella directory principale che contiene tutti i nostri esempi ASP. Questa operazione è necessaria perché IIS verifica la presenza del file global.asa solo nella directory principale del nostro sito, e non in eventuali sottocartelle. Riavviate IIS e caricate nel browser la pagina loginpersonalizza.asp, senza passare per la home del sito (a dire il vero potete anche farlo, visto che abbiamo tolto ogni riferimento alle variabili Application). Se provate ad autenticarvi, passerete il controllo senza alcun problema. Non solo: rispetto all’esempio precedente potete caricare qualsiasi pagina e l’effetto sarà il medesimo, non rischiate alcuna altra sorpresa. Il motivo di questo comportamento deriva dal fatto che le variabili di applicazione contenenti il nome utente e la password corretti non sono più memorizzate nelle singole pagine, ma centralizzate nel file global.asa. Diamo un’occhiata al file global.asa per capire come costruirlo: abbiamo riportato il codice nel listato 10. La struttura è del tutto simile ad una parte di codice che possiamo inserire in qualsiasi pagina ASP. Si riconoscono a vista d’occhio le definizioni delle variabili e il valore che gli viene associato. L’unica particolarità è la presenza della procedura Application_OnStart. Il nome non è casuale, ma è un modo per indicare a IIS quando eseguire le istruzioni contenuti in questa porzione del file global.asa. Come potete facilmente immaginare, il codice in questo caso viene richiamato alla partenza dell’applicazione Web, nel nostro caso quando avviamo o riavviamo Internet Information Services. Quando questo evento si verifica viene caricato il file global.asa e se la ricerca per la procedura Application_OnStart ha esito positivo, si eseguono tutte le istruzioni che la compongono. È quindi particolarmente comodo per lo sviluppatore utilizzare il file global.asa come accentratore delle porzioni di codice da eseguire ogni volta che parte l’applicazione. Il file global.asa può essere in realtà utilizzato non solo in questo contesto, ma anche quando l’applicazione viene arrestata, oppure per l’inizio e la fine di una sessione (in questo caso le procedure sono rispettivamente Application_End, Session_ OnStart e Session_OnEnd). Ci si potrebbe chiedere che senso ha eseguire delle istruzioni quando l’applicazione o la sessione cessano di esistere, ma ci sono casi in cui questi eventi hanno senso. Pensate per esempio a un’applicazione di una certa complessità, che per motivi di efficienza mantenga nell’oggetto application, senza mai salvarli, alcuni dati. Non appena l’applicazione, per qualsiasi motivo, viene fermata, è necessario memorizzare sul disco fisso le informazioni volatili: per farlo non c’è altro posto se non la procedura Application_End. Un altro motivo potrebbe essere chiudere esplicitamente eventuali connessioni alle basi di dati oppure liberare la memoria da oggetti indesiderati. Le variabili e la memorizzazione sul sito Gli esempi che abbiamo realizzato fino ad ora salvano nell’oggetto application il nome e la password dell’utente che ha l’autorizzazione per personalizzare lo sfondo della pagina. Una soluzione migliore, e più generale, consisterebbe nel salvare queste informazioni in una base di dati, in modo da poter realizzare più profili di utenza e di centralizzare il sistema che si preoccupa di gestire dati personali e sensibili. Non abbiamo optato per questa soluzione solo perché era importante concentrarci sul ruolo delle sessioni e dell’applicazione nello sviluppo con ASP, ma nella prossima puntata affronteremo invece lo studio delle basi di dati, per cui non dovete attendere ancora molto per capire come funziona questo mondo. 2a lezione 6 La gestione degli errori in ASP n Visual Basic Script, così come in tutti i linguaggi di programmazione, è molto importante garantire che il codice non produca risultati inattesi neppure quando si verificano degli errori di funzionamento. Normalmente, se non ci preoccupiamo di gestire gli errori, la pagina ASP non ha alcuna alternativa se non quella di terminare immediatamente l’esecuzione. Tra i file di esempio trovate errore.asp: come dice il nome, si tratta di una pagina ASP che genera un errore (listato 11). È presente infatti un ciclo for next che divide il contenuto di una variabile (posta a 1000) con quello di un’altra variabile, che viene incrementata in modo che il suo valore passi da -10 a 10. Questo però non si verifica perché non appena si tenta di eseguire una divisione per zero si scatena una condizione di errore e l’esecuzione della pagina si interrompe (figura 12). I Le contromisure Per cautelarsi da questo tipo di “disavventure” è buona abitudine, nelle parti critiche del codice, verificare se siamo entrati in condizione di errore, e reagire conseguentemente. Un primo metodo è l’introduzione dell’istruzione on error resume next, praticamente una frase che potremmo tradurre come “in caso di errore prosegui oltre”. In effetti è proprio questo che si verifica: dal punto in cui è inserita questa istruzione ogni errore viene ignorato e l’esecu- 33/97 zione del codice prosegue dalla riga successiva. Per rendersi conto di cosa succede potete eseguire una versione modificata dell’esempio precedente, erroreresume.asp (listato 12). Questa volta, non appena viene eseguita la riga con la divisione per zero il codice non si arresta, ma continua la sua esecuzione dalla riga successiva (figura 13). Potrebbe a prima vista sembrare che in questo modo tutti i nostri problemi abbiano trovato soluzione. In realtà il fatto che si verifichi una situazione imprevista, e che il codice si arresti, spesso indica che il problema sta a monte che va risolto. Immaginate di chiedere ad un utente di inserire il proprio nome e anno di nascita, e di voler calcolare l’età della persona. La situazione è illustrata in figura 14. Provate a richiamare il file con il browser (si chiama annoeta.asp) e a compilare il form con dati congruenti. La pagina di risposta vi risponde conseguentemente (figura 15). Fino a quando l’utente inserisce un valore numerico nel secondo campo non ci sono problemi nel calcolare l’età, ma poiché non avete controllo sull’input del visitatore, può anche darsi che questo inserisca dei caratteri al posto dell’anno, come vediamo in figura 16. Il risultato di questa situazione inattesa è un errore della pagina (figura 17). Se guardiamo il codice della pagina di risposta (annoetarisposta. asp, listato 13) notiamo che viene eseguita 12 la funzione cint sul valore del campo anno di nascita. Lo scopo della funzione cint è di convertire una variabile di tipo Variant 13 (che, come dicevamo nella prima puntata del corso, è l’unico vero tipo 14 dato con cui lavora Visual Basic Script) in un sottotipo numerico intero. Questa funzione si aspetta in ingresso una stringa che però contenga esclusivamente numeri: se non è così restituisce sistematicamente un errore. Ecco spiegato perché nel secondo caso l’esecuzione della pagina viene interrotta. Per evitare questa conseguenza è necessario capire se si è verificato un errore, e agire di conseguenza. Integriamo quindi il codice di questa pagina in modo da farlo diventare il contenuto del listato 14, che si riferisce al file annoetarisposta2.asp. Per prima cosa è necessario inserire, poco prima della riga con la funzione cint, l’istruzione on error resume next. Si tratta di un’operazione necessaria, pena l’arresto non appena si verifica la condizione di errore. La vera novità si trova nel codice che segue la funzione cint e coinvolge l’oggetto Err. Quest’ultimo è un oggetto interno di VBScript che in caso di errore viene creato con informazioni dettagliate sulla problematica riscontrata. Tra i metodi di questo oggetto due si rivelano particolarmente importanti: Description e Number. Il primo presenta una descrizione del problema che si è verificato, mentre il secondo è un numero univoco per ogni errore. All’interno della nostra pagina verifichiamo quindi, come prima cosa, se l’oggetto Err esiste, il che indica la presenza di un errore nella pagina. A questo punto, senza che l’esecuzione della pagina si interrompa bruscamente, abbiamo tutto il tempo di informare il visitatore del verificarsi di una situazione inattesa, come è possibile vedere in figura 18. Sta a noi decidere quali informazioni presentare all’utente, ma in questo caso abbiamo scelto di visualizzare il dettaglio dell’errore e il suo codice. Non solo: poiché il codice di errore è univoco, e 13 si riferisce a Type Mismatch (ovvero, è stato usato un tipo di dato diverso da numerico nel richiamare la funzio- 15 16 17 18 ne cint), possiamo inserire una condizione per dare qualche indicazione aggiuntiva all’utente. Conclusioni Nel corso di queste due puntate abbiamo cercato di proporvi alcuni significativi esempi di base per la programmazione Visual Basic Script in riferimento alla piattaforma ASP. Siete ora in grado di realizzare qualunque tipo di sito abbiate in mente, anche se all’aumentare della complessità, quando il tipo e numero di dati da gestire aumenta, avrete bisogno di affidarvi ad una base di dati per memorizzare ed estrarre informazioni. Fino ad ora, in effetti, ci siamo concentrati sui fondamenti del linguaggio e su una descrizione degli oggetti coinvolti. Il pregio di una piattaforma come ASP è però la possibilità di colloquiare in modo trasparente e tutto sommato semplice con le basi di dati. E nella prossima puntata affronteremo per l’appunto il mondo delle basi dati relazionali, introducendo qualche concetto fondamentale per capirne il funzionamento e lo scopo, per poi passare all’integrazione con ASP. Cliccate qui per accedere alla versione elettronica dei listati. Si aprirà una pagina Web con i link ai listati delle quattro puntate del corso. Cliccate sul link desiderato e selezionate "Salva" dalla finestra visualizzata da Internet Explorer per indicare dove volete salvarli. Gli esempi sono in formato ASP e perciò non direttamente visualizzabili nel browser a meno di avere installato o attivato il servizio di Internet Information Server sul vostro PC, nella versione per client Windows XP. LISTATO 1 DATICOMPLETI2.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Un form</title> </head> <body> <% Dim strHobby Dim blnMusica blnMusica = false strHobby = request.form("chk_hobby") For Each hobby in request.form("chk_hobby") If hobby = "Musica" Then blnMusica = true End If Next %> <% if blnMusica = true Then %> <p>Caro <%=request.Form("txt_nome")%>, ho visto che ti interessi di musica. Ti dispiace indicarmi il nome del tuo cantante o gruppo preferito?</p> <form action="visdaticompleti2.asp" method="post"> <input type="hidden" name="txt_nome" value="<%=request.Form("txt_nome")%>"> <input type="hidden" name="txt_cognome" value="<%=request.Form("txt_cognome")%>"> <input type="hidden" name="rad_sesso" value="<%=request.Form("rad_sesso")%>"> <input type="hidden" name="sel_eta" value="<%=request.Form("sel_eta")%>"> <input type="hidden" name="chk_hobby" value="<%=request.Form("chk_hobby")%>"> <input type="hidden" name="txa_note" value="<%=request.Form("txa_note")%>"> Cantante o gruppo preferito <input type="text" name="txt_cantante"> <input type="submit" value="Invia"> </form> <% else %> <p>Grazie per aver inviato i tuoi commenti, peccato non ti interessi di musica!</p> <% end if %> 34/97 </body> </html> 35/97 LISTATO 2 SORGENTI DI DATICOMPLETI2.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Un form</title> </head> <body> <p>Caro Mario, ho visto che ti interessi di musica. Ti dispiace indicarmi il nome del tuo cantante o gruppo preferito?</p> <form action="visdaticompleti2.asp" method="post"> <input <input <input <input <input <input type="hidden" type="hidden" type="hidden" type="hidden" type="hidden" type="hidden" name="txt_nome" value="Mario"> name="txt_cognome" value="Rossi"> name="rad_sesso" value="M"> name="sel_eta" value="0-20"> name="chk_hobby" value="Musica"> name="txa_note" value="Ecco qualche nota"> Cantante o gruppo preferito <input type="text" name="txt_cantante"> <input type="submit" value="Invia"> </form> </body> </html> 36/97 LISTATO 3 DATICOMPLETICOOKIE2.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Un form</title> </head> <body> <% Dim strHobby Dim blnMusica blnMusica = false strHobby = request.form("chk_hobby") For Each hobby in request.form("chk_hobby") If hobby = "Musica" Then blnMusica = true End If Next response.cookies("txt_nome") = request.Form("txt_nome") response.cookies("txt_cognome") = request.Form("txt_cognome") response.cookies("rad_sesso") = request.Form("rad_sesso") response.cookies("sel_eta") = request.Form("sel_eta") response.cookies("chk_hobby") = request.Form("chk_hobby") response.cookies("txa_note") = request.Form("txa_note") %> <% if blnMusica = true Then %> <p>Caro <%=request.Form("txt_nome")%>, ho visto che ti interessi di musica. Ti dispiace indicarmi il nome del tuo cantante o gruppo preferito?</p> <form action="visdaticompleticookie2.asp" method="post"> Cantante o gruppo preferito <input type="text" name="txt_cantante"> <input type="submit" value="Invia"> </form> <% else %> <p>Grazie per aver inviato i tuoi commenti, peccato non ti interessi di musica!</p> <% end if %> </body> </html> 37/97 LISTATO 4 VISDATICOMPLETICOOKIE2.ASP <%@ language="vbscript" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>Il risultato del form</title></head> <body> <% Dim nome, cognome, sesso, eta, hobby, note, cantante nome = request.cookies("txt_nome") cognome = request.cookies("txt_cognome") sesso = request.cookies("rad_sesso") eta = request.cookies("sel_eta") note = request.cookies("txa_note") cantante = request.cookies("txt_cantante") response.write response.write response.write response.write response.write ("Nome: " & nome & "<br>") ("Cognome: " & cognome & "<br>") ("Sesso: " & sesso & "<br>") ("Età: " & eta & "<br>") ("Cantante: " & cantante & "<br>") For Each hobby in request.form("chk_hobby") response.write ("Hobby: " & hobby & "<br>") Next response.write ("Note: " & note & "<br>") %> </body> </html> 38/97 LISTATO 5 MENU.ASP <%Option Explicit%><% Dim numVisite Dim strMessaggio numVisite = request.cookies("numerovisite") if numVisite = "" then numVisite = 1 strMessaggio = "Benvenuto nel sito di Mario Rossi. Grazie per la tua visita!" else numVisite = numVisite + 1 strMessaggio = "Bentornato nel sito di Mario Rossi. Questa è la " & numVisite & " volta che visiti questa pagina!" end if response.cookies("numerovisite") = numVisite response.cookies("numerovisite").Expires = #12/31/2004# %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Il sito di Mario Rossi</title> </head> <body> <table width="100%" border="1" cellpadding="0" cellpadding="2"> <tr> <td width="100"> <table width="100"> <tr> <td><h3>Menù</h3></td> </tr> <tr> <td><a href="home.asp">Home</a></td> </tr> <tr> <td><a href="foto.asp?sezione=foto">Foto</a></td> </tr> <tr> <td><a href="scrivimi.asp?sezione=scrivimi">Scrivimi</a></td> </tr> </table> </td> <td> <div align="center"><%=strMessaggio%></div> </td> </tr> </table> </body> </html> 39/97 LISTATO 6 COOKIE/PERSONALIZZA.ASP <% if request.QueryString("colore") <> "" then Session("colore") = request.QueryString("colore") end if %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Il sito di Mario Rossi</title> </head> <% if Session("colore") <> "" then %> <body bgcolor="<%=Session("colore")%>"> <% else %> <body> <% end if %> <table width="100%" border="1" cellpadding="0" cellpadding="2"> <tr> <td width="100"> <!--#include file="includemenu.asp"--> </td> <td align="center"> <% if request.QueryString("colore") = "" then %> Seleziona un colore di sfondo <% else %> Ho cambiato il colore di sfondo di tutte le sezioni secondo la tua scelta <% end if %> <form action="personalizza.asp" method="get"> <select name="colore"> <option value="#FFFF99">giallo</option> <option value="#FFCCCC">rosa</option> <option value="#66CCFF">celeste</option> <option value="#FFFFFF">bianco</option> </select> <input type="hidden" name="sezione" value="personalizza"> <input type="submit" value="Seleziona"> </form> </td> </tr> </table> </body> </html> 40/97 LISTATO 7 APPLICATION/MENUASP.ASP <% Application("utente") = "Mario" Application("password") = "foo" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Il sito di Mario Rossi</title> </head> <% if Session("colore") <> "" then %> <body bgcolor="<%=Session("colore")%>"> <% else %> <body> <% end if %> <table width="100%" border="1" cellpadding="0" cellpadding="2"> <tr> <td width="100"> <!--#include file="includemenu.asp"--> </td> <td><h1><div align="center">Questa è la Home Page del sito</div></h1></td> </tr> </table> </body> </html> 41/97 LISTATO 8 APPLICATION/LOGINPERSONALIZZA.ASP <% if request.QueryString("colore") <> "" then Session("colore") = request.QueryString("colore") end if %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Il sito di Mario Rossi</title> </head> <% if Session("colore") <> "" then %> <body bgcolor="<%=Session("colore")%>"> <% else %> <body> <% end if %> <table width="100%" border="1" cellpadding="0" cellpadding="2"> <tr> <td width="100"> <!--#include file="includemenu.asp"--> </td> <td align="center"> <strong>Login al sito</strong> <form action="personalizza.asp" method="get"> <strong>Nome Utente</strong>: <input type="text" name="utente" size="20"><br /> <strong>Password</strong>: <input type="password" name="password" size="20"><br /> <input type="hidden" value="personalizza"> <input type="submit" value="Invia"> </form> </td> </tr> </table> </body> </html> 42/97 LISTATO 9 APPLICATION/PERSONALIZZA.ASP <% ' Estraggo il nome utente e la password inseriti dall'utente e li salvo in sessione if request.QueryString("utente") <> "" then Session("utente") = request.QueryString("utente") Session("password") = request.QueryString("password") end if ' L'utente si è correttamente registrato se i dati di sessione sono quelli salvati nell'oggetto application if Session("utente") = Application("utente") And _ Session("password") = Application("password") Then %> <% if request.QueryString("colore") <> "" then Session("colore") = request.QueryString("colore") end if %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Il sito di Mario Rossi</title> </head> <% if Session("colore") <> "" then %> <body bgcolor="<%=Session("colore")%>"> <% else %> <body> <% end if %> <table width="100%" border="1" cellpadding="0" cellpadding="2"> <tr> <td width="100"> <!--#include file="includemenu.asp"--> </td> <td align="center"> <% if request.QueryString("colore") = "" then %> Seleziona un colore di sfondo <% else %> Ho cambiato il colore di sfondo di tutte le sezioni secondo la tua scelta <% end if %> <form action="personalizza.asp" method="get"> <select name="colore"> <option value="#FFFF99">giallo</option> <option value="#FFCCCC">rosa</option> <option value="#66CCFF">celeste</option> <option value="#FFFFFF">bianco</option> </select> <input type="hidden" name="sezione" value="personalizza"> <input type="submit" value="Seleziona"> 43/97 </form> </td> </tr> </table> </body> </html> <% else ' L'utente non si è registrato correttamente %> <html> <head><title>Errore di accesso</title></head> <body>Attenzione: accesso non consentito</body> </html> <% end if %> 44/97 LISTATO 10 GLOBAL.ASA <script language="VBScript" runat="server"> Sub Application_OnStart() Application("utente") = "Mario" Application("password") = "foo" End Sub </script> 45/97 LISTATO 11 ERRORE.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Pagina con errore</title> </head> <body> <% Dim i Dim j i = 1000 for j = -10 to 10 response.write i/j next %> </body> </html> 46/97 LISTATO 12 ERRORERESUME.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Pagina con errore</title> </head> <body> <% Dim i Dim j i = 1000 on error resume next for j = -10 to 10 response.write i/j next %> </body> </html> 47/97 LISTATO 13 ANNOETARISPOSTA.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Pagina che richiede nome e anno di nascita</title> </head> <body> <% Dim anno Dim eta anno = cint(request.QueryString("anno")) eta = Year(Now()) - anno %> Ciao <%=request.QueryString("nome")%>, hai <%=eta%> anni. </body> </html> 48/97 LISTATO 14 ANNOETARISPOSTA2.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Pagina che richiede nome e anno di nascita</title> </head> <body> <% Dim anno Dim eta on error resume next anno = cint(request.QueryString("anno")) if Err then response.write "Gentile utente, si è verificato un errore nella compilazione dei tuoi dati <br>" response.write "Descrizione dell'errore: " & Err.Description & "<br>" response.write "Codice dell'errore: " & Err.Number & "<br>" If Err.Number = 13 Then response.write "Devi inserire un numero come anno di nascita<br>" End If response.write "Torna alla <a href=""annoeta2.asp"">pagina precedente</a>" response.end end if eta = Year(Now()) - anno %> Ciao <%=request.QueryString("nome")%>, hai <%=eta%> anni. </body> </html> 49/97 3a lezione A scuola con PC Open Web Developer ASP di Antonio Volpon 1 I database relazionali ontinuiamo la nostra esplorazione della tecnologia ASP e affrontiamo in queste due ultime puntate un argomento fondamentale per sfruttarne appieno le potenzialità: l’uso dei database. Vedremo innanzitutto cosa è un database, quando adottarlo e le parti di cui si compone. Passeremo poi a introdurre il ruolo del linguaggio SQL (Structured Query Language) utilizzato per interrogare le basi di dati e infine vedremo come utilizzare un database all’interno delle applicazioni ASP. C Le differenze con un foglio elettronico Molti dei nostri lettori conoscono con tutta probabilità i programmi compresi con i pacchetti della famiglia Office: Word, Excel, PowerPoint. Excel, in particolare, è uno strumento versatile che consente di lavorare su righe di dati in modo preciso ed efficiente. A prima vista Excel sembrerebbe un database: vi si possono memorizzare delle informazioni sulle righe, realizzare ricerche e anche modifiche. In realtà un database si distingue da prodotti quali Excel perché permette di salvare dati e infor- mazioni molto più complessi, e di porli in relazione con altre realtà. Anche gli strumenti utilizzati per realizzare interrogazioni su questi dati sono più potenti, tanto che per questi scopi è stato creato un vero e proprio linguaggio (chiamato SQL). Rispetto ad Excel, che ragiona essenzialmente in termini di riga, un database relazionale introduce il concetto di tabella, che indica una parte della realtà in esame. La teoria dei database relazionali è stata introdotta nel 1969 da Edgard Codd, un ricercatore di IBM che ha applicato diversi concetti presi dal mondo della matematica. Non sono necessarie in realtà particolari conoscenze per capire il funzionamento di una base di dati, che ruota in realtà intorno ai concetti di tabella, campo e record. Vediamo di capire di cosa si tratta. Un esempio pratico: condividere le fotografie In queste due puntate ci concentreremo, come sempre, su un problema specifico. Come ormai sapete, il nostro compito è di aiutare Mario Rossi nella costruzione del proprio sito personale. In par- IL CALENDARIO DELLE LEZIONI Lezione 1: Da sito statico a dinamico Lezione 2: • Creare un database con Access • Le tabelle e le relazioni • Lo standard SQL per interrogare il database Portare il sito sul server Lezione 3: ASP e i database Le prossime puntate • I database relazionali Uso avanzato dei database 50/97 Lezione 4: La scelta di Access Per gli esempi che accompagnano queste 2 puntate utilizzeremo dei database in formato Access. La scelta deriva da diverse considerazioni. Prima di tutto Access è un prodotto che fa parte della famiglia Office (nella versione Professional) ed è quindi particolarmente diffuso. Utilizzare Access è inoltre alquanto semplice rispetto ad altri gestori di database professionali, e le prestazioni sono di tutto rispetto se, come nel nostro caso, stiamo realizzando un sito amatoriale, senza picchi di traffico. Il nostro è un corso di ASP e non di Access, quindi non ci fermeremo ad analizzare in ticolare Mario ha recentemente acquistato una macchina fotografica digitale, e vorrebbe condividere con gli amici via Web gli scatti più interessanti. Potrebbe farlo realizzando alcune pagine statiche (vedi la differenza tra sito statico e dinamico che abbiamo affrontato nella prima puntata del corso Web Master ASP, pubblicata nel numero di Novembre di PC Open), ma ha un’idea diversa. Quella che vorrebbe realizzare è una pagina che non si limiti a visualizzare l’elenco delle ultime foto inserite, ma che dia al visitatore del sito la possibilità di svolgere qualche ricerca, in modo da visualizzare le foto che ritraggono un particolare tema o che siano state scattate in un determinato luogo. Vorrebbe anche avere la possibilità di aggiungere velocemente dettaglio le caratteristiche di questo prodotto, ma è utile saper creare le tabelle ed eseguire qualche semplice interrogazione. Vediamo quindi come realizzare la tabella delle Foto (o meglio, la prima versione di questa tabella), con Access. Abbiamo scelto di utilizzare Access 2000, ma non preoccupatevi se possedete una versione diversa: per i nostri scopi le differenze tra le versioni sono del tutto trascurabili. Nessun problema neppure se non avete Access installato: sarete comunque un grado di provare gli esempi ASP che realizzeremo, poiché i file di esempio sono sempre prelevabili dal nostro sito. nuove foto che scatterà durante le prossime vacanze. Per aiutarlo in questa richiesta realizzeremo in effetti una base di dati. Abbiamo detto poco fa che un database è un insieme di dati. Aggiungiamo adesso che questo insieme di dati è dotato di un certo tipo di struttura, è cioè organizzato secondo una logica definita da chi si è occupato di costruirlo. Pensiamo al caso di Mario Rossi, cioè la costruzione di un database da pubblicare sul Web e che contenga una descrizione delle foto interessanti (useremo di seguito i termini database o base di dati per indicare lo stesso concetto). La fase logica La prima fase che porta alla costruzione di una base di da- 3a lezione ti è essenzialmente logica. Si tratta di rispondere alla domanda: quali sono le informazioni di cui ho bisogno per realizzare la pagina richiesta? Quali, tra tutti i dati che posso memorizzare a proposito di una foto, hanno senso nel contesto in esame? Quello che vogliamo memorizzare è per prima cosa il nome del file contenente la foto, così da visualizzarla su browser. Sicuramente abbiamo poi bisogno di sapere qual è l’argomento della foto, visto che Mario Rossi vuol dare ai suoi utenti la possibilità di compiere ricerche in base al tema, e la stessa cosa vale per il luogo. Un’ulteriore informazione che è bene salvare sul database è una data, così da poter svolgere in futuro qualche interrogazione per capire quante foto sono state scattate nel corso dei mesi. Una volta decisi quali dati memorizzare, il resto del lavoro è semplice. Il concetto di tabella Come prima cosa costruiamo allora una tabella. Una ta- bella, nella teoria relazionale dei dati, rappresenta la descrizione di una realtà in esame. Nel nostro caso quello che possiamo fare è costruire una tabella che descriva le foto delle vacanze. Ogni tabella è poi composta da un certo numero di attributi (nel nostro caso il nome del file, la data, il luogo) che vengono chiamati campi. I campi sono i veri contenitori dei dati, mentre la tabella è essenzialmente un contenitore di campi (in figura 1 potete vedere un’ipotetica tabella per le nostre foto, realizzata con Access). Quando popoliamo il database, ossia quando inseriamo i dati veri e propri, e in particolare nel popolare la tabella, specifichiamo diversi valori per i campi, ad esempio indicando che il nome del file è “dsc0021”, che il luogo è “Venezia” piuttosto che “Roma”. Ciascuna foto che inseriamo nella tabella prende il nome di record (in figura 2 sono riportati alcuni record per la tabella Foto). 1 2 2 Creare un database con Microsoft Access opo averlo installato, eseguite Access dal vostro computer (lo trovate sicuramente tra i programmi del menu Start): vi verrà chiesto di aprire un database esistente oppure di crearne uno nuovo, proprio quello che vogliamo. Scegliete dove salvare il file, dandogli un nome significativo (ad esempio foto). Prendete nota della cartella in cui avete salvato il database, perché dovrete successivamente spostarlo nella directory principale del vostro sito (vedremo più D avanti come fare). Vi troverete a questo punto nella schermata di figura 3. Avete davanti a voi il pannello di Access, lo strumento usato per creare gli oggetti del database (come le tabelle), per eseguire interrogazioni, ma anche per svolgere alcune attività che non rientrano nel nostro corso ASP, come la generazione di report o la scrittura di codice. Vogliamo invece realizzare una tabella, e per farlo basta assicurarsi che nel pannello sia selezionata la voce Tabella. A questo punto, tra le voci presenti 3 sulla destra scegliete Crea una tabella in visualizzazione struttura e siete pronti per descrivere tutti i campi di cui è composta la tabella (figura 4). Gli attributi dei campi Come abbiamo detto nel para- 51/97 4 5 3a lezione grafo precedente, i campi sono gli attributi che definiscono la realtà in esame, nel nostro caso la foto. Come prima cosa inseriamo quindi “Nome”, a indicare il nome del file contenente l’immagine (figura 5). Se vi spostate con il tabulatore, noterete che Access vi richiede di inserire un “tipo dati” per il campo appena definito. Quello che vi viene chiesto è in pratica di decidere il formato per l’informazione da salvare: si tratta di un testo, di un numero, di una data (e con quali dimensioni)? Per una descrizione approfondita dei tipi di dati disponibili in Access vi rimandiamo alla guida in linea, ma per il nome della foto ci sembra corretto definire il campo come un testo di lunghezza massima di 50 caratteri (figura 6). Alla foto vorremo sicuramente associare un Titolo, e scegliamo di usare un campo, sempre di tipo testo ma questa volta di lunghezza 200. Si tratta poi di inserire un campo Luogo dello stesso tipo, come Provincia e infine un campo Data, questa volta di tipo data a indicare la data di scatto della fotografia. La versione finale della tabella compare in figura 7. La chiave primaria di una tabella Possiamo a questo punto salvare la tabella: Access vi chiede di inserire un nome opportuno con il quale riferirla successivamente, e non c’è dubbio che la cosa migliore sia di chiamarla Foto. Non appena fornite di un nome della tabella, però, Access vi risponde con una finestra che richiede la vostra immediata attenzione (visto che contiene un punto esclamativo) (figura 8), consigliandovi di indicare una chiave primaria per la tabella. Di cosa si tratta esattamente? Anche se non è obbligatorio, è buona norma che ogni tabella contenga un campo i cui valori siano univoci per ogni record che inserite. Il vostro codice fiscale, tanto per fare un esempio, è univoco. Per questioni di efficienza e per facilitare le operazioni tra tabelle (che vedremo in seguito) è buona abitudine definire o creare un campo di questo tipo in ogni tabella che andremo 52/97 a realizzare. Poiché Mario Rossi possiede una macchina fotografica digitale che dà ad ogni foto un nome composto da un prefisso e un progressivo (ad esempio “dsc1234”), potremmo scegliere il campo Nome della tabella come chiave primaria. Un’alternativa è quella di inserire un campo fittizio (ad esempio “ID” per identificativo) e scegliere come tipo di dato Contatore. Ogni volta che inseriremo un record nella tabella il valore del contatore si incrementerà automaticamente di 1, realizzando quindi un campo contenente valori ogni volta diversi. Creiamo allora una chiave primaria, ma per prima cosa premiamo il pulsante Annulla come risposta alla domanda di Access. A questo punto selezioniamo la riga contenente il campo Nome della tabella e dal menu di Access selezioniamo l’icona che rappresenta il disegno di una chiave. Noterete che a sinistra del campo Nome comparirà una piccola chiave, ad indicare che quel campo conterrà sempre valori univoci per ogni record inserito (figura 9). Non si tratta solo di un’indicazione: Access non vi consentirà neppure se lo volete di inserire due volte lo stesso nome per l’immagine. Salvate di nuovo la tabella chiamandola Foto e ritornerete nel pannello di Access, dove la vedrete comparire (figura 10). Finora abbiamo definito una tabella e i suoi campi: si tratta a questo punto di popolare la tabella con alcuni dati, e quindi con alcuni record. Vedremo in particolare come creare solo alcuni record, visto che nel CD Guida abbiamo inserito tutti i file di esempio, compresi i database che useremo per gli esercizi. Per popolare la tabella è sufficiente aprirla con un doppio clic dal pannello di Access, così da entrare in modalità inserimento. Inseriamo quindi alcuni dati, come possiamo vedere in figura 11. Per verificare cosa vuol dire aver definito una chiave primaria provate a inserire un record utilizzando un nome già presente: come vedete dalla figura 12 questa operazione non è permessa. 6 7 8 9 10 11 12 3a lezione 3 Consigli per impostare una tabella abelle, campi, record: questi gli elementi fondamentali di una base di dati. In realtà, esistono una serie di regole da tenere in considerazione quando definiamo una o più tabelle e che adesso introdurremo brevemente. È importante costruire una base di dati che risulti efficiente, perché nessun programma, per quanto bene sia scritto, riesce a sopperire i limiti di una base di dati deficitaria. Le tabelle, in particolare, dovrebbero limitarsi a descrivere uno e un solo oggetto della realtà in esame. Il motivo di questi accorgimenti è evidente se diamo un’occhiata alla tabella di figura 13. Come vedete abbiamo popolato i record con alcuni dati significativi, proprio quelli che andremo a visualizzare nelle nostre pagine ASP. Un problema di questa tabella è che contiene diverse ripetizioni di valori nei campi Provincia e Stato. T I dati devono essere coerenti Caratteristica saliente di ogni base di dati è la necessità di ospitare dati che siano il più possibile coerenti tra loro. Se però nel campo Nazione scrivo Italia in un caso, Italy in un altro e magari IT in un terzo non ho sicuramente partecipato a mantenere i dati coerenti. Questa è proprio la situazione della tabella in figura. Se un utente inserisce un nuovo record non ho nessuna possibilità di guidarlo affinché inserisca un nome di nazione che rispetti lo standard definito, ma questo potrà inserire ogni volta dei valori leggermente o completamente diversi. Se domani volete contare quante immagini scattate in Italia sono presenti nella tabella (operazione semplicissima, come vedremo quando cominceremo a parlare di SQL), in questo caso non ci riuscirete. Un altro limite di questa struttura deriva dal fatto che rende difficile le modifiche sui dati. Immaginate di dover sostituire la voce Italy con Italia, in quanto il sito di Mario Rossi è per il momento (anche se Mario già aspira a tradurlo) in lingua italiana. Con questa struttura non potete far altro che sostituire ogni voce, operazione non impossibile (date le interessanti funzioni di Access), ma sicuramente scomoda in caso di interventi ripetuti. Abbiamo detto precedentemente che ogni tabella dovrebbe rispecchiare una realtà atomica. In effetti, se prestiamo attenzione al significato di Provincia e Stato, ci accorgiamo che queste non sono caratteristiche peculiari di una foto, ma piuttosto di altre tabelle, che potremmo chiamare Provincia e Stato. Costruiamo allora altre due tabelle, in modo del tutto analogo a quello usato per creare la tabella foto (riportiamo la struttura rispettivamente nelle figure 14 e 15). Ogni tabella è composta da due campi, di cui il primo è la chiave primaria. Abbiamo scelto in questo caso di usare la sigla della provincia e il codice dello stato come chiave primaria, così da garantire l’univocità di questi valori. Nelle figure 16 e 17 potete notare alcuni record di esempio per le tabelle, che rispecchiano i record inseriti nella tabella Foto. A questo punto interveniamo sulla tabella Foto in modo che i campi Provincia e Stato non si riferiscano più, come succede adesso, alle descrizioni delle province e degli stati, ma alle chiavi primarie. Per farlo sostituiamo il campo Provincia con IdProvincia e Stato con IdStato (tipo di dato testo di lunghezza 3 e 2) e li riempiamo rispettivamente con la sigla della provincia e il codice dello stato, così da ottenere qualcosa di simile alla tabella di figura 18. Il concetto di “normalizzazione” Esiste una soluzione che permette di rendere più facili le modifiche alle tabelle e di trattare dati “coerenti”: si tratta della normalizzazione, ovvero di una serie di tecniche complementari (ciascuna chiamata Prima Forma Normale, Seconda Forma Normale e altre) che aiutano lo sviluppatore nella costruzione di una base di dati efficiente. Non entreremo nel dettaglio di queste tecniche, ci limiteremo a capire come intervenire sulla nostra tabella perché sia efficiente e facilmente mantenibile. 53/97 13 14 15 16 17 18 3a lezione 4 Le relazioni tra le tabelle no dei punti cardine, nonché uno dei punti forza dei database relazionali è dato dalla possibilità di definire legami tra le tabelle (chiamati relazioni). Si tratta adesso di capire cosa vogliamo realizzare attraverso le relazioni nel nostro particolare contesto. Il nostro obiettivo è di legare il campo IdProvincia e IdStato delle tabelle Provincia e Stato con i rispettivi campi della tabella Foto, in modo che in quest’ultima tabella non sia possibile inserire valori non presenti nelle prime 2. Vediamolo con un esempio. Aprite la tabella Foto con un doppio clic e provate ad inserire alcuni dati di prova per una fotografia. In particolare, inserite dei valori assolutamente inventati per i campi IdProvincia e IdStato, ad esempio “AA” e “BB”. Access non fa una piega: vi permette di inserire i valori scelti anche se non esistono nessuna Provincia e nessuno Stato definiti nelle rispettive tabelle. Questo rappresenta un problema perché, come abbiamo detto precedentemente, uno dei vantaggi e degli scopi di un database è di mantenere l’integrità referenziale dei dati che ospita. Per superare questa limitazione ci vengono in aiuto le relazione tra tabelle che Access, da buon database relazionale, permette di definire in modalità grafica semplificando al massimo questa operazione, tanto da renderla quasi divertente. U La procedura nel dettaglio Prima di tutto eliminate il record che avete appena inserito nella tabella Foto e assicuratevi che non siano presenti record con IdProvincia e IdStato non presenti anche nelle tabelle Stato e Provincia. Adesso portatevi nella maschera di gestione delle tabelle e selezionate l’icona relazioni dalla barra dei menu. A questo punto si tratta di aggiungere le tabelle tra cui realizzare le relazioni, nel nostro caso tutte, visto che si tratta di selezionare Foto, Provincia e Stato (per selezionare più tabelle tenete premuto il tasto CTRL della tastiera mentre effettuate la selezione 54/97 con il tasto sinistro del mouse). Confermate l’operazione e vedrete comparire le tabelle nella finestra Relazioni di Access. A questo punto dobbiamo informare Access della nostra intenzione, ovvero di legare il campo IdProvincia della tabella Provincia a quello della tabella Foto, così da porli in stretta relazione. Premete il tasto sinistro del mouse sopra il campo IdProvincia della tabella Provincia e trascinatelo verso il campo IdProvincia della tabella Foto. A questo punto rilasciate il pulsante del mouse: la situazione che vi si presenta è quella di figura 19. Cerchiamo di capire il significato della schermata. Access ci propone di realizzare una relazione tra le due tabelle ponendole in relazione. Non solo: se prestate attenzione alla parte bassa della figura, vedrete un checkbox con la scritta Applica integrità referenziale: è proprio quello di cui abbiamo bisogno, per cui lo selezioniamo. A questo punto agite sul pulsante Crea e noterete che il diagramma delle relazioni cambia, in particolare è stato aggiunto un segmento di unione tra le tabelle Provincia e Foto, come in figura 20. Ripetete adesso la stessa operazione per il campo IdStato, trascinando il campo dalla tabella Stato alla tabella Foto e applicando l’integrità referenziale, così portarvi nella situazione descritta dalla figura 21. Abbiamo finito: potete chiudere la finestra relazioni e provare a ripetere l’inserimento precedente. Dalla maschera di gestione delle tabelle aprite con un doppio clic la tabella Foto e provate nuovamente ad inserire dei valori arbitrari per i campi IdProvincia e IdStato (ad esempio ancora una volta “AA” e “BB”). Questa volta Access non vi consente l’operazione (figura 22): è infatti necessario utilizzare una provincia o uno stato in una delle relative tabelle. È quindi buona norma, prima di popolare i record di questo database, riempire per prima cosa le tabelle Stato e Provincia con i valori che poi utilizzeremo nella tabella Foto. Non è una regola ferrea (altrimenti saremo di fronte ad un li- 19 20 21 22 mite): potete sempre, quando nasce l’esigenza, uscire dalla tabella Foto e inserire i record richiesti in Stato e Provincia. Terminiamo qui la nostra visita di Access: abbiamo imparato tutto quello che ci serve per costruire una base di dati. È adesso arrivato il momento di capire come possiamo usare questo database per costruire applicazioni ASP. Vediamo per prima cosa dove posizionare la base di dati e come creare un collegamento da una pagina. 3a lezione 5 Usare un database Access da ASP ealizzare da una pagina ASP la connessione ad un database Access è un’operazione semplice, che richiede però una certa accortezza per evitare errori difficilmente rintracciabili. Come sempre, trovate gli esercizi che accompagnano questa puntata nel nostro CD, ma vediamo comunque passo per passo come utilizzare il database. Portiamoci nella cartella principale del nostro sito, quella per intenderci che abbiamo configurato in Internet Information Services. Per chiarezza (ma non esiste nessun obbligo) creiamo una cartella chiamata “database” e copiamo al suo interno la base di dati che abbiamo realizzato poco fa. A questo punto entriamo nel vivo e passiamo ad analizzare il codice che la compone. La pagina è elencofoto.asp, presente in figura 23, e visualizza l’elenco dei record presenti nella tabella Foto. Il risultato è semplice ma interessante: per la prima volta da quando lavoriamo con le pagine ASP sono visualizzati dati che provengono da una fonte esterna, un database. Anche se l’esempio è quasi banale, è facile capire come l’utilizzo delle basi di dati nel contesto della programmazione Web apre delle possibilità che fino ad ora, utilizzando il solo linguaggio, non siamo riusciti a raggiungere. Passiamo ora a un attento studio delle righe di codice che permettono di raggiungere questo importante traguardo (listato 1). La pagina utilizza quasi tutte le strutture di ASP che già conosciamo, integrando la comunicazione con il database. Spenderemo un po’ di tempo ad analizzare le righe che compongono questo esempio, perché un esercizio così semplice contiene gran parte delle nozioni di cui abbiamo bisogno per utilizzare i database con ASP. Procediamo allora per gradi: la tecnologia ADO per collegarsi ai database. R I listati citati nell’articolo sono nel CD Guida nella sezione “Corsi Open Master” 55/97 ASP non dispone nativamente di un supporto per i database, ma utilizza invece la tecnologia ADO (ActiveX Data Objects), che fornisce uno strato di interfaccia tra la pagina ASP e la base di dati. Questo vuol dire che per realizzare i programmi di queste puntate non solo dovete avere installato Internet Information Services, ma anche ADO. Non preoccupatevi: con tutta probabilità il supporto ADO è già installato sul vostro computer, visto che è utilizzato da un vasto numero di applicazioni anche non Web, ma se così non fosse potete scaricare la versione più recente collegandovi al sito www.mi crosoft.com/data/. Le connessioni La prima cosa da fare per utilizzare un database è quella di stabilire una comunicazione tra la pagina ASP e i dati che vogliamo interrogare. In ADO la comunicazione avviene creando un oggetto di tipo connessione: è lo scopo della riga di codice che inizia con “Set conn”. Finora non abbiamo ancora introdotto il ruolo del metodo CreateObject dell’oggetto Server di ASP. Lo scopo del metodo è quello di creare e istanziare un oggetto che non fa parte del modello ad oggetti di ASP (come Request, Response, e così via), ma che è possibile richiamare da una pagina ASP. Un programmatore di linguaggio C++, ad esempio, potrebbe creare una libreria di funzioni e richiamarla all’interno di una pagina ASP, con il benificio di aumentare le prestazioni dell’applicazione, visto che C++ è un linguaggio compilato. Il concetto non è di facile comprensione, ma non preoccupatevi, visto che nel corso questo è l’unico ambito in cui lo useremo. L’unica cosa che è bene ricordare è che ADO non fa parte di ASP, e quindi per richiamare gli oggetti ADO da una pagina è necessario usare il metodo CreateObject. Anche la sintassi sarà sempre quella che presentiamo nell’esempio, che farete bene a copiare e incollare quando realizzerete le vostre applicazioni in modo del tutto indipendente. A questo punto “conn” diventa l’oggetto connessione che useremo nell’esempio. Una volta creata la connessione, dobbiamo aprirla, così da stabilire il canale di comunicazione tra la pagina e il database. È appunto lo scopo della riga successiva, che utilizza l’evento Open dell’oggetto connessione appena creato. Nell’aprire la connessione dobbiamo specificare il tipo di database che andremo ad utilizzare e soprattutto la posizione della cartella in cui si trova, nonché il nome che consente di identificarlo. Anche per quanto riguarda la sintassi da usare non ci soffermiamo più del dovuto: è quella presentata nel listato. L’unica parte degna di nota è il metodo MapPath dell’oggetto Server. Il metodo MapPath dell’oggetto server Lo scopo di questa istruzione è calcolare il percorso fisico di un file partendo dal percorso Web. Spieghiamo il concetto con un esempio. Quando digitate un URL (Uniform Resource Locator) nella barra degli indirizzi del browser, specificate il percorso partendo dalla directory principale del server Web. Se ad esempio scrivete http://lo calhost/miapagina.asp e la di- rectory principale del server è c:\inetpub, il percorso fisico del file nel vostro PC è c:\inetpub\miapagina.asp. Lo scopo del metodo MapPath è proprio quello di restituire il percorso completo del file ricevendo come input unicamente l’URL della pagina. Ma perché usare questo metodo quando avremmo potuto semplicemente scrivere il percorso “a mano”? In generale, quando costruiamo un’applicazione Web dovremmo cercare di essere il più generalisti possibili, ed evitare di “cablare” all’interno della pagina informazioni che domani potrebbero variare. Se state realizzando questo esercizio e lo volete successivamente far ospitare da un provider, molto probabilmente il percorso della directory principale del server cambierà. Memorizzando il percorso del database nella pagina, prima di portare in questo nuovo ambiente le pagine, sarete costretti a modificarlo, e questo per ogni pagina personalizzata. Utilizzando il metodo MapPath lasciate al server il compito di calcolare qual è il percorso del file, così potete portare la pagina in qualsiasi altro ambiente. Non a caso, se prendete i file di questa puntata dal nostro CD e li copiate nel vostro PC, non avete bisogno di apportare alcun adattamento per eseguirli correttamente. 23 3a lezione 6 Lo standard SQL per interrogare il database assiamo ora alla riga che valorizza la stringa SQL. È una riga fondamentale per il nostro scopo: definisce quali e quanti dati andare a recuperare dal database, e da quale tabella. SQL (Structured Query Language) è a tutti gli effetti un linguaggio usato per interrogare e modificare le basi di dati. È uno standard (seppur con diverse e a volte inopportune varianti): la sintassi che imparemo per Access è in realtà utilizzabile anche in altre realtà. I fondamenti di SQL sono alquanto semplici da imparare. Una query di selezione (dove per query intendiamo un’interrogazione al database) ha una struttura minima del tipo: SELECT elenco_dei_campi FROM nome_tabella che potrebbe essere tradotta come “seleziona i campi elenco_dei_campi dalla tabella nome_tabella”. L’elenco dei campi da selezionare va sempre separato da una virgola. Torniamo ora alla select del nostro esempio e confrontiamola con la sintassi appena citata: SELECT Titolo, Luogo FROM Foto Non dovremmo avere dubbi sullo scopo di questa query: estrarre dalla tabella Foto il titolo e il luogo di tutte le foto memorizzate. Per il momento ci fermiamo qui e proseguiamo ad analizzare l’esempio, ma torneremo tra breve ad arricchire la nostra conoscenza di SQL. P I recordset ADO Una volta stabilita la connessione con il database e costruita la stringa in linguaggio SQL abbiamo bisogno di un’altra struttura, un oggetto che contenga i record che andremo ad estrarre dalla base di dati: si tratta dell’oggetto Recordset (cioè insieme di record). Lo andiamo a istanziare allo stesso modo della connessione, poiché anche Recordset è un oggetto proprio di ADO e non di ASP. Anche l’oggetto Recordset dispone di un metodo Open, al quale passiamo alcuni parametri. Come prima cosa è necessario indicare al Recordset quale è la stringa SQL che deve utilizzare per restituire i dati, e 56/97 che abbiamo memorizzato nella variabile “sql” (non fatevi ingannare dal nome che abbiamo dato alla variabile: avremmo potuto usare quasiasi stringa). È inoltre fondamentale legare il Recordset alla connessione che abbiamo aperto con il database Access. Ma perché bisogna seguire questa procedura, visto che ADO avrebbe potuto automaticamente legare il Recordset con la connessione aperta? In realtà molte applicazioni Web dispongono di connessioni a database diversi, di conseguenza il sistema non è in grado a priori di decidere quale Recordset associare ad ogni connessione; è un’operazione di nostra competenza. È possibile specificare altri due parametri all’apertura del Recordset, e allo scopo abbiamo utilizzato due costanti definite ad inizio pagina. Senza spingerci nel dettaglio, questi parametri indicano all’oggetto le nostre intenzioni riguardo i dati che andremo ad estrarre. Il primo adOpenForwardOnly indica che vogliamo accedere ai dati solo una volta, spostandoci dal primo all’ultimo record presenti. Indicando al Recordset che per noi questa scelta non rappresenta un limite evitiamo di sprecare inutili risorse e rendiamo la navigazione tra i risultati più efficiente. Il secondo parametro, adLockReadOnly è utilizzata quando i dati sono utilizzati solo per lettura, anche questo è il nostro caso. Scorrere i record di un Recordset Spostiamoci ora nella parte finale del codice. Troviamo per prima cosa un ciclo “do until”. Questa titpologia di ciclo (che non abbiamo visto nella prima puntata) è eseguito fino a quando non diventa vera l’espressione che lo segue. E l’espressione che lo segue utilizza un metodo del Recordset chiamato Eof. Il risultato del metodo Eof (dove Eof sta per End Of File, fine del file) è sempre falsa, a meno che non ci troviamo dopo l’ultimo record restituito. Il significato del ciclo è quindi questo: “fino a quando non hai visualizzato tutti i record, ripeti questo ciclo”. Ci rimane allora da vedere come visualizzare i record. All’interno del ciclo viene costruita una lista HTML ricorrendo al tag <li> ed è usato un ulteriore metodo dell’oggetto Recordset, Fields. La sintassi è molto semplice ed intuitiva: recordset.fields (nome_campo). In effetti il metodo Fields restituisce il contenuto del campo richiesto per il record corrente, proprio quello di cui abbiamo bisogno. Per ogni foto estraiamo quindi il Titolo della foto e il luogo dove è stata scattata, e li presentiamo in una lista HTML. Segue questa riga rs.movenext, ancora una volta un metodo del Recordset. Come è facile intuire, utilizziamo questo metodo per spostarci sul successivo record del Recordset e ricominciare il ciclo, a meno che non ci troviamo sull’ultimo record della tabella. In questo caso infatti la condizione rs.Eof diventa vera, e l’esecuzione della pagina 24 esce dal ciclo. Nello scrivere la pagina ASP e soprattutto il ciclo è facile dimenticarsi di includere il metodo MoveNext. Prestate attenzione a non commettere mai questa leggerezza perché in questo caso la condizione del ciclo non 25 diventerà mai vera, e l’esecuzione della pagina terminerà solo quando viene raggiunto il timeout di esecuzione. Chiudere quanto si è aperto In genere gli oggetti creati da ASP vengono liberati non appena cessano di essere utilizzati o quando escono dalla “visibilità” della pagina. È comunque sempre buona norma rilasciare il prima possibile gli oggetti che non servono più alla nostra pagina. Da un lato liberate la memoria, dall’altro siete sicuri che non rimangano accidentalmente delle connessioni al database. Questo è quello di cui si occupa l’ultima parte del codice. Viene per prima cosa chiuso il Recordset, e per sicurezza viene annullato come oggetto; stessa sorte tocca poi alla connessione. Notate che l’ordine in cui svolgiamo queste operazioni non è casuale. Per prima cosa chiudiamo il Recordset, che per funzionare utilizza una connessione, e poi chiudiamo quest’ultima. Non importa quanto semplice sia il codice che andate a visualizzare: è comunque sempre buona norma rilasciare esplicitamente gli oggetti che usate nel costruire le vostre applicazioni. 3a lezione Visualizzare la foto selezionata L’esempio precedente ci è servito per introdurre ADO e gli oggetti Connection e Recordset, ma ai fini pratici del sito lascia un po’ a desiderare. L’auspicio di Mario Rossi è di presentare una pagina come quella realizzata, ma avere anche la possibilità di selezionare una voce dall’elenco e vedere la relativa foto. Modifichiamo allora l’esempio per rendere operativa questa modifica. Nel contempo modifichiamo anche la stringa SQL utilizzata per estrarre i record, così da presentare altre caratteristiche del linguaggio SQL. La nuova pagina è riportata in figura 24. Come vedete l’elenco è del tutto simile all’esempio precedente, solo che ogni voce è ora diventata un link. Abbiamo anche aggiunto un indicatore con il totale delle foto presenti nel database, così gli utenti affezionati sono in grado di rendersi conto del numero di foto che Mario carica nel corso delle settimane. Se selezionate uno dei link si apre una seconda pagina, che visualizza il dettaglio della foto selezionata (figura 25). Proprio quello di cui aveva bisogno Mario Rossi! Vediamo ora come abbiamo realizzato il codice che rende possibile tutto questo (Listato 2). Il trucco consiste nel definire due stringhe SQL: la prima utilizzata per contenere il numero totale delle foto, la seconda per selezionare tutti i record di interesse. Ci occuperemo tra un attimo di come ottenere queste informazioni nel linguaggio SQL, ma per il momento vediamo come utilizziamo l’oggetto Recordset. Non abbiamo in effetti bisogno di creare due distinti Recordset, uno per il totale e uno per l’elenco, ma possiamo riutilizzare lo stesso oggetto in contesti diversi. Come è possibile notare guardando il codice sorgente, la prima volta è aperto il Recordset utilizzando la stringa sql1, dopodiché ne viene estratto il numero di record ed è chiuso. Infine viene riaperto utilizzando la seconda stringa SQL (sql2), che restituisce l’elenco di tutti i record presenti nelle base di dati. Esaminiamo la sintassi di queste interroga- 57/97 Costruire dinamicamente le interrogazioni Estendiamo a questo punto i concetti esposti 26 finora, e partiamo da un’esigenza di Mario Rossi. Mario vorrebbe infatti dare la possibilità ai propri utenti di effettuare ricerche all’interno dell’archivio di foto, così che sia possibile specificare un termine che compone il titolo della foto. La pagina di risposta conterrà quindi solo le foto che rispondono ai criteri espressi dall’utente. Potete provare questa funzionalità puntando il vostro browser alla cartella ricerca e in particolare visualizzando la pagina ricerca.asp. Compare un form: provate a questo punto a inserire un termine contenuto nel titolo della foto, come ad esempio “fiordaliso” (figura 26). Avviate la ricerca, e come potevamo aspettarci troviamo una pagina del tutto simile a quella degli esempi precedente, ma che contiene esclusivamente le foto ricercate (figura 27). Come di consueto entriamo adesso nel dettaglio del codice ASP che rende possibile questa interessante possibilità. Vediamo per prima cosa il contenuto della pagina con il form di ricerca, ricerca.asp, che si trova nella cartella “ricerca” degli esempi della puntata (listato 3). Si tratta di una pagina che non ci spaventa, in quanto composta da un semplice form in cui inserire il termine di ricerca. Passiamo allora ad affrontare la pagina che contiene il vero e proprio codice di ricerca, elencofoto.asp (listato 4). Non ci sono veri e propri stravolgimenti rispetto a quello che abbiamo realizzato fino ad ora. In realtà ci siamo limitati a modificare la query SQL così da filtrare i dati di interesse, operazione non rara quando si tratta di interrogare una base di dati. Questa volta le due stringhe sql1 e sql2 dipendono dal campo compilato nel form: a una parte fissa di contenuto viene aggiunto il valore inserito dall’utente. Per farlo si usa una query SQL con una forma del tipo: SELECT elenco_campi FROM Tabella WHERE campo operatore criterio La sintassi della prima parte è quella che siamo soliti usare, mentre abbiamo aggiunto qualche cosa di nuovo nella seconda. Quando vogliamo filtrare i risultati presenti in una tabella, possiamo utilizzare la parola chiave “where” e farla seguire dai criteri. Se volessimo cercare tutte le foto che contengono un determinato titolo (ad esempio “montagna”, scriveremo qualche cosa del tipo: SELECT * FROM Foto WHERE Titolo = ‘montagna’ È facile capire il significato della query: “seleziona tutti i record della tabella foto il cui titolo è uguale a ‘montagna’”). La presenza dell’apice singolo a chiudere il termine di ricerca è obbligatorio quando lavoriamo con le stringhe, mentre non va usato nel caso di numeri. L’interrogazione che utilizziamo nell’esempio è però leggermente diversa da quella appena vista, perché leggermente diversa è la nostra esigenza. In effetti noi vogliamo estrarre non tutte le foto che hanno un certo termine come titolo, ma tutte quelle che hanno un titolo che contiene il termine (tanto per fare un esempio reale, vogliamo che cercando “fiordaliso” venga trovata anche la foto il cui titolo è “Fiordaliso Montano”). La sintassi da usare in questo caso è leggermente diversa: SELECT * FROM Foto WHERE Titolo like ‘%fiordaliso%’ Utilizziamo l’operatore “like” al posto di “=”, proprio perché non cerchiamo un’uguaglianza stretta tra il titolo del campo e il valore ricercato. 27 Sono presenti inoltre due simboli di percentuale, uno all’inizio e uno alla fine del termine di ricerca. Come l’asterisco nel DOS, si tratta di caratteri jolly che stanno ad indicare “qualsiasi ripetizione di caratteri”. Il significato di tutta la query diventa quindi “seleziona tutti i record della tabella titolo il cui titolo contenga fiordaliso e qualsiasi carattere prima o dopo questo termine (anche nessuno)”. Se avessimo voluto selezionare tutte le foto che iniziano con fiordaliso avremmo scritto qualche cosa del tipo: SELECT * FROM Foto WHERE Titolo like ‘fiordaliso%’ Viceversa, se fossimo interessati a tutti i record che terminano con fiordaliso, avremmo scritto qualche cosa del tipo: SELECT * FROM Foto WHERE Titolo like ‘%fiordaliso’ 3a lezione zioni. La prima stringa utiliz- zata contiene il seguente codice: SELECT count(nome) AS contatore FROM Foto La struttura è del tutto simile all’esempio precedente, ma la parte relativa alla scelta dei campi ha subìto alcune importanti modifiche. È stata in particolare usata una funzione detta di “aggregazione”, non allo scopo di restituire i record della tabella, ma di effettuare un’analisi statistica sui dati presenti. La funzione count, a cui viene passato il nome di un campo (nome), è quella di restituire (di “contare”) il numero di record con nome della foto diverso uno dall’altro (in poche parole, tutte le foto inserite nella base dati). La seconda query restituisce lo stesso elenco di prima, ma l’abbiamo leggermente modificata per introdurre altre caratteristiche dello standard SQL: SELECT * FROM Foto ORDER BY Data DESC In questo secondo caso manca completamente l’elenco dei campi, che è stato sostituito da un carattere jolly, l’asterisco (*). Il significato di tale sintassi è “selezionare tutti i campi della tabella Foto”. Quindi, senza dover elencare i campi uno per uno, un’operazione nella quale è facile commettere errori quando sono tanti, è possibile usare l’asterisco. Anche se realizziamo applicazioni semplici, vale comunque la pena di non esagerare con l’uso di questa sintassi. Impiegare l’asterisco solo perché serve un campo su 10 non è una buona scelta, poiché le operazioni di lettura dalla base dati saranno certamente più lente. Questa query ha un’altra particolarità che la distingue dall’esercizio precedente: termina con ORDER BY. Com’è facile intuire, in tal modo è possibile ordinare i risultati secondo un campo. Ad esempio, potreste voler ordinare i dati secondo la data di scatto della foto, in modo che le fotografie più recenti compaiano all’inizio. In questo modo gli utenti hanno la possibilità di trovare le foto recenti sempre nelle posizioni più vicine all’inizio della pagina, mentre le foto ormai datate si sposteranno progressivamen- 58/97 te in fondo alla pagina. Utilizziamo quindi ORDER BY seguito dal campo Data della tabella Foto e dalla parola chiave DESC, diminutivo di Descending. Se avessimo voluto ordinarle dalla più datata alla più recente avremmo invece utilizzato ASC (Ascending) oppure nulla, visto che è il comportamento standard. Abbiamo anche modificato il codice che produce l’elenco delle foto, aggiungendo un link. Se prestate attenzione a come lo abbiamo costruito, vedrete che compare un parametro, il nome della foto. In tal modo la pagina di dettaglio della foto riceverà il nome con cui abbiamo salvato l’immagine sul disco del server, e sarà così in grado di visualizzarla. In effetti, se passiamo a verificare il codice della seconda pagina, per prima cosa è estratto il valore del parametro, il nome del file della foto. A questo punto, a metà pagina, inseriamo un tag di tipo IMG. Le immagini sono state precedentemente salvate nella cartella foto del server, per questo facciamo precedere da questa cartella il percorso dell’immagine. Quando il server esegue l’istruzione ASP contenuta nel tag IMG inserisce il nome fisico dell’immagine e a questo punto il browser dispone di tutti gli elementi per visualizzarla nella pagina. Conclusioni Terminiamo qui la prima puntata dedicata all’esplorazione delle basi dati e alla loro integrazione con ASP. A questo punto siete in grado di interrogare qualsiasi tabella, con particolare riferimento a quelle realizzate con Access, anche se la struttura è del tutto ripetibile in altre realtà. Abbiamo però ancora qualche importante concetto da vedere. Ancora non sappiamo, ad esempio, realizzare delle query che interessino più tabelle, nel nostro caso Foto, Provincia e Stato. Ci siamo poi soffermati sulle query di selezione, ma ne esistono di altri tipi, in particolare quelle che vi consentono di inserire, modificare e cancellare i record dalle tabelle. E proprio di questo parleremo nell’ultima puntata del corso Web Developer ASP. Cliccate qui per accedere alla versione elettronica dei listati. LISTATO 1 ELENCOFOTO.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Le foto di Mario Rossi</title> </head> <body> <h1>Le mie foto preferite</h1> <ul> <% Const adOpenForwardOnly = 0 Const adLockReadOnly = 1 Dim sql Dim conn, rs Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/database/foto.mdb") sql = "SELECT Titolo, Luogo FROM Foto" Set rs = Server.CreateObject("ADODB.RecordSet") rs.Open sql, conn, adOpenForwardOnly, adLockReadOnly do until rs.eof %> <li><%=rs.Fields("Titolo")%>, scattata a <%=rs.Fields("Luogo")%></li> <% rs.movenext loop rs.close set rs = nothing conn.close set conn = nothing %> </ul> </body> </html> 59/97 LISTATO 2 ELENCOFOTOLINK.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Le foto di Mario Rossi</title> </head> <body> <h1>Le mie foto preferite</h1> <% Const adOpenForwardOnly = 0 Const adLockReadOnly = 1 Dim contatore Dim sql1,sql2 Dim conn, rs Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/database/foto.mdb") sql1 = "SELECT count(nome) AS contatore FROM Foto" sql2 = "SELECT * FROM Foto ORDER BY Data DESC" Set rs = Server.CreateObject("ADODB.RecordSet") rs.Open sql1, conn, adOpenForwardOnly, adLockReadOnly contatore = rs("contatore") rs.Close() rs.Open sql2, conn, adOpenForwardOnly, adLockReadOnly %> Sono presenti <%=contatore%> foto <br><br> <% do until rs.eof %> <li><a href="dettagliofoto.asp?nome=<%=rs("Nome")%>"><%=rs("Titolo")%>, scattata a <%=rs("Luogo")%></a></li> <% rs.movenext loop 'rs.close 60/97 'set rs = nothing 'conn.close 'set conn = nothing %> </ul> </body> </html> 61/97 LISTATO 3 RICERCA/RICERCA.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Le foto di Mario Rossi</title> </head> <body> <h1>Cerca tra le mie foto preferite</h1> <form action="elencofoto.asp" method="get"> Cerca la foto: <input type="text" name="rfoto"><br> <input type="submit" value="Cerca"> </form> </body> </html> 62/97 LISTATO 4 RICERCA/ELENCOFOTO.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Le foto di Mario Rossi</title> </head> <body> <h1>Le mie foto preferite</h1> Hai selezionato le foto che parlano di <%=request.QueryString("rfoto")%><br> <% Const adOpenForwardOnly = 0 Const adLockReadOnly = 1 Dim contatore Dim sql1,sql2 Dim conn, rs Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/database/foto.mdb") sql1 = "SELECT count(nome) AS contatore FROM Foto WHERE Titolo like '%" & request.QueryString("rfoto") & "%'" sql2 = "SELECT * FROM Foto WHERE Titolo like '%" & request.QueryString("rfoto") & "%' ORDER BY Data DESC " Set rs = Server.CreateObject("ADODB.RecordSet") rs.Open sql1, conn, adOpenForwardOnly, adLockReadOnly contatore = rs("contatore") rs.Close() rs.Open sql2, conn, adOpenForwardOnly, adLockReadOnly %> Sono presenti <%=contatore%> foto che soddisfano i criteri di ricerca<br><br> <% do until rs.eof %> <li><a href="dettagliofoto.asp?nome=<%=rs("Nome")%>"><%=rs("Titolo")%>, scattata a <%=rs("Luogo")%></a></li> <% 63/97 rs.movenext loop 'rs.close 'set rs = nothing 'conn.close 'set conn = nothing %> </ul> </body> </html> 64/97 4a lezione A scuola con PC Open Web Developer ASP di Antonio Volpon 1 Gestire un elenco di foto: la paginazione iamo arrivati alla fine del nostro viaggio all’interno del mondo ASP. Nelle prime due puntate del corso (pubblicate nei numeri di novembre e dicembre di PC Open) abbiamo avuto modo di capire l’importanza di questa piattaforma per lo sviluppo di siti Web, ed evidenziato le differenze rispetto a un sito statico. Nel corso della terza puntata (pubblicata nello scorso numero) abbiamo invece apprezzato l’uso di ASP insieme alle basi di dati, così da sfruttarne appieno le potenzialità. Dopo aver introdotto il ruolo dei database relazionali e la sintassi del linguaggio SQL, siamo passati ad affrontare un esempio pratico: costruire una galleria di immagini per il committente del nostro sito, il signor Mario Rossi. Ci siamo lasciati dopo aver costruito una pagina contenente un campo dal quale effettuare la ricerca nel database delle S foto (figura 1). Il risultato è un elenco di foto che soddisfano il criterio e da cui è possibile aprire la foto che interessa. In questa ultima puntata cercheremo come prima cosa di migliorare il modo con cui viene presentata la lista di foto, introducendo un meccanismo di “paginazione”. Passeremo poi ad aiutare Mario Rossi nel gestire on line il proprio catalogo di foto, creando una maschera di amministrazione (protetta da password) con la quale avrà la possibilità di inserire, modificare ed eliminare le nuove foto che scatterà nel corso delle prossime stagioni. Per farlo completeremo le nostre conoscenze del linguaggio SQL introducendo la sintassi che consente di introdurre, aggiornare e cancellare i record di una tabella. Suddividere un elenco Abbiamo lasciato un Mario Rossi soddisfatto grazie alla 1 65/97 IL CALENDARIO DELLE LEZIONI Lezione 1: Lezione 4: Da sito statico a dinamico Gestire un elenco di fotografie Lezione 2: • L’inserimento Portare il sito sul server • La modifica Lezione 3: ASP e i database relazionali • La cancellazione 2 4a lezione 3 per definire il numero di elementi da far comparire in ogni pagina di risultati. Questo è quello che si ottiene con la riga seguente: rs.PageSize = pagSize Il valore di pagSize è definito una volta per tutte a inizio pagina, così da rendere più semplici eventuali variazioni future. A questo punto è possibile aprire l’oggetto recordset, come sempre, ma per farlo utilizziamo una costante diversa per il tipo cursore. Utilizziamo infatti una sintassi del tipo: rs.Open sql2, conn, adOpenStatic, adLockReadOnly 4 possibilità di effettuare ricerche nel proprio sito. Ben presto Mario si è però accorto che all’aumentare del numero di foto nel proprio archivio on line, l’elenco comincia a diventare decisamente lungo e poco presentabile ai visitatori del suo sito (figura 2). Per questo motivo è interessato a capire se esiste un modo per suddividere l’elenco in più pagine, un po’ come si comporta Google (figura 3) quando visualizza i risultati di una ricerca. Potevamo negare a Mario questa caratteristica da inserire nel suo amato sito? Certamente no, e con alcuni semplici interventi, l’aspetto della pagina di risposta diven- 66/97 terà quello rappresentato in figura 4. Come potete notare, in fondo alla pagina è presente un elenco di numeri, che rappresentano in gergo la “paginazione”, ovvero il meccanismo utilizzato dagli utenti per spostarsi tra le diverse pagine dell’elenco. Per poter realizzare questa caratteristica è necessario modificare il file di partenza, così da ottenere quanto riportato nel listato 1 (elencofoto2.asp). La procedura nel dettaglio Vediamo operativamente le aree su cui intervenire. Il recordset dispone di un metodo, PageSize, che può essere usato Per suddividere la navigazione in pagine, non è più sufficiente utilizzare un recordset di tipo Forward Only, che può essere navigato solo in un senso (cioè da un record al successivo). Un recordset di tipo OpenStatic è una copia speculare dei dati in tabella, che non possono essere modificati o eliminati, ma con il pregio di essere molto veloce durante le letture. Poiché il nostro scopo è solo quello di visualizzare i dati, questa soluzione rappresenta il migliore compromesso. Se osservate con attenzione il codice vedrete che la costante adOpenStatic è stata definita all’inizio della pagina, con valore 3. Avremmo potuto utilizzare direttamente questo valore nel codice, ma la nostra soluzione è sicuramente più ordinata ed elegante. Dopo aver aperto il record è il momento di informare il recordset riguardo il numero di pagina che vogliamo visualizzare. All’inizio sarà sicuramente la prima pagina, ma successivamente sarà l’utente, selezionando i link della paginazione, a indicare dove spostarsi. Per vedere come questo si verifica è necessario osservare la pagina dal browser e poi capire cosa c’è scritto nel codice. Spostatevi per prima cosa con il mouse sopra i link che formano la paginazione e osservate l’indirizzo che compare nella barra di stato del browser (la barra di stato è rappresentata dalla fascia nella parte bassa della finestra del browser). Come potete notare, l’indirizzo ha una forma del tipo: http://localhost/elencofoto2.asp? pag=2 (quando selezioniamo la seconda pagina) oppure http://localhost/elencofoto2.asp? pag=3 (per la terza pagina) e così via. In particolare, quando selezioniamo un link viene caricata sempre la pagina elencofoto2.asp, ma sarà il parametro pag (che indica il numero di pagina con le foto da visualizzare) a cambiare di volta in volta. È lecito quindi aspettarsi che all’interno del codice della pagina, da qualche parte, venga estratto il valore del parametro pag e che questo venga utilizzato per richiedere al recordset la pagina corrispondente. Ed è in effetti quello che si verifica in questa parte del codice: 'Estrae il numero di pagina pagNum = cint(request.Query String("pag")) If pagNum = 0 Then pagNum = 1 Lo scopo di questa parte di codice è chiaro: viene estratto il valore della pagina da visualizzare e assegnato alla variabile pagNum. La prima volta che il visitatore richiede la pagina, tuttavia, non specifica alcun numero e in questo caso (come si vede nella seconda linea di codice), l’utente viene diretto alla prima pagina. La riga: rs.AbsolutePage = pagNum assegna il valore appena estratto al metodo AbsolutePage del recorset: lo scopo è proprio quello di restituire la pagina voluta. Queste sono tutte le informazioni necessarie al recordset per posizionarsi sulla pagina corretta. L’ultima modifica di cui abbiamo bisogno per gestire più pagine di foto riguarda il ciclo che estrae i record. In questo caso non è sufficiente visualizzare, come abbiamo fatto finora, tutti i record presenti nel recordset (utilizzando un ciclo do until rec.eof). Vogliamo invece limitare il numero di record presentati a quelli che compongono la pagina: possiamo allora utilizzare una sintassi di questo tipo: for i = 1 to pageSize <visualizza i dati della foto> next 4a lezione Anche questa porzione di codice, dopo 3 puntate del corso ASP, non ha per noi troppi segreti: si tratta di un ciclo che va da 1 a pageSize, ovvero dalla prima fino all’ultima foto della pagina (ricordatevi che il valore di pageSize è stato definito ad inizio pagina). Solo con queste 2 righe, però, rischia di generarsi un errore in fase di esecuzione. Provate infatti a pensare cosa succede se visualizzate 35 foto in pagine da 10 elementi. Il ciclo for next sarebbe equivalente al seguente: for i = 1 to 10 <visualizza i dati della foto> next L’ultima pagina (la quarta) contiene solo 5 foto. Il ciclo precedente cerca in ogni caso di visualizzare anche la foto numero 6, e il codice genera un errore. È necessario inserire qualche cautela, e aggiungere all’interno del ciclo qualcosa di questo tipo: if not rs.EOF Then <visualizza i dati della foto> else exit for end if Il ciclo for next viene eseguito solo se ci sono altri record nel recordset, altrimenti (con exit for) ne forziamo l’uscita. Ricapitoliamo la situazione Nei paragrafi precedenti abbiamo stabilito quante foto visualizzare per ogni pagina, come fare a spostarci da una pagina all’altra, e siamo riusciti a visualizzare senza errori tutte le foto. A questo punto non ci resta che visualizzare la barra di paginazione in fondo alla pagina, e per farlo ci spostiamo a osservare la fine del codice. Il pezzo responsabile dell’elenco è il seguente: <% for j = 1 to rs.PageCount %> <a href="<%=request. ServerVariables("PATH_INFO") %>?pag=<%=j%>"><%=j%></a> <% next %> Anche in questo caso è presente un ciclo for next, solo che questa volta non scorriamo tra le foto di una pagina, ma tra tutte le pagine di foto, utilizzando il metodo PageCount dell’oggetto recordset (che come è facile intuire restituisce il numero di pagine nel quale è stato suddiviso l’elenco). A questo punto è realizzato un collegamento ipertestuale (un link HTML), sfruttando un metodo dell’oggetto request. Lo scopo di request.ServerVariables(“PATH_INFO”) è quello di estrarre il nome della pagina ASP correntemente in esecuzione. Immaginate di aver crea5 67/97 6 to una pagina “miapagina.asp” e di eseguirla tramite IIS (Internet Information Services): il metodo ServerVariabiles restituirà in questo caso “miapagina.asp”. Potrebbe a prima vista sembrare una mossa poco utile, in realtà così facendo non dovete intervenire nel codice se un domani decidete di rinominare la vostra pagina ASP. Per questo motivo le 3 linee di codice riportate poco sopra possono essere copiate e incollate in qualsiasi pagina necessiti della paginazione senza doverle adattare per i diversi scopi. Il link viene a questo punto completato dal parametro indicante il numero di pagina che, come abbiamo visto precedentemente, viene usato dal recordset per posizionarsi. Per un elenco composto di 4 pagine il risultato del ciclo sarà il 7 4a lezione seguente: <a href="miapagina.asp? pag=1">1</a> <a href="miapagina.asp? pag=2">2</a> <a href="miapagina.asp? pag=3">3</a> <a href="miapagina.asp? pag=4">4</a> Come sempre, al termine della pagina rilasciamo le eventuali risorse impiegate, cioè il recordset e la connessione. Partendo dall’esempio appena realizzato, introduciamo ora qualche miglioria alla paginazione presente a fondo pagina. Se navigate abitualmente in internet, vi sarà capitato spesso di imbattervi in un elenco di risultati diviso in più pagine. Una caratteristica che normalmente possiede la paginazione è di non presentare un collegamento alla pagina precedente. Per capirci, se osservate la pagina di figura 5, noterete che la paginazione contiene dei link a tutte le pagine, fuorché la prima, che è quella corrente. Spostandoci alla seconda pagina (figura 6), vediamo che anche quest’ultima non presenta link. La ragione è duplice: da un lato è inutile presentare un link alla pagina corrente (visto che già ci siamo), dall’altro guardando la paginazione è facile capire in quale pagina ci troviamo a navigare. Per questo motivo il numero che si riferisce alla pagina corrente è solitamente evidenziato, cosa che del resto abbiamo fatto anche noi in questo esempio utilizzando il grassetto. La modifica necessaria per ottenere questa caratteristica è davvero semplice, ma migliora l’esperienza dell’utente. Se osserviamo il listato 2, notiamo che la parte finale, dedicata alla paginazione, è stata arricchita in questo modo: <% for j = 1 to rs.PageCount %> <% if j = pagNum then %> <strong><%=j%></strong> <% else %> <a href="<%=request. ServerVariables("PATH_INFO") %>?pag=<%=j%>"><%=j%> </a> <% end if %> <% next %> strTipo%>">&laquo;</a> <% End If %> Il codice visualizza le frecce verso sinistra (che in HTML possono essere rappresentate utilizzando l’entità &laquo;), ma non sempre: solo quando non ci troviamo sulla prima pagina. Il numero di pagina a cui andare è ricavato molto semplicemente sottraendo 1 alla pagina corrente. In modo del tutto speculare, dopo la paginazione abbiamo introdotto queste istruzioni: <% If pagNum < rs.PageCount Then %> <a href="<%=request. ServerVariables("PATH_INFO") %>?pag=<%=pagNum+1%>"> &raquo;</a> <% End If %> Il codice è del tutto simile all’esempio precedente, con la sola aggiunta di un’istruzione condizionale if...then...else. Ad ogni iterazione il codice verifica se il ciclo è arrivato alla pagina corrente. In questo caso non viene costruito il link, ma viene semplicemente visualizzato il numero dopo averlo convertito in grassetto. Una seconda caratteristica che è normale incontrare navigando in Internet è composta dai pulsanti avanti e indietro, utilizzati per spostarsi agevolmente alla pagina successiva e a quella precedente (li abbiamo rappresentati in figura 7 come delle doppie frecce). Il codice completo lo trovate nel listato 3, ma soffermiamoci sulla parte relativa alla paginazione. Poco prima del ciclo for...next possiamo notare questo codice: Il significato è il medesimo, solo che questa volta le frecce verso destra sono introdotte solo quando non ci troviamo sull’ultima pagina. Ma il listato appena presentato dispone anche di un’ulteriore caratteristica, come potete osservare se eseguite la pagina con un browser. Come potete osservare, i link che compongono l’elenco delle foto sono alternativamente di due colori. Per rendere possibile questa caratteristica, è necessario analizzare il codice all’interno del ciclo for...next che genera l’elenco. Le righe che ci interessano sono: <% If pagNum > 1 Then %> <a href="<%=request. ServerVariables ("PATH_INFO")%>?pag= <%=pagNum -1%><%= if i mod 2 = 0 then strColor="#3333CC" else strColor="#FF0033" end if È facile intuire che l’espressione condizionale assegna alle variabili strColor uno a scelta tra 2 colori, ma quello che ci rimane da capire è come realizzare l’alternanza. Abbiamo utilizzato l’operatore mod (modulo) che, posto tra due numeri, restituisce il resto della divisione tra il primo e il secondo. Cerchiamo di spiegarci con un esempio. Se la variabile i vale 4, l’operazione diventa 4 mod 2. La divisione di 4 per 2 restituisce 2, con resto 0. Quindi 4 mod 2 = 0. Se la variabile i vale 5, la divisione restituisce 2 con resto 1, quindi il modulo è 1. Più in generale, il resto della divisione tra un numero e 2 è 0 quando questo numero è pari, altrimenti è 1. Ecco allora spiegato il significato della condizione. Potremmo interpretarla come segue: se la variabile i è pari, allora assegna strColor a “#3333CC”, altrimenti (se cioè è dispari) diventa “#FF0033”. La variabile quindi assume una volta il primo valore, la volta successiva il secondo valore, proprio quello che ci saremmo aspettati. Ma dove viene cambiato effettivamente il valore del link, e in che modo? Responsabile del cambiamento è la seguente linea: <a style="color:<%=strColor%>"... Per realizzare questo effetto abbiamo impiegato una semplice sintassi dei CSS (Cascading Style Sheet) che ci consente di variare velocemente il colore della voce in elenco sfruttando il valore della variabile strColor. 2 Inserire una nuova fotografia razie a quello che abbiamo visto finora siamo in grado senza troppi problemi di visualizzare l’elenco di foto di Mario Rossi, anche suddividendo i risultati in più pagine. Mario ha però un’altra importante esigenza: caricare e gestire le foto che scatterà nei prossimi mesi. Una prima soluzione a questa necessità potrebbe essere G 68/97 quella di aggiornare direttamente il database Access (come abbiamo fatto la scorsa puntata quando siamo andati a inserire alcuni record), ma questo vuol dire portare ogni volta tutto il database nella cartella del server Web. La soluzione che proponiamo, e che viene spesso adottata da chi lavora sul Web per aggiornare i dati, consiste nel realizzare alcune pagine ASP ad hoc che si preoccupino di comunicare le operazioni di inserimento, modifica e cancellazione direttamente al database. La maschera di inserimento Un esempio di maschera per l’inserimento, che impareremo a costruire insieme, è presentata in figura 8. In realtà Mario non è in grado di gestire com- pletamente l’intero processo attraverso queste schermate. I file JPG delle foto devono essere comunque portati sul server “a mano”, utilizzando un programma per il trasferimento dei file che sfrutti il protocollo FTP (File Transfer Protocol). Nel nostro caso non si tratta di un limite: Mario deve semplicemente portare per prima cosa le foto sul server, e successiva- 4a lezione mente utilizzare le schermate che gli mettiamo a disposizione per inserire il record nelle tabelle, completandolo dalla descrizione, dalla data, e da tutte le altre informazioni che compaiono nella scheda. Esistono in realtà componenti di terze parti che permettono di inviare file (documenti, immagini, video) direttamente da una pagina ASP. Non ne parliamo in questo corso perché introdurremo delle complessità che non ci permetterebbero di concentrarci sulla sintassi SQL necessaria a completare le operazioni. Se siete interessati a questa problematica potete ad esempio far visita all’indirizzo www.aspupload.com, sito di una società che sviluppa un componente a pagamento per gestire l’invio di file da una pagina ASP. Inserire una nuova foto Vediamo come aiutare Mario ad inserire una nuova foto nel database on line. Per prima cosa portate i file di questa lezione (che trovate nel CD ROM allegato) nella directory principale del vostro server Web, eventualmente cancellando oppure rinominando eventuali pagine realizzate nelle scorse lezioni. Successivamente, come abbiamo detto, è necessario copiare le foto nella cartella del server Web utilizzando per esempio un programma FTP (oppure, se state provando in locale, è sufficiente copiare i file da una cartella a quella del Web server). A questo punto indirizzare il vostro browser al file gestione_inserisci.asp (figura 9). È una pagina del tutto simile alla lista realizzata nell’esempio precedente, che è però dotata di un link per inserire una nuova foto. Non ci serve entrare nel dettaglio del codice sorgente, che riportiamo nel listato 4, per cui possiamo cliccare sul link, così da portarci nella maschera di inserimento che abbiamo visto poco fa. In questo caso abbiamo introdotto alcune importanti novità, per cui soffermiamoci ad analizzare nel dettaglio il codice sorgente (listato 5). Come è lecito aspettarsi, quasi tutto il codice della pagina è contenuto all’interno di un form, il cui attributo action porta alla pagina inseriscimodifica_risposta.asp. Questa è la pagina che utilizzeremo per inserire effettivamente i dati all’interno della tabella, e che vedremo tra poco. La parte più interessante della pagina è quella utilizzata per creare i due combo box per la selezione della provincia e dello stato. Se vi ricordate i nostri discorsi rispetto alla normalizzazione delle tabelle, che 8 69/97 9 abbiamo introdotto la scorsa puntata, saprete che abbiamo deciso di suddividere la tabella foto così da separarla dai dati della provincia e dello stato. La tabella foto contiene unicamente un riferimento (detto chiave esterna) alla provincia e allo stato. L’unica informazione che è necessario inserire nella tabella foto è quindi il codice della provincia e il codice dello stato, e questa è esattamente l’operazione che andiamo a fare in questa parte del sorgente: <select name="provincia"> <% sql = "SELECT * FROM Provincia ORDER BY Provincia DESC" rs.Open sql, conn, adOpenForwardOnly, 10 4a lezione adLockReadOnly do until rs.Eof %> <option value="<%=rs ("IdProvincia")%>"><%=rs ("Provincia")%></option> <% rs.movenext loop rs.Close() %> </select> Abbiamo creato un recordset che preleva l’elenco delle province dalla rispettiva tabella, e realizzato un controllo HTML di tipo select. A questo punto scorriamo il recordset e per ogni provincia trovata aggiungiamo una voce all’elenco. Prestate attenzione al fatto che la descrizione viene presentata all’utente sulla pagina, mentre il codice della provincia (IdProvincia) viene associato all’attributo value del tag option. Questa operazione è necessaria perché il valore da scrivere nella tabella foto è, come dicevamo prima, il codice della provincia, mentre la descrizione è utile solo ai fini della visualizzazione. Per rendervi conto del risultato di questo pezzo di codice date un’occhiata al sorgente della pagina inviata al browser. Anche per la selezione dello stato utilizziamo la stessa tecnica, che non commentiamo ulteriormente. L’impiego di un controllo di questo tipo è utile quando i valori da selezionare sono in numero limitato (intorno ai 100) ed evita all’utente di commettere qualche errore nel corso della compilazione. Sempre in tema di semplicità e interfaccia notate come abbiamo realizzato il campo data. Piuttosto che utilizzare un unico campo e lasciare all’utente la libertà di separare l’anno dal mese e dal giorno abbiamo scelto di utilizzare 3 campi: in questo modo è evidente come debbano essere compilati. Vedremo tra poco che le cautele non terminano qui, ma che è anche necessario verificare che l’utente inserisca dei valori coerenti per il giorno, il mese e l’anno. Navigando in internet è a volte possibile trovare alcuni form in cui anche per la data sono stati impiegati dei combo box, come per le province e gli stati. Questa soluzione è in realtà poco efficace per l’utente, che impiega sicuramente più tempo a scegliere 70/97 le voci dell’elenco piuttosto che digitarle nei 3 campi, per cui ne sconsigliamo l’adozione. Compilate a questo punto i dati della foto (inserendo come data quella odierna), sullo stile di come abbiamo fatto noi in figura 10, e premete il pulsante Inserisci. La risposta non lascia spazio ai dubbi: Foto inserita correttamente. Per rendervi conto che il record è stato effettivamente inserito provate ad aprire con il browser la lista delle foto, e vedrete quella appena inserita comparire in testa (compaiono per prime le foto più recenti). La pagina responsabile dell’effettivo inserimento nella tabella è inseriscifoto_risposta.asp, che passiamo adesso subito ad analizzare (listato 6). A inizio della pagina vengono estratti i valori della foto che sono stati passati dal form. L’unica particolarità di queste righe è nella creazione della data, che viene composta partendo dal giorno, dal mese e dall’anno. Creiamo e apriamo la solita connessione e a questo punto definiamo la stringa SQL che ci permette di inserire i dati. SQL, come abbiamo avuto modo di approfondire la scorsa puntata, è il linguaggio utilizzato per interrogare una base di dati, ma anche per inserire, modificare e cancellare record. Finora abbiamo avuto modo di apprezzare solo la prima di queste caratteristiche, facendoci restituire una lista di foto oppure il dettaglio. Vediamo ora qual è la sintassi da usare per inserire un record (riportiamo in maiuscolo le parole chiave): INSERT INTO nome_tabella (campo1, campo2, campon) VALUES (valore1, valore2, valoren) È un’istruzione alquanto semplice. Specifichiamo come prima cosa il nome della tabella in cui inserire i valori. A questo punto, tra parentesi, indichiamo il nome dei campi da inserire; è importante che in questa lista compaiano tutti i campi la cui compilazione è obbligatoria, pena un errore in fase di esecuzione. A questa lista segue la parola chiave VALUES e infine l’elenco, sempre tra parentesi, dei valori che vogliamo inserire. Precisiamo subito che, come è facile intuire, il primo valore (valore1) si riferisce al primo campo (campo1), e così via. Nel nostro caso specifico il codice che abbiamo scritto è il seguente: sql = "INSERT INTO Foto ( Nome, Titolo, Data, Luogo, IdProvincia, IdStato ) VALUES (" & _ "'" & strNome & "', " & _ "'" & strTitolo & "', " & _ "'" & strData & "', " & _ "'" & strLuogo & "', " & _ "'" & strProvincia & "', " & _ "'" & strStato & "' " & _ ")" La sintassi è la medesima, complicata solo dal fatto che stiamo costruendo una stringa concatenando valori diversi. Per rendere il codice più leggibile, e per evitare di scrivere una lunga riga con l’intera concatenazione, abbiamo preferito terminare ogni riga con “& _”. Così facendo è possibile andare a capo senza generare errori in fase di esecuzione: non appena il compilatore Visual Basic Script incontra questi 2 caratteri capisce che l’istruzione continua sulla riga successiva. L’esecuzione dell’istruzione SQL Arrivati a questo punto, dopo aver creato una stringa con l’istruzione SQL, è sufficiente eseguirla. In questo caso non abbiamo necessariamente bisogno di un recordset, poiché l’unica e indivisibile operazione che ci interessa portare a termine è l’inserimento. Possiamo allora utilizzare un comodo metodo dell’oggetto Connection: Execute. Come potete vedere nell’ultima parte del codice, la sintassi è semplicissima, poiché basta richiamare il metodo insieme alla stringa con il codice SQL da eseguire. I giochi sono fatti, il record è stato inserito e possiamo avvisare l’utente della conclusione dell’operazione. Come migliorare la pagina Realizzare una pagina di inserimento non ha richiesto molto sforzo, ma questo tipo di pagine (insieme a quelle che consentono la modifica) devono essere realizzate con alcuni accorgimenti che evitino all’utente di inserire inavvertitamente dati non corretti. In questo esempio specifico i punti di intervento per migliorare la pagina sono diversi. Per prima cosa è necessario verificare che l’utente non tenti di inserire una foto con un nome già utilizzato. Se vi ricordate come abbiamo costruito la tabella, infatti, il campo nome è una chiave primaria, e caratteristica di una chiave primaria è l’univocità per tutti i record della 11 4a lezione tabella. Se l’utente tenta di in- serire due volte lo stesso nome, quindi, è bene che venga avvertito e l’operazione interrotta. Un altro punto critico è l’inserimento della data. L’utente potrebbe inserire lettere al posto dei numeri, o potrebbe ad esempio invertire i mesi con i giorni. È buona abitudine, prima di procedere con l’inserimento, verificare che il formato della data sia corretto. Infine, anche se è stato preso ogni accorgimento affinché l’utente inserisca solo dati coerenti, qualcosa può sempre andare per il verso sbagliato. Ci potrebbe essere un problema di rete, o il database potrebbe soffrire di qualche problema di lentezza. In tutti i casi, dopo avere eseguito il metodo Execute, è bene verificare qual è stato l’esito dell’operazione. Tutte queste modifiche entrano allora a far parte di una nuova pagina, che chiameremo inseriscifoto_risposta_2.asp, che presentiamo nel listato 7 e che cominciamo senza indugi a studiare. Costruiamo per prima cosa un recordset che ci aiuti nel verificare la presenza di una foto con lo stesso nome di quella che vogliamo inserire. Per farlo utilizziamo una stringa SQL di tipo SELECT e che utilizza la funzione di aggregazione count(), che restituisce il numero di record. La clausola WHERE viene costruita utilizzando il nome della foto che vorremo inserire. Il significato dell’istruzione è: “restituisci il numero di foto contenute nella tabella foto con un nome uguale a quella che si vorrebbe inserire, e chiama questo valore ‘totale’”. È esattamente quello che vogliamo. A questo punto è sufficiente una semplice condizione per verificare se il totale è maggiore di zero, nel qual caso esiste già una foto in tabella con quel nome. È la situazione che si verifica in figura 11. L’istruzione response.end all’interno della condizione termina immediatamente l’esecuzione della pagina ASP. Si tratta di una soluzione che abbiamo adottato per ridurre la complessità della pagina, ma buona regola sarebbe ripresentare la schermata compilata dall’utente e dargli la possibilità di modificare il nome della foto senza che sia costretto a reinserire tutti i valori. La seconda condizione presente nella pagina verifica invece se la data inserita è in un formato valido. L’operazione è molto semplice in quando esiste una vera e propria istruzione pensata allo scopo: IsDate. L’istruzione restituisce vero se riesce a risalire a una data dalla stringa passata, falso negli altri casi. Abbiamo fatto seguire questo controllo da un’altra cautela che è bene adottare quando si inseriscono i dati in una tabella utilizzando direttamente il linguaggio SQL. Prima non ci siamo soffermati su una particolarità della stringa SQL che andiamo a inserire, ma se guardate con attenzione il modo con cui costruiamo la INSERT, noterete che ogni valore è stato racchiuso da apici singoli. Questa operazione è necessaria ogni volta che i valori da inserire sono di tipo stringa. Un esempio di questo tipo è dato dalla seguente riga di codice: INSERT INTO Foto (Nome,Titolo) VALUES (‘DSC1234’,’Tramonto’) Ma cosa succede se l’utente inserisce un apice come titolo della foto? La riga diventerà qualche cosa del tipo: INSERT INTO Foto (Nome,Titolo) VALUES (‘DSC1234’,’L’alba’) La presenza di un apice non è indolore: durante l’esecuzione del codice si verifica un errore perché il sistema non è in grado di distinguere tra apici intesi come delimitatori rispetto a quelli inseriti nel testo. Un modo in realtà esiste e consiste nel “raddoppiare” ogni apice presente nel valore, ottenendo quindi questa stringa: INSERT INTO Foto (Nome,Titolo) VALUES (‘DSC1234’,’L’’alba’) La modifica al nostro codice non è complessa grazie all’impiego di un’altra importante istruzione messa a disposizione da Visual Basic Script: replace. La funzione replace riceve in input 3 argomenti (in realtà anche degli altri, ma per il nostro esercizio ne sono sufficienti solo 3): la stringa su cui intervenire, la stringa da sostituire, e quella che sostituisce. Ecco allora che l’istruzione strNome = replace(strNome,"'","''") non fa altro che prendere il nome della foto, sostituire eventuali apici singoli in doppi, e assegnare alla stessa variabile il risultato dell’operazione. Nel nostro esempio questa sostituzione, oltre che nel nome della foto, va estesa al titolo della foto e al luogo di scatto. L’ultima parte del codice della pagina si preoccupa invece di eventuali problemi verificatesi durante l’esecuzione dell’inserimento. Per evitare che il codice vada in condizione di errore abbiamo fatto precedere il metodo Execute dall’istruzione on error resume next. Se vi ricordate quanto detto nella seconda puntata, questa istruzione impedisce l’arresto dell’esecuzione della pagina quando si verifica un errore. A questo punto, subito dopo l’Execute, viene richiamata una funzione ConnError a cui è passato l’intero oggetto Connection. ConnError non è una funzione VBScript, ma è in realtà una funzione che abbiamo scritto noi stessi, e che potete trovare in fondo alla pagina. L’oggetto Connection è dotato di una collezione di errori (con l’oggetto Errors) che noi iteriamo, contiamo ed eventualmente stampiamo sulla pagina. La funzione restituisce il numero di errori riscontrati e se il totale è maggiore di zero l’utente è avvisato del problema che si è verificato. Ricordate di prestare sempre molta attenzione quando date all’utente del vostro sito la possibilità di modificare e inserire record nelle tabelle. Il numero di errori che può commettere, anche se in buona fede, è infatti elevato: dovrete arricchire il vostro codice di numerosi controlli e attenzioni. 3 Modificare le foto nell’elenco ario Rossi è soddisfatto: ha la possibilità di gestire gli inserimenti delle proprio foto in modo semplice e intuitivo. A questo punto avverte però la necessità di apportare modifiche ai dati inseriti precedentemente. È una situazione abbastanza comune: potrebbe voler aggiungere informazioni a foto già caricate o semplicemente correggere M 71/97 qualche errore di inserimento. Per dare a Mario questa possibilità, interveniamo per prima cosa sul codice della pagina di gestione, quella che contiene l’elenco di foto su cui intervenire. La figura 12 illustra il pannello di controllo: come potete osservare accanto a ogni voce compare la possibilità di modificare la foto. Un’alternativa sarebbe stata quella di creare una maschera di ricerca ad hoc, ma la soluzione che proponiamo è più generale (la useremo anche per la cancellazione) e semplice (riportiamo il codice nel listato 8). L’unica parte interessante dell’intera pagina è proprio il link: [<a href="modificafoto.asp? nome=<%=rs("nome")%>"> modifica</a>] Viene caricata la pagina modificafoto.asp e le è passato il nome (cioè l’identificativo univoco, essendo chiave primaria) della foto da aggiornare. Se provate a selezionare la modifica di una foto si aprirà una pagina contenente, come ci saremmo aspettati, un form non tutti i dati della foto (figura 13), anche se in realtà noterete che non è prevista la modifica 4a lezione 12 del nome. In effetti dovreste valutare attentamente se concedere ai vostri utenti la modifica della chiave primaria di una tabella. Cosa succede se l’utente tenta di modificare il nome della foto con quello di una foto già presente nella tabella? Quale delle due foto dobbiamo mantenere e quale rinominare? Solitamente, ma questa non è una regola (la soluzione dipende dal tipo di dati che state gestendo), la chiave primaria non è modificabile. Se l’utente desidera cambiarla, elimina la foto dalla tabella e reinserisce nuovamente i dati, e questa è la soluzione che adottiamo nel nostro caso. Il codice di modificafoto.asp (listato 9) è del tutto simile a quello di inseriscifoto.asp, con la sola eccezione che i campi sono già compilati con i dati della foto. Come vi ricorderete, la pagina è richiamata passando il nome della foto. A questo punto creiamo una connessione e un recordset che restituisca un record contenente tutti i dati della foto da utilizzare per riempire i campi. Per i tag di tipo “text” la modifica è molto semplice, e consiste nell’utilizzare l’attributo value. Osserviamo ad esempio il 72/97 campo titolo: <input type="text" size="20" name="titolo" maxlenght="255" value="<%=rs("titolo")%>"> La riga non ha bisogno di troppi commenti: nella casella che contiene il testo è estratto il valore del campo titolo. Il tag per il campo luogo si comporta nello stesso modo, mentre per la data la situazione è leggermente diversa, poiché si tratta di dividere l’informazione su 3 campi. In questo caso ci vengono in aiuto le funzioni Day, Month e Year che come è facile immaginare restituiscono il giorno, il mese e l’anno di una data passata come parametro. If rs2("IdProvincia") = rs("IdProvincia") Then strSuffisso = " selected" Else strSuffisso = "" End If Rs2 è il recordset che contiene l’elenco di tutte le province, mentre rs è il recordset che si riferisce alla foto attualmente in modifica. Il controllo è molto semplice: se la provincia che stiamo visualizzando dall’elenco è la stessa della foto, associamo alla variabile strSuffisso il valore “selected”, altrimenti lasciamo la variabile senza valore. A questo punto usiamo questa stringa per completare la voce dell’elenco in HTML. Se in una combo box utilizzare l’attributo selected, questa voce apparirà selezionata nell’elenco, ed è proprio quello che vogliamo. La stessa cosa si verifica, come potete immaginare, anche per la selezione dello stato. Notate anche che nella pagina compare un campo nascosto, il nome della foto. Abbiamo inserito questo valore per poter passare il nome della foto alla prossima pagina, che userà il valore per sapere quale foto aggiornare tra tutti i record presenti nella tabella. Non c’è altro di interessante in questa pagina, per cui passiamo a vedere cosa contiene la pagina di risposta, che è anche la pagina che si preoccupa dell’aggiornamento: modificafoto_risposta.asp (listato 10). La pagina contiene già tutti gli accorgimenti che abbiamo introdotto in fase di inserimento di una foto, ovvero le cautele in caso di errore, la gestione dell’accento singolo e il controllo sul formato della data. Quella che cambia è sostanzialmente la sintassi del comando SQL, che per un aggiornamento ha una forma del tipo: UPDATE nome_tabella SET campo1 = valore1, campo2 = valore2, campon = valoren WHERE condizione Il significato è immediato: “aggiorna il campo1 della tabella nome_tabella con il valore1, ecc”. Prestate sempre attenzione a specificare la clausola WHERE. Nel nostro caso, infatti, la sola foto che vogliamo aggiornare è quella con il nome specificato, ma un comando di UPDATE può agire su un qualunque numero di record di una tabella (anche tutti, se non specificate alcuna clausola WHERE). Per eseguire questa istruzione è sempre possibile utilizzare l’utile metodo Execute della connessione, senza dover aprire recordset. 13 I controlli di tipo combo box Passiamo adesso a qualcosa di più complicato. Quando si tratta di visualizzare la provincia e lo stato siamo di fronte a controlli di tipo combo box, che visualizzano una lista di tutte le selezioni possibili. L’esigenza in questo caso è di aprire un recordset di province, estrarle e visualizzarle tutte, ma anche evidenziare e selezionare quella associata alla foto. Per farlo inseriamo una condizione all’interno del ciclo seguente: 4a lezione 4 Cancellare una fotografia ’ ultima fase che ci rimane da affrontare per chiudere il percorso sull’aggiornamento del catalogo riguarda la cancellazione. Dobbiamo cioè scoprire come eliminare una fotografia dall’elenco. Come nel caso della modifica, anche in questo caso aggiungiamo una voce a destra del nome della foto, nell’elenco, evidenziando questa possibilità (figura 14). La rimozione di una foto dal database è un’operazione che non richiede il passaggio a una schermata in cui inserire o modificare dei valori: è un’azione diretta. Per questo motivo non è necessario produrre una pagina eliminafoto.asp (come è stato per inseriscifoto.asp e modificafoto.asp), ma possiamo direttamente passare alla costruzione di eliminafoto_risposta.asp. La cancellazione di una foto è però un’operazione a rischio: se l’utente preme inavvertitamente il link elimina, la foto viene tolta dalla tabella senza che sia possibile annullare l’operazione. Per questo genere di azioni è importante introdurre una qualche forma di avvertimento da parte del browser per chiedere all’utente quali sono le sue effettive intenzioni (qualcosa di simile a quello che compare in figura 15). L’utente che ha inavvertitamente premuto il pulsante di cancellazione ha la possibilità di annullare l’operazione, mentre chi è deciso a cancellare la foto può semplicemente confermare. Questo tipo di controllo non ha nulla a che fare con ASP o con il codice VBScript (che viene eseguito a lato server), ma è realizzato dal lato del client (è cioè il browser stesso che lo esegue) utilizzando codice Javascript. Il codice è tutto all’interno del link per la cancellazione: L [<a onclick="javascript:return confirm('Cancellare la foto selezionata ?')" href="eliminafoto_risposta.asp? nome=<%=rs("nome")%>"> elimina</a>] 73/97 Il codice precedente apre una finestra di richiesta (confirm) quando l’utente clicca sul link (evento onclick). A questo punto il browser apre la pagina con il link solo in caso di risposta affermativa alla domanda, altrimenti non è caricata nessuna pagina, ma la visualizzazione rimane a quella corrente. Avremmo anche potuto realizzare un controllo lato server, con una schermata HTML contentente la scritta di conferma all’interno di un form, ma l’utente avrebbe dovuto compiere due richieste e non solo una al server Web, rendendo l’operazione (per quanto non sia una routine) abbastanza lenta. 14 La sintassi del codice per la cancellazione Non ci resta a questo punto che guardare il codice che si occupa della cancellazione (presente nel listato 11). Come potete immaginare l’unica cosa che cambia rispetto agli esempi precedenti è la sintassi del comando SQL che permette di eliminare un record dalla tabella. Questo ha una forma del tipo: DELETE FROM nome_tabella WHERE condizione Non c’è bisogno di specificare alcun nome di campo: quando si cancella un record si cancellano i valori di tutti i campi, è quindi inutile specificarli. Come per l’UPDATE, prestate attenzione a specificare una clausola WHERE che comprenda i record che volete cancellare, e solo quelli. La cancellazione può essere effettuata da un minimo di un record, a un massimo che corrisponde a tutta la tabella. Mario Rossi ha a questo punto tutto quello che gli serve: può inserire una nuova foto, modificarla ed eventualmente cancellarla. Non solo: ha un sistema di visualizzazione presente nel suo sito che organizza le foto per ordine di data e presenta una simpatica navigazione per scorrere le pagina avanti e indietro. A questo punto non gli resta che scattare tante foto da mettere presto on line! Conclusione Con questa puntata termina il corso di 4 puntate dedicate al mondo ASP. Siamo passati da una fase di introduzione della sintassi del linguaggio, e siamo arrivati a comunicare con i database, spingendoci fino a inserire e modificare dati nelle tabelle. Disponete adesso delle basi per sbizzarrirvi nella realizzazione del vostro sito personale, e perché no, anche professionale. Le applicazioni da realizzare non mancano di certo: potete realizzare una agenda da consultare, un elenco dei film e album preferiti, e magari un guestbook per i visitatori del vostro sito: tutte applicazioni che sfruttano quanto appreso in queste 4 puntate. A questo punto l’unico limite a quello che potete fare con ASP è dato unicamente dalla vostra fantasia...buon lavoro! I listati citati nell’articolo sono nel CD Guida 2 nella sezione “Corsi Open Master” 15 Cliccate qui per accedere alla versione elettronica dei listati. LISTATO 1 ELENCOFOTO2.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Le foto di Mario Rossi</title> </head> <body> <h1>Le mie foto preferite</h1> Hai selezionato le foto che parlano di <%=request.QueryString("rfoto")%><br> <% Const adOpenStatic = 3 Const adLockReadOnly = 1 Const adOpenForwardOnly = 0 Dim Dim Dim Dim Dim Dim contatore sql1,sql2 conn, rs pagNum pagSize i,j pagSize = 2 Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/mdb-database/foto2.mdb") sql1 = "SELECT count(nome) AS contatore FROM Foto WHERE Titolo like '%" & request.QueryString("rfoto") & "%'" sql2 = "SELECT * FROM Foto WHERE Titolo like '%" & request.QueryString("rfoto") & "%' ORDER BY Data DESC " Set rs = Server.CreateObject("ADODB.RecordSet") rs.Open sql1, conn, adOpenForwardOnly, adLockReadOnly contatore = rs("contatore") rs.Close() 'Estrae il numero di pagina pagNum = cint(request.QueryString("pag")) If pagNum = 0 Then pagNum = 1 'Imposta la dimensione della pagina (il numero massimo di elementi da far comparire per ogni pagina) rs.PageSize = pagSize rs.Open sql2, conn, adOpenStatic, adLockReadOnly 74/97 %> Sono presenti <%=contatore%> foto che soddisfano i criteri di ricerca<br><br> <% rs.AbsolutePage = pagNum for i = 1 to pagSize if not rs.EOF Then %> <li><a href="dettagliofoto.asp?nome=<%=rs("Nome")%>"><%=rs("Titolo")%>, scattata a <%=rs("Luogo")%></a></li> <% rs.movenext Else Exit For End If next %> <br><hr><br> <div align="left"> <% for j = 1 to rs.PageCount %> <a href="<%=request.ServerVariables("PATH_INFO")%>?pag=<%=j%>"><%=j%></a> <% next %> </div> <% rs.close set rs = nothing conn.close set conn = nothing %> </ul> </body> </html> 75/97 LISTATO 2 ELENCOFOTO3.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Le foto di Mario Rossi</title> </head> <body> <h1>Le mie foto preferite</h1> Hai selezionato le foto che parlano di <%=request.QueryString("rfoto")%><br> <% Const adOpenStatic = 3 Const adLockReadOnly = 1 Const adOpenForwardOnly = 0 Dim Dim Dim Dim Dim Dim contatore sql1,sql2 conn, rs pagNum pagSize i,j pagSize = 2 Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/mdb-database/foto2.mdb") sql1 = "SELECT count(nome) AS contatore FROM Foto WHERE Titolo like '%" & request.QueryString("rfoto") & "%'" sql2 = "SELECT * FROM Foto WHERE Titolo like '%" & request.QueryString("rfoto") & "%' ORDER BY Data DESC " Set rs = Server.CreateObject("ADODB.RecordSet") rs.Open sql1, conn, adOpenForwardOnly, adLockReadOnly contatore = rs("contatore") rs.Close() 'Estrae il numero di pagina pagNum = cint(request.QueryString("pag")) If pagNum = 0 Then pagNum = 1 'Imposta la dimensione della pagina (il numero massimo di elementi da far comparire per ogni pagina) rs.PageSize = pagSize rs.Open sql2, conn, adOpenStatic, adLockReadOnly %> 76/97 Sono presenti <%=contatore%> foto che soddisfano i criteri di ricerca<br><br> <% rs.AbsolutePage = pagNum for i = 1 to pagSize if not rs.EOF Then %> <li><a href="dettagliofoto.asp?nome=<%=rs("Nome")%>"><%=rs("Titolo")%>, scattata a <%=rs("Luogo")%></a></li> <% rs.movenext Else Exit For End If next %> <br><hr><br> <div align="left"> <% for j = 1 to rs.PageCount %> <% if j = pagNum then %> <strong><%=j%></strong> <% else %> <a href="<%=request.ServerVariables("PATH_INFO")%>?pag=<%=j%>"><%=j%></a> <% end if %> <% next %> </div> <% rs.close set rs = nothing conn.close set conn = nothing %> </ul> </body> </html> 77/97 LISTATO 3 – ELENCOFOTO4.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Le foto di Mario Rossi</title> </head> <body> <h1>Le mie foto preferite</h1> Hai selezionato le foto che parlano di <%=request.QueryString("rfoto")%><br> <% Const adOpenStatic = 3 Const adLockReadOnly = 1 Const adOpenForwardOnly = 0 Dim Dim Dim Dim Dim Dim contatore sql1,sql2 conn, rs pagNum pagSize i,j pagSize = 2 Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/mdb-database/foto2.mdb") sql1 = "SELECT count(nome) AS contatore FROM Foto WHERE Titolo like '%" & request.QueryString("rfoto") & "%'" sql2 = "SELECT * FROM Foto WHERE Titolo like '%" & request.QueryString("rfoto") & "%' ORDER BY Data DESC " Set rs = Server.CreateObject("ADODB.RecordSet") rs.Open sql1, conn, adOpenForwardOnly, adLockReadOnly contatore = rs("contatore") rs.Close() 'Estrae il numero di pagina pagNum = cint(request.QueryString("pag")) If pagNum = 0 Then pagNum = 1 'Imposta la dimensione della pagina (il numero massimo di elementi da far comparire per ogni pagina) rs.PageSize = pagSize rs.Open sql2, conn, adOpenStatic, adLockReadOnly %> Sono presenti <%=contatore%> foto che soddisfano i criteri di ricerca<br><br> 78/97 <% rs.AbsolutePage = pagNum for i = 1 to pagSize if not rs.EOF Then if i mod 2 = 0 then strColor="#3333CC" else strColor="#FF0033" end if %> <li><a style="color:<%=strColor%>" href="dettagliofoto.asp?nome=<%=rs("Nome")%>"><%=rs("Titolo")%>, scattata a <%=rs("Luogo")%></a></li> <% rs.movenext Else Exit For End If next %> <br><hr><br> <div align="left"> <% If pagNum > 1 Then %> <a href="<%=request.ServerVariables("PATH_INFO")%>?pag=<%=pagNum 1%><%=strTipo%>">&laquo;</a> <% End If %> <% for j = 1 to rs.PageCount %> <% if j = pagNum then %> <strong><%=j%></strong> <% else %> <a href="<%=request.ServerVariables("PATH_INFO")%>?pag=<%=j%><%=strTipo%>"><%=j%></ a> <% end if %> <% next %> <% If pagNum < rs.PageCount Then %> <a href="<%=request.ServerVariables("PATH_INFO")%>?pag=<%=pagNum+1%>">&raquo;</a> <% End If %> </div> 79/97 <% rs.close set rs = nothing conn.close set conn = nothing %> </ul> </body> </html> 80/97 LISTATO 4 GESTIONEINSERISCI.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Gestione foto di Mario Rossi</title> </head> <body> <h1>Gestione foto</h1> <% Const adOpenForwardOnly = 0 Const adLockReadOnly = 1 Dim Dim Dim Dim Dim Dim contatore sql1,sql2 conn, rs pagNum pagSize i,j pagSize = 2 Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/mdb-database/foto2.mdb") sql1 = "SELECT count(nome) AS contatore FROM Foto" sql2 = "SELECT * FROM Foto ORDER BY Data DESC" Set rs = Server.CreateObject("ADODB.RecordSet") rs.Open sql1, conn, adOpenForwardOnly, adLockReadOnly contatore = rs("contatore") rs.Close() 'Estrae il numero di pagina pagNum = cint(request.QueryString("pag")) If pagNum = 0 Then pagNum = 1 'Imposta la dimensione della pagina (il numero massimo di elementi da far comparire per ogni pagina) rs.PageSize = pagSize rs.Open sql2, conn, 3, adLockReadOnly %> Foto presenti nella base di dati: <%=contatore%><br><br> Inserisci una <a href="inseriscifoto.asp">nuova foto</a> <% 81/97 rs.AbsolutePage = pagNum for i = 1 to pagSize if not rs.EOF Then if i mod 2 = 0 then strColor="#3333CC" else strColor="#FF0033" end if %> <li> <a style="color:<%=strColor%>" href="dettagliofoto.asp?nome=<%=rs("Nome")%>"><%=rs("Titolo")%>, scattata a <%=rs("Luogo")%></a> </li> <% rs.movenext Else Exit For End If next %> <br><hr><br> <div align="left"> <% If pagNum > 1 Then %> <a href="<%=request.ServerVariables("PATH_INFO")%>?pag=<%=pagNum 1%><%=strTipo%>">&laquo;</a> <% End If %> <% for j = 1 to rs.PageCount %> <% if j = pagNum then %> <%=j%> <% else %> <a href="<%=request.ServerVariables("PATH_INFO")%>?pag=<%=j%><%=strTipo%>"><%=j%></ a> <% end if %> <% next %> <% If pagNum < rs.PageCount Then %> 82/97 <a href="<%=request.ServerVariables("PATH_INFO")%>?pag=<%=pagNum+1%><%=strTipo%>">& raquo;</a> <% End If %> </div> <% rs.close set rs = nothing conn.close set conn = nothing %> </ul> </body> </html> 83/97 LISTATO 5 INSERISCIFOTO.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Gestione foto di Mario Rossi</title> </head> <body> <h1>Inserimento nuova foto</h1> <% Const adOpenForwardOnly = 0 Const adLockReadOnly = 1 Dim Dim Dim Dim contatore sql1,sql2 conn, rs i,j Set conn = Server.CreateObject("ADODB.Connection") Set rs = Server.CreateObject("ADODB.Recordset") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/mdb-database/foto2.mdb") %> <form action="inseriscifoto_risposta.asp" method="post" cellpadding="2" cellspacing="2"> <table border="0"> <tr> <td>Nome</td> <td><input type="text" size="20" name="nome" maxlenght=""></td> </tr> <tr> <td>Titolo</td> <td><input type="text" size="20" name="titolo" maxlenght=""></td> </tr> <tr> <td>Data</td> <td><input type="text" size="2" name="datagg" maxlenght="2">/<input type="text" size="2" name="datamm" maxlenght="2">/<input type="text" size="4" name="datayyyy" maxlenght="4"></td> </tr> <tr> <td>Luogo</td> <td><input type="text" size="20" name="luogo" maxlenght=""></td> </tr> <tr> <td>Provincia</td> <td> <select name="provincia"> <% 84/97 sql = "SELECT * FROM Provincia ORDER BY Provincia DESC " rs.Open sql, conn, adOpenForwardOnly, adLockReadOnly do until rs.Eof %> <option value="<%=rs("IdProvincia")%>"><%=rs("Provincia")%></option> <% rs.movenext loop rs.Close() %> </select> </td> </tr> <tr> <td>Stato</td> <td> <select name="stato"> <% sql = "SELECT * FROM Stato ORDER BY Stato DESC " rs.Open sql, conn, adOpenForwardOnly, adLockReadOnly do until rs.Eof %> <option value="<%=rs("IdStato")%>"><%=rs("Stato")%></option> <% rs.movenext loop rs.Close() %> </select> </td> </tr> <tr> <td align="right" colspan="2"><input type="submit" name="invia" value="Inserisci"></td> </tr> </table> </form> </body> </html> <% set rs = nothing conn.close set conn = nothing %> 85/97 LISTATO 6 INSERISCIFOTO_RISPOSTA.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Gestione foto di Mario Rossi</title> </head> <body> <h1>Inserimento nuova foto</h1> <% Dim contatore Dim sql Dim strNome, strTitolo, strData, strLuogo, strProvincia, strStato strNome = request.Form("nome") strTitolo = request.Form("titolo") strData = request.Form("datagg") & "/" & request.Form("datamm") & "/" & request.Form("datayyyy") strLuogo = request.Form("luogo") strProvincia = request.Form("provincia") strStato = request.Form("stato") Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/mdb-database/foto2.mdb") sql = "INSERT INTO Foto ( Nome, Titolo, Data, Luogo, IdProvincia, IdStato ) VALUES (" & _ "'" & strNome & "', " & _ "'" & strTitolo & "', " & _ "'" & strData & "', " & _ "'" & strLuogo & "', " & _ "'" & strProvincia & "', " & _ "'" & strStato & "' " & _ ")" response.write sql conn.Execute sql conn.close set conn = nothing %> Foto inserita correttamente 86/97 LISTATO 7 INSERISCIFOTO_RISPOSTA_2.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Gestione foto di Mario Rossi</title> </head> <body> <h1>Inserimento nuova foto</h1> <% Const adOpenForwardOnly = 0 Const adLockReadOnly = 1 Dim Dim Dim Dim contatore sql1,sql2 conn, rs i,j Dim strNome, strTitolo, strData, strLuogo, strProvincia, strStato strNome = request.Form("nome") strTitolo = request.Form("titolo") strData = request.Form("datagg") & "/" & request.Form("datamm") & "/" & request.Form("datayyyy") strLuogo = request.Form("luogo") strProvincia = request.Form("provincia") strStato = request.Form("stato") Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/mdb-database/foto2.mdb") sql = "SELECT count(*) AS totale FROM Foto WHERE nome = '" & request.Form("nome") & "'" Set rs = Server.CreateObject("ADODB.RecordSet") rs.Open sql, conn, adOpenForwardOnly, adLockReadOnly 'Qualche controllo If rs("totale") > 0 Then 'Esiste una foto già inserita con lo stesso ID response.write "Questo nome di foto esiste già nella tabella, devi sceglierne un altro<br>" response.write "Ritorna alla<a href=""inseriscifoto.asp"">pagina di inserimento</a>" response.end End If If Not IsDate(strData) Then 'Data in formato non valido response.write "La data inserita (" & strData & ") non è valida<br>" response.write "Ritorna alla<a href=""inseriscifoto.asp"">pagina di inserimento</a>" 87/97 response.end End If 'Rinforzo l'accento per evitare problemi in inserimento strNome = replace(strNome,"'","''") strTitolo = replace(strTitolo,"'","''") strLuogo = replace(strLuogo,"'","''") sql = "INSERT INTO Foto ( Nome, Titolo, Data, Luogo, IdProvincia, IdStato ) VALUES (" & _ "'" & strNome & "', " & _ "'" & strTitolo & "', " & _ "'" & strData & "', " & _ "'" & strLuogo & "', " & _ "'" & strProvincia & "', " & _ "'" & strStato & "' " & _ ")" on error resume next conn.Execute sql If ConnError(conn) > response.write dati.<br>" response.write inserimento</a>" Else response.write response.write foto</a>" End If 0 Then "Si è verificato un problema con l'inserimento dei "Ritorna alla <a href=""inseriscifoto.asp"">pagina di "I dati della foto sono stati inseriti correttamente<br>" "Ritorna all'<a href=""gestione.asp"">elenco delle on error goto 0 set rs = nothing conn.close set conn = nothing Function ConnError(conn) Dim i i = 0 For Each errorObject In conn.Errors i = i + 1 Response.Write "ERRORE: " & errorObject.Description & "<br><br>" Next ConnError = i End Function %> 88/97 LISTATO 8 GESTIONE_MODIFICA.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Gestione foto di Mario Rossi</title> </head> <body> <h1>Gestione foto</h1> <% Const adOpenForwardOnly = 0 Const adLockReadOnly = 1 Dim Dim Dim Dim Dim Dim contatore sql1,sql2 conn, rs pagNum pagSize i,j pagSize = 2 Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/mdb-database/foto2.mdb") sql1 = "SELECT count(nome) AS contatore FROM Foto" sql2 = "SELECT * FROM Foto ORDER BY Data DESC" Set rs = Server.CreateObject("ADODB.RecordSet") rs.Open sql1, conn, adOpenForwardOnly, adLockReadOnly contatore = rs("contatore") rs.Close() 'Estrae il numero di pagina pagNum = cint(request.QueryString("pag")) If pagNum = 0 Then pagNum = 1 'Imposta la dimensione della pagina (il numero massimo di elementi da far comparire per ogni pagina) rs.PageSize = pagSize rs.Open sql2, conn, 3, adLockReadOnly %> Foto presenti nella base di dati: <%=contatore%><br><br> Inserisci una <a href="inseriscifoto.asp">nuova foto</a> <% 89/97 rs.AbsolutePage = pagNum for i = 1 to pagSize if not rs.EOF Then if i mod 2 = 0 then strColor="#3333CC" else strColor="#FF0033" end if %> <li> <a style="color:<%=strColor%>" href="dettagliofoto.asp?nome=<%=rs("Nome")%>"><%=rs("Titolo")%>, scattata a <%=rs("Luogo")%></a> [<a href="modificafoto.asp?nome=<%=rs("nome")%>">modifica</a>] </li> <% rs.movenext Else Exit For End If next %> <br><hr><br> <div align="left"> <% If pagNum > 1 Then %> <a href="<%=request.ServerVariables("PATH_INFO")%>?pag=<%=pagNum 1%><%=strTipo%>">&laquo;</a> <% End If %> <% for j = 1 to rs.PageCount %> <% if j = pagNum then %> <%=j%> <% else %> <a href="<%=request.ServerVariables("PATH_INFO")%>?pag=<%=j%><%=strTipo%>"><%=j%></ a> <% end if %> <% next %> <% If pagNum < rs.PageCount Then 90/97 %> <a href="<%=request.ServerVariables("PATH_INFO")%>?pag=<%=pagNum+1%><%=strTipo%>">& raquo;</a> <% End If %> </div> <% rs.close set rs = nothing conn.close set conn = nothing %> </ul> </body> </html> 91/97 LISTATO 9 MODIFICAFOTO.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Gestione foto di Mario Rossi</title> </head> <body> <h1>Modifica foto esistente</h1> <% Const adOpenForwardOnly = 0 Const adLockReadOnly = 1 Dim Dim Dim Dim Dim contatore sql conn, rs, rs2 i,j strSuffisso Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/mdb-database/foto2.mdb") sql = "SELECT * FROM Foto WHERE nome = '" & request.QueryString("nome") & "'" Set rs = Server.CreateObject("ADODB.RecordSet") Set rs2 = Server.CreateObject("ADODB.RecordSet") rs.Open sql, conn, adOpenForwardOnly, adLockReadOnly %> <form action="modificafoto_risposta.asp" method="post" cellpadding="2" cellspacing="2"> <table border="0"> <tr> <td>Nome</td> <td><%=rs("nome")%><input type="hidden" name="nome" value="<%=rs("nome")%>"></td> </tr> <tr> <td>Titolo</td> <td><input type="text" size="20" name="titolo" maxlenght="255" value="<%=rs("titolo")%>"></td> </tr> <tr> <td>Data</td> <td><input type="text" size="2" name="datagg" maxlenght="2" value="<%=Day(rs("data"))%>">/ <input type="text" size="2" name="datamm" maxlenght="2" value="<%=Month(rs("data"))%>">/ 92/97 <input type="text" size="4" name="datayyyy" maxlenght="4" value="<%=Year(rs("data"))%>"></td> </tr> <tr> <td>Luogo</td> <td><input type="text" size="20" name="luogo" maxlenght="255" value="<%=rs("luogo")%>"></td> </tr> <tr> <td>Provincia</td> <td> <select name="provincia"> <% sql = "SELECT * FROM Provincia ORDER BY Provincia DESC " rs2.Open sql, conn, adOpenForwardOnly, adLockReadOnly do until rs2.Eof If rs2("IdProvincia") = rs("IdProvincia") Then strSuffisso = " selected" Else strSuffisso = "" End If %> <option value="<%=rs2("IdProvincia")%>"<%=strSuffisso%>><%=rs2("Provincia")%></option> <% rs2.movenext loop rs2.Close() %> </select> </td> </tr> <tr> <td>Stato</td> <td> <select name="stato"> <% sql = "SELECT * FROM Stato ORDER BY Stato DESC " rs2.Open sql, conn, adOpenForwardOnly, adLockReadOnly do until rs2.Eof If rs2("IdStato") = rs("IdStato") Then strSuffisso = " selected" Else strSuffisso = "" End If %> <option value="<%=rs2("IdStato")%>"<%=strSuffisso%>><%=rs2("Stato")%></option> <% rs2.movenext loop rs2.Close() %> </select> 93/97 </td> </tr> <tr> <td align="right" colspan="2"><input type="submit" name="invia" value="Modifica"></td> </tr> </table> </form> </body> </html> <% rs.close set rs = nothing set rs2 = nothing conn.close set conn = nothing %> 94/97 LISTATO 10 MODIFICAFOTO_RISPOSTA.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Gestione foto di Mario Rossi</title> </head> <body> <h1>Modifica di una foto</h1> <% Const adOpenForwardOnly = 0 Const adLockReadOnly = 1 Dim Dim Dim Dim contatore sql1,sql2 conn, rs i,j Dim strNome, strTitolo, strData, strLuogo, strProvincia, strStato strNome = request.Form("nome") strTitolo = request.Form("titolo") strData = request.Form("datagg") & "/" & request.Form("datamm") & "/" & request.Form("datayyyy") strLuogo = request.Form("luogo") strProvincia = request.Form("provincia") strStato = request.Form("stato") Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/mdb-database/foto2.mdb") If Not IsDate(strData) Then 'Data in formato non valido response.write "La data inserita (" & strData & ") non è valida<br>" response.write "Ritorna alla<a href=""gestione.asp"">pagina di gestione</a>" response.end End If 'Rinforzo l'accento per evitare problemi in inserimento strTitolo = replace(strTitolo,"'","''") strLuogo = replace(strLuogo,"'","''") sql = "UPDATE Foto SET " & _ " Foto.Data = '" & strData & "', " & _ " Foto.Titolo = '" & strTitolo & "'," & _ " Foto.Luogo = '" & strLuogo & "', " & _ " Foto.IdProvincia = '" & strProvincia & "', " & _ " Foto.IdStato = '" & strStato & "'" & _ " WHERE Foto.Nome = '" & strNome & "'" on error resume next 95/97 conn.Execute sql If ConnError(conn) > response.write response.write gestione</a>" Else response.write response.write gestione</a>" End If 0 Then "Si è verificato un problema con la modifica dei dati.<br>" "Ritorna alla <a href=""gestione.asp"">pagina di "I dati della foto sono stati modificati correttamente<br>" "Ritorna alla <a href=""gestione.asp"">pagina di on error goto 0 set rs = nothing conn.close set conn = nothing Function ConnError(conn) Dim i i = 0 For Each errorObject In conn.Errors i = i + 1 Response.Write "ERRORE: " & errorObject.Description & "<br><br>" Next ConnError = i End Function %> 96/97 LISTATO 11 ELIMINAFOTO_RISPOSTA.ASP <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Gestione foto di Mario Rossi</title> </head> <body> <h1>Elimina foto</h1> <% Dim sql Dim conn Dim i Set conn = Server.CreateObject("ADODB.Connection") conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" & server.MapPath("/mdb-database/foto2.mdb") sql = "DELETE FROM Foto WHERE nome = '" & request.QueryString("nome") & "'" on error resume next conn.Execute sql If ConnError(conn) > response.write foto.<br>" response.write foto</a>" Else response.write response.write foto</a>" End If 0 Then "Si è verificato un problema con l'eliminazione della "Ritorna all'<a href=""gestione.asp"">elenco delle "La foto è stata eliminata correttamente<br>" "Ritorna all'<a href=""gestione.asp"">elenco delle on error goto 0 set conn = nothing Function ConnError(conn) Dim i i = 0 For Each errorObject In conn.Errors i = i + 1 Response.Write "ERRORE: " & errorObject.Description & "<br><br>" Next ConnError = i End Function %> 97/97