45
1 a lezione C itando testualmente la prefazione del manuale uf- ficiale di PHP.net: “L'obiet- tivo principale del linguaggio PHP è di permettere agli svi- luppatori Web di scrivere velo- cemente pagine Web dinami- che, ma con PHP si possono fa- re molte altre cose. È in questo spirito che PC Open introduce nelle sue pagi- ne questo minicorso di PHP, potente linguaggio di scripting open source, pienamente inte- grabile con HTML (da cui la propedeuticità del corso Web- master, fornito sul CD Guida n. 2 unito a questo numero, utile anche se non necessaria) e in- dirizzato prevalentemente allo sviluppo dei siti Internet dina- mici. PHP viene utilizzato an- che per creare scripting di ri- ghe comando e applicazioni client-side GUI (Graphical User Interface) utilizzando le esten- sioni PHP-GTK. Tralasciando queste due applicazioni spe- cialistiche, vedremo come PHP offra strumenti professionali molto evoluti per la gestione Web, pur mantenendo una struttura semplice, adatta an- che a chi si avvicina per la pri- ma volta a linguaggi di pro- grammazione di questo tipo. Alla fine di questo minicorso avremo gli strumenti di base per migliorare i nostri siti e per affrontare una delle più impor- tanti funzionalità di PHP, ossia l'integrazione con i database e in particolare con MySQL. La storia del linguaggio PHP PHP è un acronimo ricorsivo (tipico dell'ambiente open source) che significa PHP: Hy- pertext Preprocessor. Che cosa sia un ipertesto è chiaro, men- tre può lasciare perplessi il si- gnificato di Preprocessor: PHP, come ASP, è un linguaggio ser- ver-side, ossia il codice PHP è prima elaborato dal server e solo dopo indirizzato al brow- ser che ha chiamato la pagina. In tal senso PHP elabora la pa- gina “prima” della sua visualiz- zazione. È una caratteristica total- mente diversa rispetto a lin- guaggi come Javascript che in- vece sono client-side, ossia in- teramente interpretati dai browser. Vedremo in seguito come questa caratteristica ser- ver-side consenta l'implemen- tazione di strutture e funziona- lità assolutamente inedite per chi è abituato a ragionare in termini di HTML puro. PHP consente, inoltre, di creare immagini, file PDF, fil- mati Flash, generare file basati su XML, utilizzare i protocolli di posta POP3 e IMAP (ne ve- dremo un'applicazione nella seconda parte del corso), com- primere file in gzip e bz2, gesti- re sessioni, utilizzare funzioni e classi, fare uso della program- mazione orientata agli oggetti e naturalmente interagire con tutti i database più diffusi. Per alcune di queste funzioni biso- gna installare estensioni forni- te con il file binario di PHP e quindi si dovrà verificare pres- so il proprio Web provider l'in- stallazione delle specifiche li- brerie (ad esempio quelle gra- fiche). PHP ha ormai quasi 10 anni di storia alle spalle (è stato creato nel 1994 da Rasmus Ler- dorf e la prima distribuzione ri- sale al 1995; sito di riferimento: www.php.net), sposa appieno la filosofia open source ed è di- stribuito con licenza GPL. È un linguaggio multipiattaforma, utilizzabile indifferentemente su macchine client con sistemi operativi Windows, Linux, BSD o Mac e interfacciabile con tut- ti i più popolari Web server. Utilizzare PHP off line e scrivere i primi listati I listati in PHP possono esse- re creati utilizzando un qualsia- si editor di testo e salvando le pagine con estensione .php. Proviamo a scrivere il nostro primo semplice listato (la parte PHP è in grassetto. Più avanti ne approfondiremo il significa- to), salviamolo col nome ph- pinfo.php (listato1) e poi visua- lizziamolo col nostro browser: LISTATO 1 (phpinfo.php) <html> <head> <title>Prova PHP</title> </head> <body> <?php phpinfo(); ?> </body> </html> Lezione 1: - La scelta di PHP - PHP con un server off line - La prima pagina PHP: inseriamo PHP in HTML - Funzioni base e variabili - I costrutti di controllo: if else, while, do until, foreach - I form: passaggio di dati coi metodi GET e POST - Esempi Le prossime puntate Lezione 2: Approfondiamo PHP Lezione 3: PHP e i database Lezione 4: PHP e MySql Lezione 5: Gestire un sito dinamico con PHP e MySql IL CALENDARIO DELLE LEZIONI di Federico Pozzato A scuola con PC Open W eb D eveloper PHP 1 La scelta di PHP La pagina phpinfo.php è la prima pagina di questo corso realizzata in PHP 1 I listati completi sono sul CD

Corso di Php (fonte: PC OPEN)

  • Upload
    theoan

  • View
    3.474

  • Download
    9

Embed Size (px)

Citation preview

Page 1: Corso di Php (fonte: PC OPEN)

1a lezione

Citando testualmente laprefazione del manuale uf-ficiale di PHP.net: “L'obiet-

tivo principale del linguaggioPHP è di permettere agli svi-luppatori Web di scrivere velo-cemente pagine Web dinami-che, ma con PHP si possono fa-re molte altre cose”.

È in questo spirito che PCOpen introduce nelle sue pagi-ne questo minicorso di PHP,potente linguaggio di scriptingopen source, pienamente inte-grabile con HTML (da cui lapropedeuticità del corso Web-master, fornito sul CD Guida n.2 unito a questo numero, utileanche se non necessaria) e in-dirizzato prevalentemente allosviluppo dei siti Internet dina-mici. PHP viene utilizzato an-che per creare scripting di ri-ghe comando e applicazioniclient-side GUI (Graphical UserInterface) utilizzando le esten-sioni PHP-GTK. Tralasciandoqueste due applicazioni spe-cialistiche, vedremo come PHPoffra strumenti professionalimolto evoluti per la gestioneWeb, pur mantenendo unastruttura semplice, adatta an-che a chi si avvicina per la pri-ma volta a linguaggi di pro-grammazione di questo tipo.

Alla fine di questo minicorso

avremo gli strumenti di baseper migliorare i nostri siti e peraffrontare una delle più impor-tanti funzionalità di PHP, ossial'integrazione con i database ein particolare con MySQL.

La storiadel linguaggio PHP

PHP è un acronimo ricorsivo(tipico dell'ambiente opensource) che significa PHP: Hy-pertext Preprocessor. Che cosasia un ipertesto è chiaro, men-tre può lasciare perplessi il si-gnificato di Preprocessor: PHP,come ASP, è un linguaggio ser-ver-side, ossia il codice PHP èprima elaborato dal server esolo dopo indirizzato al brow-ser che ha chiamato la pagina.In tal senso PHP elabora la pa-gina “prima” della sua visualiz-zazione.

È una caratteristica total-mente diversa rispetto a lin-guaggi come Javascript che in-vece sono client-side, ossia in-teramente interpretati daibrowser. Vedremo in seguitocome questa caratteristica ser-ver-side consenta l'implemen-tazione di strutture e funziona-lità assolutamente inedite perchi è abituato a ragionare intermini di HTML puro.

PHP consente, inoltre, di

creare immagini, file PDF, fil-mati Flash, generare file basatisu XML, utilizzare i protocollidi posta POP3 e IMAP (ne ve-dremo un'applicazione nellaseconda parte del corso), com-primere file in gzip e bz2, gesti-re sessioni, utilizzare funzioni eclassi, fare uso della program-mazione orientata agli oggetti enaturalmente interagire contutti i database più diffusi. Peralcune di queste funzioni biso-gna installare estensioni forni-te con il file binario di PHP equindi si dovrà verificare pres-so il proprio Web provider l'in-stallazione delle specifiche li-brerie (ad esempio quelle gra-fiche).

PHP ha ormai quasi 10 annidi storia alle spalle (è statocreato nel 1994 da Rasmus Ler-dorf e la prima distribuzione ri-sale al 1995; sito di riferimento:www.php.net), sposa appienola filosofia open source ed è di-stribuito con licenza GPL. È unlinguaggio multipiattaforma,utilizzabile indifferentemente

su macchine client con sistemioperativi Windows, Linux, BSDo Mac e interfacciabile con tut-ti i più popolari Web server.

Utilizzare PHP off line e scrivere i primi listati

I listati in PHP possono esse-re creati utilizzando un qualsia-si editor di testo e salvando lepagine con estensione .php.Proviamo a scrivere il nostroprimo semplice listato (la partePHP è in grassetto. Più avantine approfondiremo il significa-to), salviamolo col nome ph-pinfo.php (listato1) e poi visua-lizziamolo col nostro browser:

LISTATO 1 (phpinfo.php)<html>

<head><title>Prova PHP</title>

</head><body>

<?phpphpinfo();

?></body>

</html>

Lezione 1:- La scelta di PHP- PHP con un server off line- La prima pagina PHP:inseriamo PHP in HTML

- Funzioni base e variabili- I costrutti di controllo: if else, while, do until, foreach

- I form: passaggio di dati coi metodi

GET e POST- Esempi

Le prossime puntateLezione 2: ApprofondiamoPHPLezione 3: PHP e i databaseLezione 4: PHP e MySqlLezione 5: Gestire un sitodinamico con PHP e MySql

IL CALENDARIO DELLE LEZIONI

di Federico Pozzato

� A scuola con PC Open

WebDeveloper PHP1 La scelta di PHP

La pagina phpinfo.php è la prima pagina di questo corso realizzata in PHP

1 I listaticompleti

sono sul CD

Page 2: Corso di Php (fonte: PC OPEN)

1a lezione

Sul vostro browser vedrete ouna pagina totalmente vuotaoppure il listato esattamentecome è scritto qui sopra. Cos'èsuccesso? Abbiamo affermatoche PHP è un linguaggio ser-ver-side, quindi per visualizza-re le pagine create abbiamo bi-sogno di tre strumenti: un ser-ver Web, il supporto PHP (ilparser, gli elementi di una fraseo di un’istruzione) attivato daparte del server scelto e unbrowser.

Nel nostro esempio ci siamoserviti solamente del browserche, da solo, non è in grado diinterpretare la pagina PHP e lafa vedere come fosse un nor-male documento HTML (quin-di, in questo caso, apparente-mente vuoto) oppure come unfile testo. Nel primo caso la pa-gina sembra vuota, ma se an-diamo a vedere il codice sor-gente (ogni browser consentedi farlo selezionando l'appositavoce presente nei menu) ve-dremo il listato 1. Per vedere in-vece la pagina PHP interpretatanella maniera esatta, avremmodovuto per prima cosa caricarela pagina phpinfo.php su un ser-ver Web (abilitato per la tradu-zione delle pagine PHP) e poirichiamare la pagina col brow-ser (vedi disegno a fondo pagi-na). Avremmo ottenuto quantovisibile nell'immagine 1: la no-stra prima pagina ci restituiscetutte le caratteristiche dellaversione PHP installata sul ser-ver Web.

Per la maggior parte dellepersone è certamente impro-ponibile pensare di poter im-parare a programmare in PHPrestando connessi a Internet,vuoi a causa dei costi, vuoi perla scomodità di dover ogni vol-ta caricare le proprie paginevia FTP (o con upload dedicati)per poi richiamarle tramitebrowser (vedi disegno A ).

Risulta quindi necessario in-stallare un server sul proprioPC, col supporto alle paginePHP per le operazioni di par-sing. L'installazione di un ser-ver sul proprio PC è già statadescritta nella 7a lezione delcorso Webmaster e la si dà peracquisita (l'installazione delserver Web va fatta prima diPHP). Vediamo adesso comeinstallare il parser, con indica-zioni riguardanti tre server:Apache, Xitami e IIS di Micro-soft.

La prima regola fondamen-tale è scaricare l'ultima release

stabile di PHP per il proprio si-stema direttamente dal sito uf-ficiale: www.php.net.

Al momento in cui scrivia-mo, la release stabile è una4.3.x, in attesa del sospirato ri-lascio della release 5. Trala-sciamo l'installazione di PHPsu Linux, in quanto è un'opera-zione generalmente eseguita inautomatico scegliendo gli op-portuni pacchetti della propriadistribuzione, e dedichiamociall'ambiente Windows. Nell'a-rea download di www.php.netsi trovano due file utilizzabilicon sistemi Windows:• un file installer (come: php-

4.3.7-installer.exe). Questo fileha dimensioni minime (circa1 MB), è direttamente esegui-bile nel sistema e configuraautomaticamente i server IISe Xitami, consentendo l'in-stallazione come versioneCGI per il server Apache. L'in-staller non comprende leestensioni di PHP.

• un file zippato contenente ilcodice binario (come: php-4.3.7-Win32.zip). Questo fileha dimensioni ben più consi-stenti (circa 7 MB), ma con-sente l'installazione (manua-le) di tutti i moduli.

Il server ApacheCome ASP richiamava il ser-

ver IIS, così PHP richiama ilserver Apache. Tuttavia, nonesiste al momento una proce-dura automatica per configura-re il server Apache, sia esso1.3.x o 2.0.x (supporto piena-mente abilitato solo con unaversione di PHP oltre la 4.3.1).

Si può procedere in due mo-di, configurando PHP in versio-ne CGI (installazione più sem-plice) o come modulo (installa-zione consigliata per motivi disicurezza).

Nel primo caso utilizziamo ilfile Installer. Eseguiamolo (ri-cordandoci la cartella dovePHP verrà installato: C:\PHP vabenissimo, ma potete cambiar-la a piacere) e arriviamo al ter-mine dell'installazione (anchescegliendo l'opzione di confi-gurazione automatica di Apa-che, il software vi risponderàche questa procedura non èancora applicabile). Ora dove-te editare il file httpd.conf delserver Apache (Start > Pro-grammi > Apache > Configure >Edit the httpd.conf configurationfile) e, dopo esservi posiziona-ti nella sezione ScriptAlias, ag-giungete le seguenti righe:

ScriptAlias /php/ "c:/php/"AddType application/x-httpd-php .phpAction application/x-httpd-php"/php/php.exe"

sostituendo a c:\php la car-tella di installazione. PHP vieneinstallato nella versione CGI:fate ripartire il server Apache epoi verificate se la pagina ph-pinfo.php viene visualizzatanella maniera corretta.

Questo tipo di installazioneè giudicato non sicuro e menoperformante dell'installazionedi PHP come modulo, però dalmomento che ce ne serviamosolo per scopi didattici (esclu-sivamente off line) va comun-que bene per i nostri scopi.Non è possibile, però, installa-re alcuna estensione.

Il secondo metodo richiedeil file zip binario. Per prima co-sa si deve scompattare il file inuna cartella tipo c:\php, quindicopiare il file php.ini-dist nella%SYSTEMROOT% (per Win-dows 2000 è C:\WINNT) modifi-candone il nome in php.ini. Al-tra operazione da compiere ècopiare il file php4ts.dll nellacartella c:\php\sapi. Ultimisforzi: editare il file httpd.confdel server Apache (Start > Pro-grammi > Apache > Configure >Edit the httpd.conf configurationfile) e, dopo essersi posiziona-ti nella sezione LoadModule, ag-giungere le seguenti righe (perApache 2.0.x):

LoadModule php4_modulec:/php/sapi/php4apache2.dll [ophp4apache.dll per Apache 1.3.x]AddType application/x-httpd-php .php

Facciamo le necessarie veri-fiche, dopodiché siamo prontiper iniziare.

IIS, PWS e Xitami Con IIS, PWS e Xitami la vita è

più semplice rispetto ad Apa-che, sempre che ci si acconten-ti dell'installazione minima (ge-neralmente sufficiente per i no-stri scopi).

In questo caso si deve soloeseguire l'installer PHP: duran-te la procedura di installazioneci verrà chiesto se è presenteun server da configurare conPHP. Scegliete IIS o Xitami e at-tendete la conclusione dell'in-stall shield: da adesso saremoin grado di verificare off line lenostre pagine PHP. Per verifica-re il funzionamento, fate partireil server, provate a inserire nel-la cartella scelta come root deidocumenti il file phpinfo.php erichiamatelo col browser: do-vete ottenere l'immagine 1 dellapagina a lato.

L'installazione delle esten-sioni implica l'utilizzo del filezip binario e qualche passo“manuale” aggiuntivo. Non latrattiamo in questa sede, ma ècomunque presente il file in-stall.txt che vi assiste passo pas-so.

EstensioniPer utilizzare le estensioni

si deve effettuare l'installazionedel parser PHP tramite il file zipbinario. Andrà poi modificato ilfile php.ini (dalla %SYSTEM-ROOT%) inserendo l'indicazio-ne C:\php\extensions dopo l'u-guale nella riga che inizia conextension_dir =. Fatto questo,sempre nel file php.ini, cercarela sezione Windows extensionse togliere il punto e virgola da-vanti alle estensioni da abilita-re (ad esempio, per utilizzare lefunzioni PDF bisogna abilitarel'estensione php_pdf.dll).

BROWSERUTENTE

I N T E R N E T

ServerWEB

PAGINASORGENTE

PHPParserPHP

1 Caricamento paginasul server (via FTP)

2 Richiesta pagina da parte del browser

3 Il server, ricevuta la richiesta, chiede al parser di interpretare la pagina sorgente

4 Il parserPHPrestituisceal server la paginainterpretata

5 Il serverrestituisce albrowser la paginainterpretata dalparser (NON vienerestituita la paginasorgente in PHP)

Schema per lavisualizzazionedi pagine PHP

Page 3: Corso di Php (fonte: PC OPEN)

1a lezione

3 Tipi di dato, variabili e operatori

La prima pagina PHP, inrealtà, l'abbiamo già realiz-zata (la solita phpinfo.php)

e la possiamo quindi analizza-re. La parte iniziale e la parte fi-nale comprendono solo tag econtenuti HTML, mentre la “se-zione” PHP, quella interpretatadal parser tramite il server e re-stituita poi al client browser,viene chiaramente identificatadai tag <?php (inizio sezionePHP) e ?> (fine sezione PHP).Questi tag possono essere

aperti e chiusi quante volte sivuole in un listato HTML: ai finidell'efficienza nell'elaborazio-ne della pagina, infatti, è megliouscire dalla modalità PHP se sidevono passare blocchi di con-tenuti HTML “puri” (vale spe-cialmente per pagine compli-cate).

Tutto quello che si trovacompreso tra i tag PHP vienequindi interpretato dal server erestituito al browser per la vi-sualizzazione: la funzione ph-pinfo(), infatti, restituisce tuttele caratteristiche settate per ilparser PHP installato nel ser-ver. Può essere curioso esami-nare il sorgente di questa pagi-na: sono tutti contenuti HTMLe della funzione phpinfo(), giu-

stamente, non c'è alcuna trac-cia.

Notate il “;” al termine dellariga compresa nei tag: tutte leistruzioni PHP terminano conquesto segnale di fine riga. Iltag di chiusura ?> fa anche da“;” e quindi per l'ultima istru-zione prima della chiusura sipotrebbe anche eliminare il “;”,però è certamente meglio nonprendere certe abitudini e usa-re tutta la sintassi normalmen-te richiesta.

Un secondo esempio, hel-lo.php, ci consente di introdur-re la funzione echo che ha loscopo di restituire un output(listato 2 - hello.php):

LISTATO 2 (hello.php)<?php

echo “ciao PC OPEN”;?>

La funzione print() produceesattamente lo stesso output.

È possibile anche introdurredei tag HTML all'interno dellasezione PHP come si può vede-re da hello-html.php (listato 3).Andranno inseriti all'interno diecho in quanto questi tagHTML devono diventare un

output del parser:

LISTATO 3<?php

echo “<h1>Ciao PC OPEN</h1>”;?>

Per indicare inizio e fine della sezione PHP

Ci sono altri sistemi per in-dicare l'inizio e la fine della se-zione PHP:

• tag brevi (short tag): basta indicare <? e ?>. Per

usarli deve essere apposita-mente configurato il parserPHP del server Web ospitante.Generalmente è così, ma l'usodi questi short tag è comunquesconsigliato per motivi di sicu-rezza: se, per qualunque moti-vo (manutenzione, aggiorna-mento, e così via), il parser noninterpretasse più in manieracorretta gli short tag, il vostrocodice diverrebbe visibile atutti (come nell'esempio vistoall'inizio).

• indicazione di script:<script language="php"> e</script>. Non è sempre inter-pretato correttamente quindievitiamolo.

• ASP tag: i tag sono gli stes-si usati per ASP: <% e %>. An-

che in questo caso deve essereattivata un'apposita opzionedel parser (asp_tags = On), congli stessi problemi di sicurezzagià indicati per gli short tag.

In tag.php trovate riuniti in-sieme questi ultimi tre modi diindicare il codice PHP (vedi li-stato 4).

Per buona regola, è semprebene utilizzare <?php e cercaredi essere il più ordinati possi-bile, nell'eventualità di doverfare delle modifiche a distanzadi tempo.

Per inserire dei commenti sipremettono al commento ledoppie slash //.

2 La prima pagina in PHP

Curiosità

In un'ottica di filosofia opensource si sente nominarel'acronimo LAMP. Essoindica un gruppo di prodotti divenuti, nel loroinsieme, un riferimento per lo sviluppo di siti Web:

LinuxApacheMySQLPHP

Per iniziare realmente a usa-re PHP e scoprirne le ca-ratteristiche, abbiamo bi-

sogno di spendere ancora qual-che minuto per introdurre lagestione delle variabili.

Diversamente da ASP, conPHP non serve dichiarare espli-citamente le variabili indican-do nome e tipo, ma, più sem-plicemente, basta assegnare al-la variabile il suo valore: sarà ilparser ad attribuire alla varia-bile il giusto “tipo” (dichiara-zione implicita). Tutte le varia-bili vanno indicate col simbolo$ davanti al nome scelto (il pri-mo digit dopo $ non deve maiessere un numero).

Tipi di variabili scalariVediamo i quattro tipi di va-

riabile scalare che abbiamo adisposizione:

$prova1 = 12; // $prova1 è un tipo di dato intero(integer),

in questo esempio è un inte-ro a base decimale, ma avrem-mo potuto fare una dichiara-zione con le notazioni esadeci-male o ottale. In caso di supe-ramento del limite massimoprevisto per un intero, PHP as-segna automaticamente alla va-riabile il tipo float.

$prova2 = 1,23; // $prova2 è un tipo di dato a virgola mobile (float).

$prova3 = TRUE; // $prova3 è un tipo di dato

booleano (boolean),ossia assume solo valori ve-

ro (true) o falso (false). Il nu-mero 0 o una stringa vuota cor-rispondono al valore boolenofalse; un numero diverso da 0 ouna stringa non vuota corri-spondono al valore booleanotrue.

$prova4 = “pippo”;// $prova4 è un tipo di datostringa (string).

La stringa può essere defini-ta utilizzando le virgolette sin-gole ' (single quotes) o le virgo-lette doppie “ (double quotes).Nel proseguimento del corso siuserà la seconda notazione chepermette, tra le altre cose, diinserire dei nomi di variabili al-l'interno della dichiarazione

$1prova = 1;// il nome della variabile non è valido (numero dopo $)

Ridichiarando le variabili, oconcatenandole, PHP scegliesempre automaticamente il ti-po di dato da gestire. Se voles-simo sapere, ad esempio permotivi di debug, quale sia il ti-po di dato di una certa variabi-le, si può usare la funzionegettype:

<?php$prova = 1,2;echo gettype ($prova); // si ottiene a video il tipo di dato: float

?>

Il tipo può essere impostomediante l'istruzione settypeall'atto già della dichiarazione

Page 4: Corso di Php (fonte: PC OPEN)

1a lezione

(esplicita) della variabile o at-traverso l'imposizione (ca-sting) del tipo (boolean, int,float, string, array, object, null):

<?phpsetype ($prova, “int”);$prova = 1,2;echo $prova; // si ottiene a video il valore del tipo “int”: 1

?>

<?php$prova = 1,2;$intero = (int) $prova;echo $intero; // si ottiene a video il valore del tipo “int”: 1

?>

Variabili di tipo compostoOltre alle variabili di tipo

scalare, ci sono due variabili ditipo composto: array e object.

Array non è solo il classicovettore (ossia una lista di ele-menti individuati da un indicenumerico avente numero ini-ziale 0), ma può essere ancheuna tabella di hash (una map-pa), dove un elemento è indivi-duato da una chiave non ne-cessariamente numerica. Ciòlascia estrema libertà di utiliz-zo del tipo array, ma imponeanche di prestare attenzionequando viene richiamato unvalore. Le chiavi possono esse-re valori sia numerici, sia di ti-po stringa; gli elementi dell'ar-ray possono essere di qualun-que tipo (anche altri array).

Se vogliamo creare un vetto-re, lo possiamo fare in manieraesplicita (indico la parola chia-ve array) o implicita (assegno ivalori alla variabile che sarà ilvettore):

$vettore_a = array (2, 5, 7, 9, 11);// dichiarazione esplicita con elementisolo numerici

$vettore_b = array (2, “pippo”, true,1.24, array (1,2,3)); // dichiarazioneesplicita con elementi misti

$vettore_c = array (0 => 2, 1 =>“pippo”, 2 => true); // notazione perindicare le chiavi del vettore (potevanoessere omesse senza problemi)

$vettore_d[0] = 2; // dichiarazioneimplicita del primo elemento delvettore_d

$vettore_d [1] = “pippo”; // dichiarazione implicita del secondoelemento del vettore_d

Per visualizzare un array e lesue chiavi usiamo la funzioneprint_r, come indicato nell'e-sempio vettore.php (listato 5).Dagli esempi qui sopra ottenia-mo coppie che sono sempre

identificate da un numero. Perfare riferimento a un elementospecifico (per stamparlo, mo-dificarlo e così via) si usa il co-strutto:

$array[n]con n valore intero che parte da 0.

Creare un array come tabelladi hash è altrettanto semplice eversatile, ma in questo caso cidovremo preoccupare di indi-care anche il valore (sia essoun numero o una stringa) daassegnare alla chiave dell'ele-mento dell'array:

$hash_a = array (“italia” => ”roma”, “francia” => ”parigi”, “spagna” =>”madrid”, 12 => “pippo”);

$hash_b[“italia”] = “roma”;$hash_b [“francia”] = “parigi”;$hash_b[12] = “pippo”;

La stampa dell'hash la pos-siamo vedere nell'esempio ha-sh.php (listato_06). Per elimina-re, modificare, stampare i datidell'hash vi faremo riferimentocon i due costrutti (diversi aseconda del tipo di chiave):

$array[numero]$array[“chiave”] // o: $array['chiave']

Si rivelerà utile questa pos-sibilità che ci concede PHP: do-po aver dichiarato un array ha-sh_a, possiamo inserire gli ele-menti anche senza fare riferi-mento a una chiave specifica:

$hash_a[ ] = “topolino”;

In questo caso la chiave del-l'elemento sarà il numero inte-ro successivo al numero interopiù alto già presente nell'hash.Pertanto, come mostrato dal-l'array hash_b dell'esempio ha-sh-due.php (listato 7), possia-mo creare facilmente un arrayassegnando come chiave ini-ziale un numero diverso da 0.Vedremo come questo possaessere utile quando parleremodi date.

Il tipo di dato object lo ana-lizzeremo nel prosieguo delcorso parlando delle classi.

Tipi di variabili specialiPer finire l'analisi, vi sono

ancora due tipi speciali di va-riabili: resource e null. Il primoè creato e usato da una serie difunzioni ben definite (per ap-profondimenti vedere le ap-pendici del manuale PHP),mentre il secondo serve ad as-

segnare a una variabile lo spe-ciale valore NULL.

Nell'ambito delle variabili,oltre a quelle definite da noitroviamo le cosiddette variabi-li superglobals, arrays conte-nenti informazioni sul Web ser-ver, sull'ambiente di utilizzo esugli input degli utenti. Alcuniesempi si possono vedere (coirelativi valori) aprendo la no-stra prima pagina creata (ph-pinfo.php), e altri li vedremo in-troducendo i form e le sessioni.Quasi tutti questi array super-globali iniziano con un under-score: $_POST, $_GET, $_SES-SION, S_SERVER.

OperatoriGli operatori consentono di

eseguire operazioni sulle varia-bili, operazioni non solo di na-tura numerica (esempio: cal-coli aritmetici) e testuale(esempio: concatenazione), maanche operazioni di controllo(esempio: logica binaria) e con-fronto (esempio: confronto divalori e tipi).

La concatenazione è senzadubbio una delle operazionipiù usate: le variabili in PHPpossono essere concatenateusando il segno “.”:

<?php$a = “PC OPEN”;$b = “una rivista di informatica”;$c = $a.”, “.$b;echo $c; // si ottiene come output:

PCOPEN, una rivista di informatica?>

Notate l'inserimento, tra vir-golette doppie, della virgola edello spazio vuoto per megliovisualizzare a video le due va-riabili.

Lo stesso risultato lo si sa-rebbe ottenuto utilizzando op-portunamente la funzione echo(senza però utilizzare la varia-bile $c):

echo ”$a, $b”; // equivalente a: echo$a.”, “.$b;

Si può anche “concatenare”una stringa con se stessa conquesta sintassi abbreviata:

<?php$a = “PCOPEN “;$a. = ”amico” // equivale a: $a =

$a.”amico”;echo $a; // si ottiene a video: PC

OPEN amico?>

Vi sono poi operatori arit-

metici, logici e di confronto.Per comodità sono stati rias-sunti nel riquadro della paginasuccessiva, indicando solo glioperatori che verranno utiliz-zati nel corso; per tutti gli altrioperatori (e per la loro prio-rità) fare riferimento al manua-le di PHP.net.

CostantiPer alcune esigenze potrem-

mo avere bisogno di definiredelle costanti e non delle varia-bili. In questo caso il costruttoda usare è:

define (“nome”, valore);echo nome;

Valore può essere solo di ti-po scalare; nome non è prece-duto dal simbolo $ ed è casesensitive.

Applicazione:immagine random

Vediamo finalmente unesempio pratico di quanto ab-biamo imparato: immaginiamodi avere inserito in una certacartella del nostro spazio Webuna serie di immagini contenu-te nella directory Immagini eaventi nome vacanza_x.jpg do-ve x è un numero intero pro-gressivo che parte dal valore 1.

Sulla nostra home page è vi-sualizzata una di queste imma-gini, ma noi vorremmo, perrendere il sito più attraente efarlo sembrare sempre diversoe aggiornato, fare apparireun'immagine diversa ogni voltache l'home page viene richiesta(o quando viene fatto il refre-sh). La situazione di partenza èvisibile nella pagina intro.html(listato 8) che mostra l'immagi-ne (un quadrato colorato) va-canza_1.jpg al centro della pa-gina.

Dovremo fare in modo che ilvalore x sia generato in manie-ra random a ogni chiamata del-la home page. Utilizzeremo atale scopo la funzionerand(y,z) di PHP, supponendodi avere cinque immagini nelserver Web. Il risultato è visibi-le aprendo la paginarandom.php (listato 9): la parteche ci interessa, quella che ge-nera il numero casuale com-preso tra 1 e 5 e che visualizzal'immagine è la seguente:

<?php$num=rand(1,5);// rand(min,max) genera un numero

casuale intero compreso tra min e max �

Page 5: Corso di Php (fonte: PC OPEN)

inclusiecho "<img src='immagini/vacanza_".$num.".jpg'>"; //

gli attributi HTML vanno indicati usandogli apici singoli e non le virgolette?>

Riprenderemo l'esempio,per approfondirlo e migliorar-lo, dopo aver introdotto il co-strutto while.

Le dateCome avrete notato, PHP

non propone nessun tipo di va-riabile date o time, ma moltoprobabilmente avremo spessobisogno di utilizzare questi for-mati data e tempo.

A tale scopo useremo le fun-zioni di data e ora previste daPHP. La principale è senza dub-bio

date (formato, timestamp);

in grado di restituire tutti ipossibili valori in termini di da-ta e tempo estraendoli da unotimestamp. Il timestamp, natonel modo UNIX, rappresenta ilnumero di secondi trascorsidal 1/1/1970 (la cosiddettaUnix Epoch) ed è valido fino al2037 (va bene, quindi, per lenostre esigenze attuali). Se nonindichiamo il timestamp, dateconsidererà giorno e ora diquel preciso momento del ser-ver Web ospitante PHP. Se vo-lete inserire un vostro time-stamp, dovete usare la funzio-ne mktime() con questa moda-lità:

mktime (ora, minuti, secondi, mese,giorno, anno, ora_legale) // ora_legale(valore -1 o 0) può essere omesso:PHP cercherà di ricavare il valore dalsistema

Date fornisce una lunga listadi formati tra cui scegliere, co-me:

$timestamp = mktime (12, 0, 0, 2,11, 2004); // timestamp del12/02/2004, ore 12.00

echo date (“d-m-y”, $timestamp);// a video: 11-02-04

echo date (“D d, F Y”, $timestamp);// a video: Wed 11, February 2004

echo date (“H:i:s”, $timestamp);// a video: 12:00:00

echo date (“w, z”, $timestamp);// a video: 3 (giorno della settimana),41 (giorno dell'anno)

Può essere interessante an-che studiare la funzione getda-

te, la quale inizializza un arraycon tutti i valori estratti da unotimestamp specificato.

Esempi di utilizzo di date in PHP

Trattare con le date non èsemplice, ma può essere moltoutile saperlo fare. Ecco quindidue esempi per fare un po' dipratica.

Oggi.php (listato 10): serve aesprimere la data odierna uti-lizzando i nomi estesi dei gior-ni e dei mesi, in italiano. La fun-zione date non è sufficienteperché estrae sì questi dati, main lingua inglese. Si potrebbeusare setlocale e strftime, mapreferiamo usare un altro si-stema che ci consente anche siutilizzare gli array. Date ci con-sente di estrarre il valore nu-merico (senza zeri) sia del gior-no della settimana (0=domeni-ca) che del mese, quindi perprima cosa creiamo due array(quello dei mesi ha il primo nu-mero della chiave corrispon-dente a 1) e poi il gioco è fatto:

<?php$giorno = array ("domenica",

"lunedì", "martedì", "mercoledì","giovedì", "venerdì", "sabato");

$mese = array (1 => "gennaio","febbraio", "marzo", "aprile","maggio", "giugno", "luglio", "agosto", "settembre", "ottobre","novembre", "dicembre");

$giorno_mese = date ("d");$anno = date ("y");$mese_nome = $mese[date("n")];

// restituisce il nome del mese$giorno_nome = $giorno[date("w")];

// restituisce il nome del giorno dellasettimana

echo "Ciao, oggi è $giorno_nome $giorno_mese $mese_nome $anno";

?>

counter.php (listato 11): ser-ve a organizzare un elementoche funga da contatore per in-dicare, ad esempio, quanti gior-ni mancano a una data partico-lare. Per prima cosa dovremoricavare il timestamp della dataodierna (in un orario x) e delladata da raggiungere (sempreallo stesso orario x. Qui pren-diamo come riferimento il 31dicembre del 2004). Facendola differenza tra questi time-stamp otterremo il numero disecondi che separa le due date,quindi dividendo per il numerodi secondi di un giorno(60*60*24 = 86.400 secondi)avremo il numero di giorni che

ci separano dal nostro riferi-mento. I dettagli sono com-mentati nel listato:<?php

$inizio = mktime(12,0,0,date(“n”),date(“j”), date(“Y”), 0);

$fine = mktime (12,0,0,12,31,2004,0);

$diff=($fine-$inizio)/86400;echo "Alla fine del 2004 mancano

$diff giorni";?>

1a lezione

Operatori aritmeticiPoniamo: $a=5 e $b=3

$c=$a+$b; // somma: $c=8$c=$a-$b; // sottrazione: $c=2$c=$a*$b; // moltiplicazione: $c=15$c=$a/$b; // divisione: $c=1,66$c=$a%$b; // modulo: $c=2

Pur non essendo un operatore va ricordato anche:

$c=int($a/$b); // quoziente intero della divisione: $c=1

Utilizzeremo anche gli operatori di incremento e decremento:

$c=++$a; // $c=6 (pre-incremento) e $a=6$c=--$a; // $c=4 (pre-decremento) e $a=4$c=$a++; // $c=5 (post-incremento) e $a=6$c=$a--; // $c=5 (post-decremento) e $a=4

Operatori logiciPoniamo: $a=true e $b=false

$c=$a and $b; // AND: $c=false$c=$a or $b; // OR: $c=true$c=! $a; // NOT: $c=false

Operatori di confrontoUseremo questi operatori coi costrutti di controllo.

$a == $b; // true se $a uguale a $b

NB: l'operatore == effettua un controllo di confronto senzamodificare il valori di $a e $b, mentre l'operatore = effettuaun'assegnazione di valore.

$a <> $b; // true se $a diverso da $b$a < $b; // true se $a minore di $b$a > $b; // true se $a maggiore di $b$a <= $b; // true se $a minore o uguale a $b$a >= $b; // true se $a maggiore o uguale a $b

Page 6: Corso di Php (fonte: PC OPEN)

Per interagire con chi acce-de alle nostre pagine ab-biamo a disposizione, tra-

mite HTML, una serie completadi campi da compilare. L'utenteci fornirà quindi i dati che ver-ranno usati come base per ela-borare le azioni successive.

Come webmaster dobbiamocompiere questi passaggi: crea-re il form di inserimento dati,acquisire i dati (registrandolinelle forme opportune ed even-tualmente validandoli), fornireuna risposta all'utente. La crea-zione del form si effettua conHTML e la si dà per acquisita(vedi corso webmaster). Fon-damentale per passaggio, regi-strazione e utilizzo dei dati è laprima riga dell'istruzione form,e in particolare la parola actione i due metodi get e post:

<form action=”test.php” method=”post”>

Questa riga indica, una voltasottoscritti i dati con l'appositocontrollo submit, che il browserverrà indirizzato alla pagina te-st.php sul CD (se action èomessa la pagina cui l'utenteviene reindirizzato è la paginastessa che comprende il form)e i dati passeranno col metodopost.

Il metodo post consente di

trasmettere, in maniera total-mente trasparente all'utente,tutti i dati compilati nel formsenza alcun limite di spazio,mentre il metodo get trasferi-sce i dati visualizzandoli sullariga di indirizzo del browser (ecol limite di soli 256 caratteritrasmissibili). Per vedere la dif-ferenza fate riferimento a po-st.php (listato_12, è un form conmetodo post) e a get.php (lista-to_13, è un form con metodoget): entrambi hanno come at-tributo action la paginatest.php, ma la differenza di tra-smissione dei dati la notate sul-la riga del browser (vedi imma-gini 2 e 3).

Tre istruzioni Una volta trasferiti i dati, do-

vremo essere in grado di acce-dervi: PHP mette a disposizio-ne queste tre istruzioni “su-perglobali”:

$_GET[“dato”] // per form con metodo get

$_POST[“dato”] // per form con metodo post

$_REQUEST[“dato”] // sia per form con metodo get che post

$_REQUEST concede unapossibilità che $_GET e $_POST

non danno: una volta registratoun dato del tipo $_REQUE-ST[“nome_dato”] possiamo poirichiamarlo nella pagina comefosse una variabile appena di-chiarata, ossia con la forma:

$nome_dato

Conto alla rovesciamodificato

Ora siamo in grado di intera-gire col nostro utente. Potrem-mo, ad esempio, aumentare l'u-tilità del “conto alla rovescia”presentato nella sezione prece-dente, consentendo all'utentedi indicare lui stesso la data cuifare riferimento.

Dobbiamo solo stare attentiai dati inseriti (sia in termini diformato che di valori consenti-ti) e quindi useremo dei con-trolli con caselle combinate (leliste a discesa), come nell'e-sempio inserisci.html (listato14). I valori inseriti sarannopassati attraverso il metodopost alla pagina conto_rove-scia.php sul CD. È possibile an-che inserire date senza senso(ad esempio 31 giugno): la fun-zione timestamp si occuperà ditrasformare l'errato inserimen-to nella data più vicina e visua-lizzeremo questa data nella ri-sposta. La data inserita dall'u-tente nel form viene così ripor-tata, tramite $_POST, nella pa-gina indicata da action:

// $fine è il timestamp della datarichiesta

$fine = mktime (12,0,0,$_POST['mese'],$_POST['giorno'], $_POST['anno'],0);

Sarebbe comunque da impe-dire l'inserimento di date nonvalide, ma per fare questo dob-

biamo aspettare di aver intro-dotto i costrutti di controllo.

Modifica dello stile di una pagina Web

Un altro interessante esem-pio lo possiamo immaginaresfruttando le caratteristichedei fogli di stile: vogliamo, in-fatti, dare la possibilità al no-stro utente di visualizzare i no-stri articoli riportati su paginaWeb con carattere, dimensionie colori preferiti.

Faremo transitare il nostroutente dalla pagina introduzio-ne.html (listato_15) dove è pre-sente un form attraverso ilquale si dovrà scegliere il ca-rattere poi visualizzato nellapagina articolo.php sul CD.

La scelta dei caratteri è ri-dotta alle quattro famiglie(arial, verdana, times, courier)generalmente visualizzate datutti i browser, e i colori con-sentiti sono espressi in terminiesadecimali, anche se l'utentevede delle descrizioni “norma-li” (bianco, nero, giallo, ...).Scelta la combinazione voluta,la pagina articolo.php verrà vi-sualizzata di conseguenza tra-mite le indicazioni inserite nelfoglio di stile incorporato:

<style>span.font {font-family: <?php echo

$_POST['carattere']; ?>;font-size: <?php echo

$_POST['dimensione']; ?>px;color: <?php echo $_POST['col_car']; ?>;}body {background-color: <?php echo

$_POST['col_sfondo']; ?>;}</style>

1a lezione

4 I form

POST e GET in PHP

2

3

Metodo GET

Metodo POST

Fino alla versione 4.2.0, PHPconcedeva sempre e comunquedi richiamare i dati inseriti nei form con la forma$nome_dato. Ora questapossibilità, salvo il caso vistocon $_REQUEST, non è piùconcessa per motivi di sicurezza. Per capirne le implicazioni, immaginate che qualcuno avesse chiamatola pagina test.php senzapassare attraverso i form:semplicemente scrivendohttp://www.xxxxx.it/test.php?nome=topolino questo utentesmaliziato sarebbe riuscito ad attribuire alla variabile$nome il valore topolino.Vi sono casi in cui questapossibilità conduce a eventiassolutamente indesiderati,compreso l'accesso a pagine

protette.Per utilizzare il “vecchio”sistema bisogna fare una modifica su php.ini,sostituendo il valore offa on sulla riga register_globals(il valore valido per il vostrosistema lo potete vedere anchecontrollando la paginavisualizzabile usando la paginaphpinfo.php).Sottolineiamo però, ancora una volta, come sia megliocomunque abituarsi a usare$_POST e $_GET, sia perevitare problemi di sicurezza,sia per evitare che il vostroprovider, magari aggiornando il parser PHP, cambi il valore di register_globals da on a offlasciandovi un bel po' di problemi sulla visualizzazionedel vostro sito!

Page 7: Corso di Php (fonte: PC OPEN)

1a lezione

L'esempio può essere am-pliato coinvolgendo tutte le ca-ratteristiche della pagina co-me indicato dalle proprietà deiCSS. Anche qui, però, mancanole strutture di controllo: cosasuccede se si accede alla pagi-na senza passare attraversol'introduzione? Sarà il browsera decidere la visualizzazione,ma chiaramente questa è unacondizione inaccettabile per ilwebmaster.

Accessibilità dei siti WebNell'esempio indicato è pos-

sibile variare la dimensione (inpixel) del carattere.

Si potrebbe pensare chequesta indicazione definisca ladimensione del carattere inmaniera fissa, indipendente dalbrowser.

In realtà se aprite la paginaarticolo.php con Mozilla (oppu-re Opera o Firefox) vedrete cheusando le combinazioni CTRL++ o CTRL+ - i caratteri aumente-ranno o diminuiranno di di-mensione.

Microsoft Explorer, invece,non modifica assolutamente la

dimensione dei font cui è stataassegnata una dimensione fis-sa (in punti o pixel).

Le disposizioni del W3CChi sbaglia? Diversamente

da quanto si potrebbe pensare,è Explorer a non rispettare idettami stabiliti per i browserInternet: anche se questa pos-sibilità di ridimensionamentomanda in crisi i webmaster (de-siderosi di mantenere il layoutstudiato per la pagina), essa èespressamente richiesta dalW3C (World Wide Web Consor-

tium) per accrescere l'usabilitàdel Web a persone cui può es-sere assolutamente necessarioscalare i caratteri.

Tenete poi presente che unacerta dimensione in pixel puòessere splendida per certe ri-soluzioni video, ma per altrepuò rivelarsi non adatta perchétroppo piccola.

Non prendetevela, quindi, sedopo aver speso giorni e giornia stabilire la giusta visualizza-zione della pagina fissando tut-ti i font, un semplice CTRL+ +potrà scompaginare tutto.

5 Costrutti di controllo

Per costruire script avanza-ti bisogna padroneggiareassolutamente le strutture

di controllo, ossia quelle istru-zioni che consentono di ese-guire delle azioni solo a frontedella verifica di particolari con-dizioni.

L'esempio tipico è dato dallapagina protetta da password:volendo descrivere a parole l'a-zione connessa, essa suona co-me Accedi alla pagina solo se lapassword che hai fornito corri-sponde a quella registrata per ilnome utente inserito. “Solo se” èil costrutto di controllo.

PHP ci fornisce tutti i co-strutti standard (for, if, while,switch) e un paio di istruzioniestremamente utili (foreach eisset) per accelerare i tempi discrittura del codice.

If – else – elseifLa condizione if (con l'even-

tuale aggiunta di else o elseif) èla base dei costrutti di control-

lo. Viene definita una condizio-ne: se (if) è rispettata (condi-zione vera) viene eseguito ilcodice tra le parentesi graffedopo la if, altrimenti si escedalla if senza eseguire il codiceo viene eseguito del codice al-ternativo (else):

if (condizione) {codice da eseguire se condizione è vera}else {codice da eseguire se condizione è false }

Le condizioni if possono es-sere nidificate senza problemiper creare strutture comples-se. La condizione elseif con-sente di aggiungere ulterioricondizioni da verificare primadi arrivare al codice else o diuscire dal costrutto.

Un esempio di utilizzo lopossiamo vedere in confron-

to.php (listato 16): creiamo duenumeri interi casuali $a e $bcompresi tra 1 e 4 e verifichia-mo quale dei due sia più gran-de:

In alcuni frangenti si dimo-stra utile usare la parola chiaveexit all'interno di una condizio-ne: quando viene incontrataquesta istruzione, il serverblocca la “traduzione” della pa-gina e la invia al browser clientcome definita in quel momen-to. Un esempio è disponibile incontrollo-exit.php (listato_17):se la prima condizione è soddi-sfatta non posso più visualiz-zare quanto scritto dopo lachiusura del ciclo if:

if ($a>$b) {echo "\$a=$a e \$b=$b:<br>";echo "\$a è maggiore di \$b";echo "<p><h3> Verificata questa

condizione blocco il codice successivousando exit. Non potete sapere cosa c'è scrittodopo il blocco if!</h3>";

exit;}

WhileIl costrutto del ciclo while è

veramente semplice e al con-tempo potente: le istruzionicontenute nel ciclo sono itera-te finché la condizione è vera,ogni volta andando a leggere(ordinatamente) il valore suc-cessivo della condizione.Quando la condizione diventafalsa il ciclo si arresta e prose-gue oltre:

while (condizione) {codice}

Questo costrutto è moltoutilizzato per leggere le liste:ad esempio si usa while permandare a video tutti i recorddi una tabella terminando l'e-secuzione quando la tabella èvuota (vedremo questo utiliz-zo nelle lezioni dedicate a My-SQL).

Con il costrutto while siamofinalmente in grado di miglio-rare l'esempio creato per la vi-sualizzazione random di unafoto (random.php, listato_09).

Cosa succede, infatti, se in-seriamo altre immagini nellacartella Web che abbiamo scel-to, sempre seguendo le stesselogiche di numerazione?

Dovremmo correggere off-li-ne il listato di cui sopra, sosti-tuendo al valore 5 il valore piùalto delle nuove immagini in-serite, per poi trasferire dinuovo la pagina sul server so-vrascrivendo la precedente.Facile, ma è una possibile fon-te di errori: PHP ci può rispar-miare questa operazione ren-dendo la nostra pagina validaqualunque sia il numero di im-magini presenti nella cartella.

Per questo sfruttiamo le fun-zioni per le directory (in parti-colare opendir e readdir) e i co-strutti di controllo.

Innanzi tutto usiamo open-dir per registrare (e validare) ilpercorso della cartella, e poireaddir per leggere il primo filedella directory.

Qui interviene while: attra-verso una condizione while sureaddir, la directory viene lettafile dopo file e ogni riferimentoè registrato su un array. Esau-

LISTATO 16

<?php$a = rand (1,10);$b = rand (1,10);

if ($a>$b) {echo “$a=$a e \$b=$b:<br>\$a è maggiore di \$b”; // il carattere escape (\) serve a visualizzare come output simboli particolari come $}

elseif ($a==$b) { // notare l'operatore di confronto ==echo “$a=$a e \$b=$b:<br>\$a è uguale a \$b”;}

else {echo “$a=$a e \$b=$b:<br>\$a è minore di \$b”;}

?>

Page 8: Corso di Php (fonte: PC OPEN)

1a lezione

rita la lettura, il codice esce dalciclo while e possiamo final-mente definire $max, ossia ilnumero di immagini che ab-biamo trovato nella directoryImmagini.

Ecco quindi la pagina ran-dom-due.php (listato 18).

La parte più utile da analiz-zare è la seguente:

while (false !== ($file = readdir($cartella))) {// il ciclo while verrà iterato finché

la cartella non sarà stata interamenteletta. A ogni iterazione $file assume il nome del file successivo. Con la prima iterazione creo l'array e registro il primo nome di file, poi l'array viene riempito con i nomi dei file seguenti

$lista[ ]=$file;}// count conta il numero

di elementi contenuti nell'array. Vienediminuito di due perché l'array dellacartella contiene sempre le indicazioniUNIX "." e ".."

$max=count($lista)-2;if ($max==0) {echo "Attenzione: Non ci sono

immagini nella cartella";}

else {$num=rand(1,$max);

}

Ricordiamo che PHP 5, almomento rilasciato solo comerelease candidate, prevede unanuova funzione, scandir, in gra-do di evitare questo passaggiocon while: scandir sarà infattiin grado di leggere i contenutidi una cartella e registrarli di-rettamente in un array senzautilizzare altre funzioni.

ForIl ciclo for consente di itera-

re un'azione, definendo la con-dizione iniziale di un puntato-re, il controllo da fare e l'incre-mento del puntatore dopoogni ciclo. L'azione verrà ese-guita (e rieseguita) finché ilcontrollo darà risposta true al-la verifica.

for (punto iniziale; condizione darispettare; tipo di iterazione) {

codice da eseguire }

For si rivela utilissimo percostruire strutture di paginadi cui non possiamo conoscerecon anticipo tutti gli elementi:stiamo parlando, quindi, di ve-ri e propri siti dinamici.

Per capire meglio, possiamocostruire un esempio basan-doci su quanto visto per il co-strutto while con la directoryImmagini.

In questo caso, però, il no-stro scopo è ottenere la listadelle immagini contenute nellacartella, visualizzandole nellapagina Web elenco-dir.php. Quitrovate la parte del listato chesi riferisce al costrutto for (li-stato 19).

Possiamo migliorare la visi-bilità del nostro elenco visua-lizzando i file alternativamentesu righe aventi colore di sfon-do diverso (elenco-dir-due.php,listato_20). Qui l'attenzione vaposta nel conteggio delle righeda mandare in output: se sonopari verrà eseguito un ciclo fore usciremo dalla pagina, men-tre se sono dispari il ciclo fordovrà fermarsi prima dell'ulti-ma riga, che andrà stampata aparte (listato 20).

Un buon esercizio per verifi-care di aver compreso bene iconcetti di cui sopra può esse-re il seguente (è una variazionesul tema di quanto appena vi-sto): creare una galleria delleimmagini della directory, vi-sualizzandole a due a due, unadi fianco all'altra.

Chiaramente dovremo usarele tabelle e/o i CSS, ponendoattenzione all'eventuale ultimaimmagine dispari. La soluzioneda me proposta la trovate nel-la pagina elenco-galleria.php(sul CD).

Vedremo nelle prossimepuntate del corso come creareuna galleria con un certo nu-

mero prefissato di immagini, oaltri oggetti, per ogni pagina(ad esempio sei immagini perpagina) e una barra di naviga-zione per spostarsi tra le pagi-ne.

SwitchIl costrutto switch somiglia

a una serie di if di uguaglianza:una variabile (array e objectesclusi) viene confrontata condei valori predefiniti così daeseguire differenti blocchi dicodice a seconda del valoreassunto dalla variabile:

$mese=date('n');switch ($mese) {

case 1:echo “Siamo in Gennaio”;break;

case 2:echo “Siamo in Febbraio”;break;

case 3:echo “Siamo in Marzo”;break;

..................}

Lo stesso risultato si sareb-be raggiunto con:

$mese=date('n');if ($mese==1) {

echo “Siamo in Gennaio”;}if ($mese==2) {

echo “Siamo in Febbraio”;}if ($mese==3) {

echo “Siamo in Marzo”;}..................

Dove sta la differenza? Nelprimo caso la variabile $meseè valutata all'inizio del costrut-to e poi il valore è solo con-frontato con quelli delle istru-zioni case, mentre nel caso diif la variabile $mese è valutatae verificata ogni volta, con unospreco di risorse e tempo dielaborazione.

Notate la parola chiavebreak: va inserita al termine diogni blocco di codice case, al-trimenti il parser continuereb-be leggendo il blocco succes-sivo invece di uscire dal co-strutto.

È possibile definire un casecon valore default: il codicesarà eseguito quando tutte lealtre condizioni case si rivele-ranno false.

IssetAbbiamo spesso la neces-

sità di controllare, prima dicompiere un'azione, se una va-riabile è definita (anche se ma-gari con valore nullo) oppurese non lo è.

Questo controllo è assoltosemplicemente da isset incombinazione con if: isset, in-fatti, restituisce un valore truese la variabile cui fa riferimen-to esiste:

if (isset($variabile)) {codice

}

Possiamo usare isset per mi-gliorare l'esempio in cui modi-ficavamo la visualizzazione diun articolo.

LISTATO 19

echo "<h4>La cartella 'immagini' contiene questi file:</h4><p>";for ($i=2;$i<=count($lista)-1;$i++) { // il contatore $i parte da 2

perché i primi due valori registrati nell'array $lista sono “.” e “..”, e non voglio visualizzarli

$ordine=$i-1;echo "---------------------------------------------------<br>";echo "<span class='output'>File $ordine: $lista[$i]</span><br>";

}

LISTATO 20

if ($fine%2==0) { // controllo se nella cartella c'è un numero pari di immaginifor ($i=2;$i<count($lista);$i=$i+2) { // il ciclo di for visualizza due file

ad ogni iterazione$ordine=$i-1;$j=$i+1;echo "<span class='dispari'>File $ordine: $lista[$i]</span>";echo "<span class='pari'>File $i: $lista[$j]</span>";}

}else { // il numero di immagini è dispari, quindi si deve aggiungere l'ultima riga

disparifor ($i=2;$i<$fine;$i=$i+2) { // il ciclo for visualizza due file per ogni iterazione e si ferma prima dell'ultima immagine

$ordine=$i-1;$j=$i+1;echo "<span class='dispari'>File $ordine: $lista[$i]</span>";echo "<span class='pari'>File $i: $lista[$j]</span>";}

$j=$i-1;echo "<span class='dispari'>File $j: $lista[$i]</span>";}

Page 9: Corso di Php (fonte: PC OPEN)

1a lezione

Invece di usare un form in-termedio di passaggio (tra l’al-tro poco elegante, dal momen-to che il nostro utente potreb-be accedere direttamente allapagina articolo.php una voltache ne conosca l'URL), po-tremmo definire dei valori didefault validi finché non vienescelto un diverso carattere dalform cliccando su “invia”.

Il controllo della definizioneiniziale delle variabili è de-mandato proprio a isset comeesemplificato in articolo-due.php (listato 21):

ForeachForeach, un po' come isset,

ci aiuta a risparmiare tempoper compiere un'azione di cuispesso si ha bisogno: attraver-sare completamente un array,effettuando delle operazioni(assegnazione, confronto, vi-sualizzazione, ...) su un secon-do array “copia” appositamen-te creato.

La funzione più importantela si rileva quando bisognaoperare su un array completo,anche solo per visualizzare tut-ti gli elementi.

Per fare questo potremmousare un ciclo for (ma dobbia-mo sapere quanti elementicompongono l'array) o un ciclowhile (con una struttura nonmolto amichevole). Oppure unsemplice ciclo foreach (paginalista-disney.php, listato 22):

Un altro esempio concretolo si ha in occasione della vali-dazione dei dati passati attra-verso un form: se vogliamoporre tutti i campi di un formcome obbligatori, dovremocontrollare tutti i campi per ve-rificare che sia stato immessoun valore, inserendo quindiuna serie di istruzioni if e/o is-set. Foreach ci viene in aiutoper rendere la scrittura più agi-le e per evitare banali dimenti-canze, come si vede dalla pagi-na check.php (listato 23):

Notate, nel ciclo if, la funzio-ne trim il cui scopo è eliminaretutti gli spazi vuoti all'inizio diun campo: in questo modo seun utente compilasse il formsolo con degli spazi vuoti, il no-stro test comunque non ne va-liderebbe l'inserimento (unafunzione if semplice, invece, l'a-vrebbe fatto passare).

Un controllo di questo tipo èsufficiente per la maggior partedelle nostre esigenze, come ve-dremo nella prossima puntatadel corso.

Introduciamo qui anche lafunzione die che interrompel'esecuzione della pagina vi-sualizzando come output il co-dice chiuso dalle parentesi.

Lo stesso compito era assol-to anche da exit, vista in unodegli esempi precedenti.

Siti di riferimentoSe volete avere ulteriori ap-

profondimenti su PHP potetevisitare questi siti:

http://www.php.nethttp://freephp.html.ithttp://www.apache.org

Se state ricercando un sug-gerimento su una qualsiasi fun-zione di PHP, potete accederevelocemente alle pagine delmanuale on-line scrivendol'URL del sito seguito da unoslash con la parola da ricerca-re, ad esempio http://www.php.net/isset (sul manua-le sarà cercata la parola isset).

È utile farlo perché, oltre alladescrizione del manuale, si tro-vano anche molti esempi prati-ci scritti dagli utilizzatori diPHP. �

LISTATO 21

<style>span.output {

font-family:<?php

if (isset($_POST['carattere'])) {echo $_POST['carattere'];// valido solo se è stato sottoscritto il form e quindi $_POST esiste

}else {

echo "Arial";// è la visualizzazione di default quando $_POST non esiste, ossia non è mai stato cliccato il bottone “invia” del form

}?>;

}</style>

LISTATO 22

$lista=array (“pippo”, “topolino”, “paperino”, “pluto”);foreach ($lista as $copia) {

echo “Un personaggio Disney: $copia<br>”;}

Si può utilizzare foreach anche per definire un secondo array contenente le chiavidell'array originale:

$lista=array (“pippo”, “topolino”, “paperino”, “pluto”);foreach ($lista as $chiave=>$copia) {

echo “Personaggio Disney numero $chiave -> $copia<br>”;}

LISTATO 23

if (!isset($_POST['nome'])) {// serve solo alla prima chiamata della pagina

die ("<p><h3>Tutti i campi vanno obbligatoriamente compilati</h3>");}

foreach ($_POST as $ctr) {// foreach ci consente di controllare tutto l'array $_POST

if (trim($ctr)==""){// trim toglie gli spazi vuoti eventualmente presenti in $ctr

die ("<p><h3>Tutti i campi vanno obbligatoriamente compilati</h3>");}

}

I corsi Webmasterdisponibilinel CDNel CD Guida 2 allegatoa questo numero di PCOpen, all’interno dellacartella PDF/Corsi, trovatedue corsi completi chepossono essere un utilecomplemento al corso PHP.Uno è il corso WebDeveloper ASP, 97 paginesuddivise in quattro lezioniper capire come realizzaresiti dinamici in tecnologiaASP.

Il corso Webmaster spiega,invece, in 88 paginesuddivise in otto lezioni tuttoquello che bisogna sapere per costruire un sito e imparare il linguaggioHTML 4.01, i CSS (fogli di stile), Java Script e CGI. Il corso è completato da utiliconsigli per promuovere il proprio sito on line.

Page 10: Corso di Php (fonte: PC OPEN)

2a lezione

Nella lezione 1 abbiamoesplorato le basi di PHP,dando tutti gli elementi

per creare le nostre prime pa-gine e alcuni spunti per coglie-re le potenzialità di questo lin-guaggio.

Nella seconda lezione mette-remo in luce, invece, funziona-lità avanzate che ci consenti-ranno di migliorare i nostriscript, rendendoli più efficientie utilizzabili anche per il futuro.

Il discorso sarà poi conclusonella terza puntata, dove ver-ranno trattate anche tematicherelative alla sicurezza e alla ge-stione degli errori.

Non parleremo ancora dellaconnessione tra PHP e i data-base (con particolare riguardoa MySQL), in quanto questo ar-gomento sarà oggetto di tratta-zione specifica e approfonditanelle prossime puntate del cor-so.

Spesso capita di inserire inpiù pagine Web esatta-mente lo stesso codice: un

esempio tipico sono le righeche formano la testata (hea-der) o il piè di pagina (footer),ma possiamo prendere in con-siderazione anche le righe checompongono le barre di navi-gazione e dei menu, le chiama-te ai database, la protezione dipagine con password, la chia-mata dei CSS esterni e altro an-cora.

Come agiamo in questi casi?Usando il “tradizionale” HTML,non abbiamo molta scelta: cidobbiamo armare di pazienzaed effettuare una serie di copia-incolla di codice su pagine di-verse! A parte gli errori semprein agguato nell'operazione delcopia-incolla, un grosso pro-blema nascerà con la necessitàdi modificare una parte qual-siasi di questo codice ripetuto:prima o dopo, inutile negarlo,avremo bisogno di cambiarequalcosa, vuoi per migliorarele funzionalità e la navigazione,vuoi per aggiornamenti e refre-sh. Di fronte a questa esigenza

dovremo nuovamente armarcidi pazienza (molta più di quel-la che ci era servita quando ab-biamo realizzato le pagine),aprire tutti i file interessati edeffettuare la modifica. L'opera-zione può essere più o menoagevole a seconda del tipo dicambiamento e del softwareutilizzato, e può divenire unostacolo insormontabile se i li-stati delle pagine sono staticreati da terzi. Alcuni program-mi, come Home Site, ci vengo-no in aiuto con una utilissimafunzione che consente di ope-rare il replace su più file con-temporaneamente, però que-sto non è sufficiente.

Leggendo queste righe im-maginiamo che qualcuno ab-bia pensato ai fogli di stile(CSS, Cascading Style Sheet) e aiproblemi di modifica del layoutdi un sito Web. Prima dell'in-troduzione dei CSS, infatti, mo-dificare gli attributi di struttura(anche solo la dimensione diuna font) su tutte le pagine diun sito Web era un lavoro im-probo, mentre adesso bastasemplicemente cambiare un

unico attributo in un CSS ester-no e il gioco è fatto.

Include e require in PHPfunzionano allo stesso mododi un CSS esterno: nel puntovoluto del listato Web possia-mo inserire una chiamata a unfile esterno il cui contenutosarà “trasferito” alla paginachiamante e interpretato dalparser PHP come appartenen-te alla pagina di origine. Ognieventuale modifica andrà effet-tuata, quindi, solo sul file ester-no e automaticamente verràestesa a tutte le pagine interes-sate.

PHP ci propone due funzionisimili: include e require. Si inse-riscono in maniera estrema-mente semplice nella paginachiamante, semplicemente in-dicando il nome (col percorsorelativo) del file voluto:<?php

include (“testata.inc.php”);?>

<?phprequire (“testata.inc.php”);

?>La differenza tra le due fun-

zioni è nella gestio-ne degli errori: incaso di errore, include producesolo un avvertimento (war-ning) senza bloccare la pagina,mentre require blocca la com-pilazione del linguaggio (fatalerror). Che cosa usare, quindi,è funzione degli obiettivi delWebmaster.

Un esempio semplice delvantaggio di usare gli inclu-de/require file lo possiamo ri-cavare direttamente dalla quo-tidianità. Immaginiamo di avercreato un sito dove sia neces-sario inserire in molte pagineun disclaimer a tutela del trat-tamento dei dati personali, co-me previsto dalle norme sullaprivacy. Essendo Webmasterprevidenti abbiamo incluso inogni pagina interessata (comeprivacy.php, vedi listato_01) unfile esterno col testo del di-sclaimer (disclaimer.inc.php,vedi listato 2):

<html><head><title>Privacy</title>

</head>

Lezione 1:- PHP con un server off line- Funzioni base e variabili- I costrutti di controllo

Lezione 2:- Approfondiamo PHP- Include e require- Funzioni e classi

- Proteggere una pagina- Cookie e sessioni- La funzione mail

Le prossime puntateLezione 3: PHP e databaseLezione 4: PHP e MySQLLezione 5: Gestire un sitodinamico con PHP e MySQL

IL CALENDARIO DELLE LEZIONI

di Federico Pozzato

� A scuola con PC Open

WebDeveloper PHP1 Approfondire PHP

I listaticompleti

sono sul CD

2 Include e require

Page 11: Corso di Php (fonte: PC OPEN)

2a lezione

<body><h3>Questa parte di testo è inserita

direttamente nella paginaprivacy.php</h3>bla bla bla bla bla bla bla<p><h3>Quella che segue, invece, èinserita nella pagina disclaimer.inc.phped è visualizzata in questa paginautilizzando un'istruzione include:</h3><?php

include("disclaimer.inc.php");?>

</body></html>listato 1

<em>Ai sensi della L. 675/96 ti informiamoche tutti i dati in nostro possessoverranno utilizzati solo perpubblicizzare iniziative inerenti XYZWK.Nessun dato verrà ceduto a terzi. Inogni momento potrai chiedere diessere cancellato dal nostro databasecon una semplice comunicazione alnostro indirizzo di posta elettronica.</em>listato 2

Quando il browser chiameràprivacy.php, l'effetto sarà di ve-dere riportato il testo del di-sclaimer come se appartenes-se alla pagina originale (imma-gine 1). Il vantaggio di questastruttura lo avremmo tangibil-mente verificato all'inizio del2004 quando è entrata in vigorela nuova norma di disciplinadel settore (dalla Legge 675/96al D.Lgs.196/03): invece di mo-dificare tutte le pagine, l'unicaoperazione di modifica l'a-vremmo compiuta solo su di-sclaimer.inc.php semplicemen-te modificando il riferimentodella Norma (vedi l'esempiocorrispondente privacy_new.php con disclaimer_new.inc.php).

Bisogna porre molta atten-zione al fatto che le pagine cuifanno riferimento include e re-quire sono a tutti gli effetti pa-gine appartenenti al sito e ri-chiamabili col browser. Se in-seriamo note particolari in

questi file esterni (magari an-che password), dobbiamo es-sere sicuri che non siano visi-bili nel caso qualcuno ci finiscadentro direttamente. Il consi-glio, quindi, è di nominare que-sti file inclusi come nomepagi-na.inc.php, dove il suffisso incserve a noi per capire al voloche quella pagina è inclusa inun'altra, mentre l'estensionephp indica al server di trattarela pagina utilizzando il parsing(è ovvio che nel listato dovran-no essere presenti i tag PHP).

Se usassimo solo l'estensio-ne .inc (o .html o .txt o nessuna)il browser ci farebbe vedere lapagina come fosse un testo, an-che se contenesse i tag PHP.Buona norma è dunque prova-re ad aprire direttamente colbrowser tutti i file inclusi e ve-dere se è tutto OK per la sicu-rezza dei nostri dati.

Se volete una prova del ri-schio che si può correre, pro-vate ad aprire la pagina acces-so.inc: vedrete in maniera deltutto trasparente i dati di ac-cesso a un database, passwordcompresa (immagine 2). Pro-vate poi a chiamare accesso.inc.php e vedrete la differenza!

Un esempio praticoSe il primo esempio serviva

solo a entrare nell'argomento,la seconda proposta, invece,può trovare utili applicazionipratiche nelle pagine del no-stro sito: useremo include, gliarray e i costrutti di controlloper costruire una barra di na-vigazione dinamica.

Lo scopo è sapere sempre inquale sezione del sito ci trovia-mo e dare la possibilità di spo-starsi velocemente nelle altresezioni. La barra verrà inseritacome include in tutte le pagine:sarà quindi molto flessibile perpermettere modifiche futurenel caso di ampliamento delprogetto.

Per il nostro esempio abbia-mo bisogno di una paginamain.php, due sottopagine

arg1.php e arg2.php che con-tengono le sezioni “viaggi e fo-to” e “curriculum”, una paginamenu.inc.php (listato_03) per labarra di navigazione e un fogliodi stile menu.css per definirel'aspetto della barra stessa.

La logica da applicare è la se-guente:

• inizializziamo un array as-segnando a ogni nome di pagi-na un testo da visualizzare nel-la barra che verrà creata;

• verifichiamo in quale pagi-na ci troviamo. Per fare questoutilizziamo una delle tante va-riabili superglobals di PHP (inquesto caso $_SERVER[“PHP_SELF”] ) in unione con la fun-zione basename che restitui-sce solo il nome del file elimi-nando il resto del percorso

• creiamo una struttura dicontrollo di tipo foreach-if: lafunzione foreach ci consente dinavigare lungo tutto l'arraycreato, mentre if si occupa di“distinguere” la pagina attiva(quella dove ci troviamo) dailink cliccabili.

<?php// inizializzo l'array$naviga = array ("main.php"=>"Homepage", "arg1.php" => "Viaggi e foto","arg2.php" => "Curriculum");

// verifico in quale pagina mi trovo$nome_file =basename($_SERVER["PHP_SELF"]);echo "<table><tr align='center'><tdclass='lato'>&nbsp;</td>";

// struttura di controlloforeach ($naviga as $chiave=>$menu)

{echo "<td ";if ($chiave==$nome_file) {echo " class='nolink'>".$menu;}else {echo " class='link'><a class='nav'href='".$chiave."'>$menu</a>";}echo "</td>";}echo "</td><tdclass='lato'>&nbsp;</td></tr></table>";?>listato 3

È chiaro che, se aggiungo al-tre pagine, l'unica operazioneda compiere sarà aggiungere lanuova pagina all'array $naviganel file incluso menu.inc.php.

Il risultato ottenuto (uno deitanti possibili a seconda di co-me definiamo il foglio di stile) èvisibile nell'immagine 3: la pa-gina dove ci troviamo è visibilecon sfondo verde e non è clic-cabile, mentre lo sono le altrepagine. Fate clic per vedere co-sa succede entrando nelle altrepagine.

La funzione basename con-sente anche di estrarre la radi-ce del nome della pagina, eli-minando l'estensione. Per farequesto, l'estensione da elimi-nare va indicata come secondoargomento di basename:

<?php$nome_file =basename($_SERVER["PHP_SELF"],“php”);?>Include e require facilitano l’inserimento dei file di testo uguali in numerose pagine

1

Nella pagina accesso.inc sono trasparenti anche i dati riservati

2

La pagina è visibile con fondo verde e non è cliccabile, ma lo sono le altre pagine

3

Page 12: Corso di Php (fonte: PC OPEN)

2a lezione

Spesso si scrivono righe dicodice uguali per effettua-re operazioni ripetitive e

comuni a più pagine. Esempipossono essere gli script per lacreazione di qualche menu, maanche listati molto più semplicicon i quali si vuole magari cal-colare l'area di un triangolo orestituire un valore vero-falsodopo una verifica.

Una soluzione semplice e ba-nale può essere usare la classi-ca accoppiata copia-incolla, so-luzione valida, però, solo se sisa esattamente dove recupera-re il codice da copiare. Potrem-mo riuscire a risolvere veloce-mente il nostro problema,aprendo comunque la strada apossibili errori: copiatura erra-ta del codice, difficoltà ad adat-tare il nome delle variabili conpossibili dimenticanze semprein agguato, propagazione dieventuali errori contenuti nellerighe originali, difficoltà nell'in-dividuazione del codice chepotrebbe essere diversamenteincapsulato nelle pagine.

Per venire incontro alle esi-genze dei Webmaster, PHP ciaiuta con funzioni e classi.

Le funzioniLe funzioni sono script di

codice da invocare e da cui ci siattende una risposta:

function esempio (eventualiargomenti){

codicereturn risultato restituito

}

La funzione deve avere unnome univoco (attenzione: nonpossiamo utilizzare i nomi ri-servati previsti da PHP, comead esempio print) e va inserita(sembra una cosa ovvia, manon sempre è rispettata) in unpunto del listato precedente al-la chiamata. Il risultato vienerestituito utilizzando l'istruzio-ne return: chiamata all'internodi una funzione, return terminaimmediatamente l'esecuzionedella funzione corrente e resti-tuisce il suo argomento comevalore della funzione. Possia-mo inserire più istruzioni re-turn all'interno della stessa fun-zione, tenendo presente che,appena incontrato il return, ilcodice proseguirà al di fuoridella funzione.

Finora abbiamo visto moltis-sime funzioni predefinite diPHP: basename, ad esempio, èuna di queste. Basename, infat-ti, necessita di alcuni argomen-ti (il percorso della pagina eun'eventuale estensione) e re-stituisce di conseguenza il va-lore atteso, ossia il nome dellapagina con o senza estensione.

Una funzione può restituireanche solo un valore vero-falso(true-false), da usare magari incombinazione con un if percreare un ciclo di controllo, oun qualsiasi altro tipo di varia-bile (valori, array, oggetti).

Usare le funzioni consente diconcentrarsi sul codice puro(“astratto”) della funzione, sen-za doversi preoccupare del si-gnificato delle variabili all'e-sterno della funzione stessa.

Una volta scritta, la funzionesarà sempre utilizzabile e nondovremo neppure preoccupar-ci di reinterpretare il codiceper adattarlo alle nuove varia-bili. Spesso passa molto tempotra quando si scrive del codicee quando poi lo si riutilizza: an-che in questo caso, con le fun-zioni evitiamo di doverci rin-frescare la memoria ricom-piendo i passaggi logici del pas-sato.

Basename è registrata nellelibrerie di PHP ed è valida uni-versalmente per tutti gli utiliz-zatori. Nel nostro piccolo,però, anche noi abbiamo biso-gno di semplificarci la vita equindi decidiamo di scrivere lanostra prima funzione (listato4) per calcolare il prezzo nettodi un bene, dato uno scontoespresso come valore da 0 a100:

function prezzo_netto($prezzo,$sconto){if ($sconto<0 or $sconto>100) {return “Questa funzione assume che losconto debba essere un numerocompreso tra 0 e 100, mentre tu haiinserito uno sconto uguale a $sconto”;}$netto=$prezzo*(1-$sconto/100);return $netto;}listato 4

Questa funzione può essereusata dovunque ce ne sia biso-gno: l'applicazione pratica la sivede nella pagina sconto.phpche contiene un form con duecampi dove inserire i valori diprezzo e sconto sulla base deiquali calcolare il prezzo netto.Da notare è la chiamata dellafunzione prezzo_netto nella pa-gina sconto.php:

echo “Prezzo netto: ”.prezzo_netto($_POST['pre'],$_POST['sco']);

Come si vede, le variabilipassate come argomento dellafunzione hanno un nome diver-so da quello assegnato nelloscript della funzione, ma la co-sa non ha la minima importan-za perché questo è il senso del-le funzioni: PHP, infatti, inter-preta la prima variabile passa-ta come fosse la variabile$prezzo originale e la seconda

variabile come fosse la $scontooriginale.

Va sottolineato che le varia-bili usate all'interno della fun-zione non possono essere ri-chiamate all'esterno, quindiqualsiasi invocazione a $prez-zo o $sconto nel corso del lista-to non produrrà alcun risultato(salvo, ovviamente, non esista-no nel corpo della pagina duevariabili con questo nome).

Se volessimo questa possi-bilità dovremmo definire le va-riabili della funzione come$GLOBALS (col loro nome) al-l'interno dello script della fun-zione stessa. L'esempio è ri-portato nella pagina sconto_global.php dove, all'interno del-la dichiarazione della funzioneprezzo_netto è presente l'istru-zione:

$GLOBALS[“sconto”] = $sconto;

Adesso sarà possibile chia-mare la variabile $sconto ancheall'esterno della funzione, men-tre non si potrà chiamare$prezzo perché non è stata di-chiarata globale.

Possiamo definire anchefUnzioni senza argomenti: è ilcaso delle funzioni che effet-tuano dei controlli ripetitivi erestituiscono una stringa o deivalori true/false.

La funzione controllo(), pro-posta come esempio, verificaper prima cosa se esiste unacartella varie posta allo stessolivello della pagina Web su cuiviene inserita. Se la cartella esi-ste, viene poi verificato se èvuota o se contiene dei file. Lalogica che sta alla base dellafunzione è esprimibile in formadi algoritmo, come si può ve-dere nell'illustrazione 4. Perfunzioni semplici, disegnare unalgoritmo può essere solo unaperdita di tempo, ma è essen-ziale per funzioni più comples-se ed è quindi buona abitudineimparare a usarli.

La funzione è riportata nel li-stato 5, mentre la pagina Web diesempio è la checkvarie.php.Provate a creare e cancellare lacartella varie, lasciandola vuo-ta o inserendo qualche file.

function controllo()// questa funzione controlla che inuna directory predefinita sia presente

3 Funzioni e classi

Un algoritmo esprime la logica che sta alla base della funzione controllo ()

4

Nome cartella

Esiste?

Contiene file?

RETURN 3

RETURN 1

RETURN 2

No

No

Page 13: Corso di Php (fonte: PC OPEN)

2a lezione

almeno un file{$cartella=@opendir('varie');if (!$cartella) {return "Attenzione: è inutile cercarefile... la cartella non esiste e quindidevi prima crearla";}while (false !== ($file =readdir($cartella))) { $lista[]=$file;}$fine=count($lista)-2;if ($fine==0){return "Attenzione: Non ci sono filenella cartella";}return “Prosegui pure: nella cartellac'è almeno un file”;}listato 5

Per rendere più utilizzabilequesta funzione, si può passarealla funzione un argomentouguale al percorso della cartellada controllare. La modifica è fa-cile (la trovate in checkvarie_plus.php): basta definire la fun-zione controllo ($directory) einserire $directory all'internodella funzione come argomen-to di opendir.

Ulteriore esercizio è prende-re il percorso della cartella dacontrollare direttamente da unform: provate a costruire la pa-gina da soli e poi confrontatelacon checkvarie_form.php (vediimmagine 5). Adesso potetecontrollare tutte le cartelle chevolete, l'unica accortezza è ri-cordarsi che il percorso dellacartella è relativo e non assolu-to.

Abbiamo detto all'inizio delparagrafo che la funzione origi-nale deve essere presente nelcodice prima di un’eventualechiamata. Potremmo pensaredi inserire (copia-incolla) lafunzione in tutte le pagine checi interessano, ed è una validaidea se le pagine che usanoquesta funzione sono poche,altrimenti ricadiamo nei pro-blemi già descritti in preceden-za. Una soluzione più efficiente

(ed elegante) consiste, invece,nello salvare le funzioni in fileseparati includendoli poi co-me già visto. Ogni modifica fat-ta sulla funzione verrà quindipropagata automaticamente atutte le pagine:

<?phpinclude (“funzione_controllo.inc.php”);?>

Non è possibile, per chiarez-za di comportamento del codi-ce, ridefinire funzioni già di-chiarate all'interno di uno stes-so listato (overloading).

Le classiLe funzioni sono costrutti

semplici, adatti a lavori ripeti-tivi da cui ci si aspetta un unicorisultato.

Non sempre ciò è sufficiente,basti pensare al caso di costru-zioni di codice avanzato in gra-do di interagire con altre fun-zioni e variabili: un esempiopuò essere la creazione di unsistema di gestione avanzato dicommercio elettronico, magarida esportare su più siti. In que-sto caso un'architettura de-mandata a funzioni stand-aloneè possibile, ma diventa semprepiù difficile da gestire all'au-mentare della complessità ri-chiesta.

Per esigenze di questo tipoci viene in aiuto il concetto diclasse, grazie al quale potremoaddentrarci brevemente nellaprogrammazione rivolta aglioggetti. La trattazione non puòessere esaustiva perché l'argo-mento prevede conoscenzespecialistiche, ma la cosa im-portante è riuscire a cogliere ilconcetto alla base della pro-grammazione OO (ObjectOriented) per poterlo poi ap-profondire con testi o corsispecifici.

Orientarsi agli oggetti signi-fica porre l'accento sulla defi-nizione di tutte le proprietà ge-neriche di un certo oggetto edelle funzioni legate a queste

proprietà. Lo faccio senza pen-sare all'oggetto specifico X o al-l'oggetto specifico Y, bensìguardando al concetto piùastratto possibile grazie al qua-le posso poi definire gli oggettispecifici.

Una classe è, quindi, una col-lezione di variabili (proprietà)e funzioni (metodi) che utiliz-zano queste variabili:

class Nuova_classe{variabili (proprietà)funzioni (metodi)}

Definita una classe come ve-dremo in seguito, possiamo ge-nerare un oggetto utilizzando ilcostrutto new:

$oggetto = new Nuova_classe;

È il codice della classe che“definisce” l'oggetto, il qualedeve essere creato, tramite l'i-struzione new, con un nomediverso da quello di altri ogget-ti istanziati (cioè inizializzati)dalla stessa classe. Per il con-cetto stesso che sta alla basedella programmazione OO, in-fatti, è possibile definire quantioggetti si vuole basandoli suuna stessa classe. Ricordate lascorsa puntata quando parla-vamo dei tipi di variabili? Man-cava solo il tipo object, ossiaproprio quello definito usandola classe.

Definito un oggetto, a esso èpossibile applicare tutti i me-todi implementati nella classedi appartenenza, in manieramolto semplice e con una puli-zia di codice inarrivabile peruna programmazione stan-dard.

Facciamo un esempio trattodalla vita di tutti i giorni: se de-vo disegnare un rombo granderosso e un rombo piccolo gial-lo, sostanzialmente devo faredue operazioni simili.

Qual è la differenza tra i due“oggetti” da disegnare? Solo ladimensione e il colore, dal mo-mento che la definizione dirombo è unica! Bene, allora èsufficiente che sia dichiarata(una volta per tutte) una “clas-se” Rombo all'interno dellaquale siano introdotte le varia-bili dimensioni e colore checonsentono di effettuare il di-segno.

Alla classe non interessa il ti-po di rombo da disegnare, masolo definire che cos'è un rom-

bo colorato. A questo puntoper risolvere il nostro compitonon ci resta che creare due “og-getti” facenti riferimento a que-sta classe, inizializzando sem-plicemente i due oggetti con leloro caratteristiche. Siamo ingrado di creare infiniti rombi e,fondamentale, siamo in gradodi farlo pur non sapendo nulladi cosa sia un rombo! Forniti idati di colore e dimensioni, in-fatti, è la classe che si incaricadi restituire gli oggetti in ma-niera del tutto trasparente perl'utente.

Vediamo di fare un esempiodi programmazione di classe:supponiamo di creare una clas-se Quadrato grazie alla quale,una volta definito il lato, pos-sano essere ricavati i valori diarea, perimetro e diagonale. Ladefinizione completa della clas-se la trovate in classe_quadra-to.inc.php, mentre qui ci bastaun estratto (listato_06) con so-lo il metodo “area”.

class quadrato{// dichiarazione delle variabiliutilizzate (da accompagnare con unadescrizione, per rendere più leggibile ilcodice)var $lat;var $ar;var $per;var $diago;

function quadrato($lato)// costruttore{

$this->lat=$lato;}

function area()// calcola l'area del quadrato{

$this->ar=$this->lat*$this->lat;return $this->ar;

}}listato 6

Ci sono due cose da notare:quando è definita una funzionecon lo stesso nome della clas-se, questa funzione prende ilnome di costruttore. Il costrut-tore è utile in certe classi per-ché inizializza il tipo di oggettodella classe stessa. In questocaso il costruttore serve a ini-zializzare l'oggetto col valoredel lato del quadrato. Il co-struttore può anche non essereindicato, ma se lo è sarà inter-no alla classe e avrà necessa-riamente il nome della classestessa. �Il risultato in pagina della funzione controllo

5

Page 14: Corso di Php (fonte: PC OPEN)

Con la definizione di fun-zioni e classi abbiamoesaurito le nozioni fonda-

mentali di PHP. Arrivati a questo punto non

dovrebbe quindi essere un pro-blema affrontare un compitomolto pratico (e utile), ossiaelaborare qualche strategia perproteggere una o più paginedel nostro sito Web da occhi in-discreti. In pratica, vogliamoche a certe pagine possanoavere accesso solo le personedotate di una password, o me-glio di una precisa accoppiatausername-password.

I motivi di questa decisionepossono essere i più vari: suuna pagina possiamo avere in-serito testi e immagini che soloi nostri amici più cari devonoleggere, ma potrebbe anche es-sere una esigenza di lavoro checi impone di tutelare certeinformazioni, oppure una partedel Web site deve essere pro-tetta perché da essa è possibi-le gestire gli aggiornamenti delsito stesso.

Qualunque sia il motivo, ab-biamo la necessità di protegge-

re l'accesso a una pagina. Ve-diamo adesso un paio di esem-pi, rimandando poi l'approfon-dimento del discorso a dopol'introduzione dei database (le-zione 4).

PHP ci consente di ottenerela protezione di una pagina inmolti modi. Quello scelto peresercizio implica la creazionedi una funzione e l'uso di un ci-clo di controllo (listato_08). Lapagina di esempio è protet-ta_1.php, e al primo accesso cifa vedere un form dove l'unicocampo da compilare è quellorelativo alla password da inse-rire.

La funzione controllo si oc-cupa solo di restituire un valo-re true o false, a seconda che ilconfronto tra le due variabilidia esito positivo o negativo.Nel nostro caso, il valore resti-tuito dalla funzione sarà asse-gnato a una variabile $check, laquale chiama la funzione usan-do come campi la password in-serita nel form e la passworddefinita da noi (pluto). Se$check avrà valore true allora lapagina sarà visualizzata, altri-

menti ci troveremo di nuovo difronte al form vuoto.

<?php

function controllo ($confronto, $pass) {if ($confronto==$pass) {return true;}return false;}

$password=”pluto”;// la password “pluto” l'abbiamoimpostata noi

$check=controllo($_POST['pwd'],$password);// $check assumerà valore true ofalse in dipendenza del valore inseritonel form

if ($check==false) {// la password è errata o non è maistata inserita?><h3>Inserisci la password corretta perentrare nella pagina protetta</h3><form action="protetta_1.php"method="post"><input type="password"name="pwd"> = password<p></p>

<input type="submit" name="invio"value="Connetti"></form><?php}else {// la password è esatta e quindiposso avere accesso alla pagina

echo "<h3>Hai inserito la passwordgiusta. La pagina è a tuadisposizione</h3>";}?>listato 8

Una variazione sullo stessotema (meno elegante, maugualmente efficace) la potetevedere in protetta_1_var.php.

Per migliorare la costruzio-ne presentata, bisogna quanto-meno posizionare in un fileesterno la funzione e il valoreassegnato da noi alla password(vedere password.inc.php e pro-tetta_1_inc.php).

In questo modo è possibileusare il costrutto include perinserire senza errori la stessapassword in più pagine e se simodifica la password lo si fa inun unico punto.

La seconda notazione im-portante è il modo di passare ilnome delle variabili all'internodella classe: abbiamo detto cheogni classe può creare N ogget-ti basati su di essa, ma semprecon nome diverso. Non poten-do a priori conoscere il nomedell'oggetto, all'interno dellaclasse dovremo usare il co-strutto $this-> generico:

$this->nome_variabile

In questo modo tutte le va-riabili definite nella classe sa-ranno disponibili per ogni og-getto creato in seguito.

Un esempio completo è ri-portato nella pagina classe.php,dove possiamo vedere comeinizializzare gli oggetti e comechiamare variabili e funzioni.Un oggetto va istanziato (ini-zializzato) usando il costruttonew:

$a=5;$nuovo_quadrato_1=new

quadrato($a);

Creato l'oggetto $nuovo_quadrato_1, per chiamare lefunzioni o le variabili useremola notazione che già conoscia-mo (->), ricordandoci di indica-re sempre il nome dell'oggettoappena creato (vedi listato 7):

// creo un nuovo oggetto della classequadrato con lato 5$a=5;echo "<h3>Quadrato_1:<p></h3>";$nuovo_quadrato_1=newquadrato($a);

echo "<h5>Lato:".$nuovo_quadrato_1->lat."<p>";// per chiamare la funzione “area” eper ritornare il valore dell'area:echo "Area: ".$nuovo_quadrato_1->area()."<p>";// per chiamare la funzione“perimetro” e per ritornare il valore delperimetro:echo "Perimetro:".$nuovo_quadrato_1->perimetro()."<p>";

// per chiamare la funzione“diagonale” e per ritornare il valoredella diagonaleecho "Diagonale:".$nuovo_quadrato_1->diagonale()."<p></h5>";listato 7

Questo esempio di classe èbanale, ma permette di coglie-re l'essenza della programma-zione OO: definite proprietà emetodi di una classe sarà pos-sibile, infatti, creare e gestireoggetti in maniera semplice esenza preoccuparsi di tuttoquello che c'è nella classe.

Con una ricerca su Internetsi trovano numerose classipronte da usare. Una, ad esem-pio, serve a superare il limitedel timestamp: non occorre ca-pire cosa c'è sotto, ma solo sa-pere come istanziare l'oggettoe quali funzioni chiamare.

In classe.php abbiamo inseri-to due oggetti diversi (due qua-drati di lato diverso) basati sul-la stessa classe ($nuovo_ qua-

drato_1 e $nuovo_quadrato_2):le chiamate a variabili e funzio-ni differiscono solo ed esclusi-vamente per il nome dell'og-getto, e ci consentono di otte-nere facilmente tutti i dati utilidi un “oggetto” quadrato.

Lasciamo per ultima unaconsiderazione ormai ovvia: laclasse va naturalmente “inclu-sa” nella pagina chiamante eposta prima della creazione diqualsiasi oggetto.

Una classe può essere an-che la base di un'altra classeche ne estende le funzionalità.In questo caso nella secondaclasse indicheremo solo il co-dice nuovo senza dovercipreoccupare di funzioni e va-riabili già costruite nella primaclasse. Il costrutto da cercarenel manuale di php.net è ex-tends:

class quadrato_plus extends quadrato{

codice}

2a lezione

4 Proteggere una pagina con password

Page 15: Corso di Php (fonte: PC OPEN)

2a lezione

Un altro limite, però, è pro-prio quello di avere una solapassword per tutte le personeche hanno accesso alle pagine:se dovessimo cambiarla permotivi di sicurezza (poniamoche sbadatamente qualcunoabbia comunicato la passworda persone non autorizzate) do-vremo informare necessaria-mente tutti gli attori coinvolti.

Sarebbe invece più efficienteassegnare a ogni persona unadiversa coppia username-pas-sword, in modo da modificare,eventualmente, soltanto la pas-sword di quella persona speci-fica.

Vediamo allora di modificare

il codice precedente, introdu-cendo un controllo username-password.

Usiamo la stessa logica vistanel primo esempio, con la no-vità di creare un array conte-nente le coppie username-pas-sword.

La parte di codice che ci in-teressa (con la nuova funzionedi confronto e con l'array $cop-pie) è visibile in listato_09:

function controllo_coppia($confronto,$user,$pass) {foreach ($confronto as $chiave=>$val){if ($chiave==$user and $val==$pass) {return true;

}}return false;}

// valori di username e passworddecisi da noi$coppie=array("pippo"=>"pluto","topolino"=>"minni","paperino"=>"paperina");

// $check darà un valore true o false$check=controllo_coppia($coppie,$_POST['user'],$_POST['pwd']);listato_09

La parte che segue il listato 9è uguale a quanto già visto e l'e-sempio completo è riportato

sulla pagina protetta_2.php.Adesso siamo in grado di mo-dificare username e passworddelle singole coppie.

Anche in questo caso, poi,sarà buona consuetudine por-tare in un file esterno la funzio-ne e la definizione di $coppie(vedi pagine password_2.inc.php e protetta_2_inc.php).

Nel prosieguo del corso ve-dremo come usare i databaseper proteggere una pagina ecome evitare di dover inserireusername e password su ognipagina protetta.

Ma per questi argomentil’appuntamento è alle lezioni 4e 5.

5 Cookie e sessioni

Il protocollo HTTP è un proto-collo stateless, cioè non di-spone di un metodo per man-

tenere una memoria relativa al-lo stato della comunicazionetra client e server. Per ovviare aquesta mancanza vengono innostro aiuto i cookie e le ses-sioni.

Sappiamo tutti bene cosasiano i cookie: piccoli file regi-strati sul nostro PC (lato client)e richiamati dalla pagina Webcaricata (lato server). Lo scopoè recuperare informazioni pre-cedentemente fornite dall'u-tente in maniera più o menotrasparente. Se usati coscien-ziosamente dai Webmaster, icookie si dimostrano indubbia-mente utili quando richiamanodati che altrimenti dovremmoogni volta settare, però al con-tempo possono dimostrarsi de-leteri se servono, come avvie-ne col “cavallo di troia”, perestrarre dal PC informazioniinerenti la nostra privacy e re-lative a siti da noi visitati, scel-te effettuate o simili.

Proprio a causa della pessi-ma pubblicità fatta ai cookie,molti utenti ne disabilitanocompletamente la registrazio-ne nel proprio PC, o quanto-meno la abilitano solo per sitiassolutamente fidati.

Assumendo di utilizzare icookie in senso positivo, do-vremo tenere conto di questepossibili limitazioni e agire diconseguenza.

In questa sezione parleremo

prima di cookie e poi introdur-remo il concetto di sessione,assolutamente da conosceresia per trasmettere dati all'in-terno del proprio Web domainche per superare, in alcuni ca-si, il problema della disabilita-zione dei cookie.

CookiePoniamo di volere inizializ-

zare un cookie in modo da ri-conoscere un utente che abbiagià visitato il nostro sito. Ma-gari potremmo avergli chiestonelle precedenti visite quale se-zione preferisce, in modo da in-dirizzarlo direttamente versoquella specifica pagina.

PHP imposta i cookie con lafunzione setcookie:

setcookie (nome, valore, durata)// valore e durata sono parametriopzionali

e registra i valori nella varia-bile globale $_COOKIE (ricor-date le variabili globali? Ne ab-biamo parlato nella scorsapuntata) così da poterla richia-mare in un secondo momento.Il nome del cookie è sempreobbligatorio, mentre non lo so-no né il valore né la durata.

Lasciando vuoto il campovalore, il cookie specificatoverrà inizializzato assegnando-gli un valore null. Anche la du-rata è opzionale. Se non vieneindicato nulla, il cookie sarà at-tivo solo fino alla chiusura delbrowser e poi verrà cancellato

dal disco fisso del client. Se ilnostro scopo è usare i cookieper recuperare i dati di accessieffettuati in momenti diversi,dovremo quindi assegnare unadurata (un minuto, un giorno,un mese, un anno...) al “biscot-tino”.

Le istruzioni che coinvolgo-no i cookie vengono inviate in-sieme con gli header HTTP (gliheader sono le righe di intesta-zione HTTP che indicano albrowser come comportarsi) evanno pertanto chiamate (pe-culiarità degli header) prima diqualsiasi output di pagina os-sia prima anche del tag <html>.

Un'altra importante peculia-rità da ricordare è che, apertauna pagina, viene sempre recu-perato il valore del cookieeventualmente registrato inprecedenza: l'aggiornamentodel cookie (o la sua registrazio-ne) verrà letto solo quando lapagina sarà ricaricata succes-sivamente. Questo ci facilitanella scrittura del codice deinostri listati.

Un esempio è più chiaro ditante parole (vedi cookie.php):supponiamo di voler accoglie-re un navigatore che torna nelnostro sito indicandogli quan-do ci ha visitati l'ultima volta.Per fare questo dobbiamo in-nanzi tutto verificare se il navi-gatore possiede un nostrocookie precedentemente regi-strato, altrimenti dobbiamocreare il cookie per la primavolta. Il cookie dovrà essere

valido sei mesi. La prima parte da esaminare

(listato 10) è il codice che pre-cede l'inserimento del tag<html>. Con setcookie inizializ-ziamo per la prima volta (o ag-giorniamo se già esisteva) uncookie di nome data: esso con-tiene il valore $data che indicaquando la pagina è stata vistal'ultima volta. La durata delcookie è espressa in secondi apartire da oggi, quindi usiamola funzione time() aggiungendoil numero di secondi per arri-vare a sei mesi circa.

<?php$data = date("d-m-y")." alle ore".date("H-i-s");setcookie("data", $data,time()+15800000);?>listato_10

Il codice del listato 11, inve-ce, è contenuto tra i tag <html>dell'esempio proposto. Il cicloif controlla se il cookie data esi-ste: in caso positivo ci dicequando abbiamo visto la pagi-na l'ultima volta, in caso nega-tivo ci informa che è la primavolta che accediamo al sito.

Ricordiamo che la lettura delcookie si riferisce sempre allostato precedente a quello even-tualmente settato sulla paginaaperta.

<?phpif (isset($_COOKIE['data'])) {echo "<h4>Ciao amico, hai già visitato

Page 16: Corso di Php (fonte: PC OPEN)

2a lezione

� queste pagine. L'ultima volta che haiaperto questa pagina è stato il".$_COOKIE['data']."</h4>";}else {echo "<h4>Ciao amico, è la primavolta che visualizzi questa paginaoppure hai cancellato il cookie dallamemoria del tuo PC</h4>";}?>listato 11

Un cookie può essere can-cellato assegnandogli un valo-re null in questo modo:

setcookie (“data”);

SessioniI cookie, lo abbiamo appena

visto, salvano un piccolo file diinformazioni all'interno del no-stro PC, quindi lato client. Lesessioni, al contrario, sono unmetodo lato server per archi-viare informazioni relative a unsingolo accesso.

Per avere un esempio, pos-siamo pensare ai siti di com-mercio elettronico in cui è pre-sente un “carrello della spe-sa”: il compito essenziale per ilWebmaster è mantenere regi-strate le scelte effettuate daun cliente durante un collega-mento (l'utente potrebbe ac-quistare N libri, spostandosicontinuamente di pagina in pa-gina). La sessione serve pro-prio a questo, a mantenere me-moria delle scelte fatte duran-te un collegamento da ogni sin-gola persona, scelte che poipossono essere memorizzate ocancellate! Si potrebbero an-che usare i cookie, ma in que-sto caso ci sarebbe il problemadi cosa fare se sono stati disa-bilitati.

Con le sessioni, i dati sonoregistrati nel server che ospitail sito e vengono identificati (edifferenziati gli uni dagli altri)tramite un identificativo uni-voco denominato SID (SessionIdentifier). Il SID (casuale e nonprevedibile: è formato da 32caratteri alfanumerici) vieneassegnato a ogni utente che sicollega al sito e la sessione vie-ne mantenuta attiva (ossia vie-ne mantenuto lo “stato”) fin-ché il SID viene passato traserver e client durante la navi-gazione del sito.

Fondamentale, dunque, è ilpassaggio del SID, operazioneche può avvenire in due modi.Nel primo caso tornano utili icookie: se sono attivi, il SID vie-

ne passato attraverso uncookie temporaneo che vienepoi cancellato dal client quan-do viene chiuso il browser (oquando la sessione è esplicita-mente chiusa con un'operazio-ne di logout). Da parte delWebmaster non c'è da fare nul-la di particolare.

Il secondo sistema, invece,consiste nel passare il SID at-traverso l'URL di una paginausando i metodi GET o POST,quindi ogni link di pagina saràdel tipo:

<a href=”nuova pagina.php?<?phpecho SID; ?>">Clicca qui</a>

Quale scegliere? Il metodo“cookie” è più semplice dalmomento che non bisogna farenulla, però dovremo preoccu-parci di prevedere la trasmis-sione del SID anche per quegliutenti che hanno disabilitato icookie, quindi o si fa un con-trollo per vedere se i cookie disessione sono attivi (basta ve-rificare se esiste un cookiechiamato PHPSESSID) o si tra-smette sempre e comunque ilSID.

In realtà esiste anche un ter-zo metodo di passaggio delSID, completamente traspa-rente per programmatore eutente dal momento che il SIDè trasmesso automaticamente.Questa possibilità, però, impli-ca l'attivazione dell'opzionetrans_sid nel php.ini, cosa nonsempre possibile se il servernon è nostro. Inoltre general-mente l'opzione è disattivatadi default e quindi non tratte-remo questo caso.

Cosa succede dei file sessio-ne registrati sul server? Quan-to tempo restano salvati? Ladurata di salvataggio dei datisul server e anche la duratadella sessione stessa sono de-finite nel php.ini e quindi di-pendono dal gestore del ser-ver: questi valori sono visibilivisualizzando la pagina ph-pinfo di cui abbiamo parlatonella prima lezione.

È chiaro, altresì, che un filedi sessione potrà essere recu-perato e riutilizzato in un se-condo momento solo se si è te-nuta nota del SID, altrimentinon vi si potrà accedere in nes-sun caso.

Va posto un minimo di at-tenzione al fatto che i file sal-vati sul server sono semplici fi-le di testo non criptati: è bene,quindi, salvare nei file di ses-

sione solo dati che possano,nel caso più malaugurato, es-sere letti da altri senza danni.

Giusto per fare un esempio,se si vuole usare la sessioneper mantenere attivo, duranteun collegamento, l'accesso apiù pagine riservate, è benenon salvare come variabile disessione un dato sensibile co-me la password. In ogni caso,niente allarmismi: ricordo cheil SID identificante la sessioneè composto da 32 caratteri al-fanumerici casuali ed è quindiestremamente improbabileche un estraneo possa entrareaccidentalmente in una nostrasessione!

Per usare le sessioni, le re-gole da conoscere sono relati-vamente poche.

Innanzi tutto, quando un vi-sitatore accede al sito, PHPcontrollerà (su nostra esplicitarichiesta formulata tramite lafunzione session_start) se unospecifico ID di sessione sia pre-sente.

In caso positivo il preceden-te ambiente salvato verrà ri-creato, altrimenti verrà inizia-lizzata una nuova sessione colsuo specifico SID.

Come visto per i cookie, an-che session_start() dovrà esse-re chiamata prima di qualsiasioutput html. Le variabili di ses-sione saranno poi richiamatecome variabili globali $_SES-SION, e potranno essere “can-cellate” in maniera molto sem-plice usando l'istruzione unset.

La sessione può essere del

tutto cancellata con l'istruzio-ne session_destroy.

Il carrello della spesaE ora vediamo un esempio

pratico che può dare moltispunti: il carrello della spesa.Supponiamo di avere una pagi-na all'interno della quale siapossibile scegliere tra libri e di-schi da due elenchi (vedi la pa-gina lista.php), e una paginache funga da riepilogo (vedicarrello.php) di quanto sceltodurante la sessione in corso,potendo anche tornare in unsecondo momento nella listaper ordinare altri prodotti.

Sulla pagina lista.php va no-tata la chiamata della sessionee la trasmissione del SID all'in-terno della riga di intestazionedel form. In questo modo nonci interessa sapere se un uten-te abbia o meno i cookie atti-vati:

<form action='carrello.php?<?phpecho SID; ?>' method="post">

Fatta la selezione e fatto clicsul pulsante Vai ci troviamonella pagina carrello.php dovesi vedono le selezioni effettua-te fino a quel momento. Ciò èreso possibile dalle variabili disessione, come si può vedereanalizzando l'estratto visibilenel listato 12.

<?phpsession_start();// controllo se è stato selezionato unlibro

La pagina carrello.php presenta le selezioni effettuate dall’utente

6

Page 17: Corso di Php (fonte: PC OPEN)

2a lezione

if ($_POST['libro']) {

//controllo se il libro selezionatoesiste già nel carrelloif (isset($_SESSION['libro'][$_POST['libro']])) {$_SESSION['libro'][$_POST['libro']]++;}else {$_SESSION['libro'][$_POST['libro']]=1;}}listato 12

Per prima cosa si verificache un libro sia stato effettiva-mente selezionato, quindi vie-ne creato (o modificato au-mentando la quantità di 1) ilvettore $_SESSION['libro'] cheha una struttura del tipo:

$_SESSION['libro'] [libro selezionato] =quantità

Stessa operazione viene fat-ta per il vettore $_SESSION['di-sco'], quindi i due vettori ven-gono stampati col classico ci-clo foreach (dopo averli ordi-nati usando l'istruzione ksort).Il risultato è visibile nell'imma-gine 6.

Per aggiungere altri prodottibasta fare clic sul link di fondopagina che ci riporta alla listadi selezione, mantenendo me-moria dell'identificativo dellasessione ed eventualmente tra-smettendoli.

Il link che consente di can-cellare la sezione ci fa passareattraverso la pagina logout.php, che serve unicamente aeliminare tutti i dati della ses-sione e a reindirizzarci nuova-mente alla lista di partenzacon l'istruzione:

header("Location: lista.php");.

Provate ad attivare e disatti-vare i cookie dal vostro PC perverificare il funzionamento del-le sessioni. Un'altra annotazio-ne che può essere utile: di de-fault il nome della sessione èPHPSESSID, quindi per stam-pare le 32 cifre identificativebasta chiamare:

echo $PHPSESSID;

Se volessimo recuperareuna vecchia sessione (cono-scendo il PHPSESSID), bastascrivere l'URL della pagina car-rello in questo modo:

http://mio.sito/carrello.php?PHPSESSID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Adesso che questo semplicecarrello della spesa è comple-to, magari potremmo volerspedire l'ordine direttamentevia e-mail. Vediamo come farequesta operazione.

La funzione mailAttenzione: per verificare il

funzionamento off-line dellafunzione mail sul vostro PC de-ve essere installato anche unserver mail. Poiché questoesula dalla presente trattazio-ne, il consiglio è di verificare lepagine descritte caricandolesu uno spazio Web on-line do-ve PHP sia attivato.

PHP comprende una funzio-ne mail, fondamentale per po-ter creare form attraverso iquali gli utenti possano scri-verci, per automatizzare rispo-

ste, per gestire mailing, perspedire cartoline elettronichee chi più ne ha più ne metta.

La funzione preposta a tuttiquesti usi ha una forma estre-mamente semplice e compat-ta:

mail (destinatario, oggetto, messaggio,header e messaggi addizionali)// il quarto campo è opzionale e puòcontenere tutti i vari header chevediamo analizzando il codice sorgentedi una mail

Con questa funzione possia-mo simulare in tutto e per tut-to quello che facciamo col no-stro programma di posta elet-tronica, quindi possiamo spe-dire mail di solo testo o conHTML, aggiungere allegati, in-serire immagini in linea, spedi-re la mail a destinatari in CC(carbon copy) o BCC (blankcarbon copy).

In realtà proprio la compat-tezza della funzione rende al-cune delle operazioni sopradescritte alquanto complicatevisto che bisogna conoscerela codifica MIME di spedizionedelle mail. Fortunatamente inInternet si trovano classi giàpronte all'uso per risolverequesti problemi.

Qui impareremo le nozionifondamentali su come spedireun’e-mail in formato testo. Ilcaso tipico è quello della spe-dizione di un’e-mail a seguitodella compilazione di un formpredisposto su Internet (vediform_posta.php). Il form con-tiene solo quattro campi dacompilare: nome e indirizzo diposta del mittente, soggetto ecorpo della mail stessa (imma-gine 7). Cliccando su Spediscisi apre una seconda finestrache ci conferma l'avvenutaspedizione della mail.

Nel codice di questa pagina(spedisci.php) inseriamo il no-stro indirizzo (destinatario) ela funzione mail (listato 13).Notiamo che il mittente va in-serito usando un'istruzioneFrom posta nel quarto campodella funzione mail (il campoaddizionale). La funzione stri-pslashes serve a evitare pro-blemi nel caso in cui chi com-pilasse il form usasse caratteriparticolari come le virgolette,gli apici, le slash.

<?php// destinatario della mail$to="[email protected]";

// soggetto della mail$subject=stripslashes($_POST['soggetto']);

// oggetto della mail. In questo puntoil costrutto “\n” serve a far andare iltesto a caporiga nella mail che ciarriverà al nostro indirizzo$object=stripslashes($_POST['nome'])."\n\n";$object.="Oggetto:".stripslashes($_POST['testo']);

// mittente della mail$from="From:".$_POST['email'];

// funzione che spedisce la mailmail($to,$subject,$object,$from);?>listato_13

Anche eventuali campi dainserire in copia o copia na-scosta vanno inseriti nel quar-to campo di mail(), separan-doli con i caratteri speciali\r\n che determinano le azionidi “ritorno carrello” e “a capo”.Un esempio è presente nel li-stato 14:

<?php$to="[email protected]";$subject=stripslashes($_POST['soggetto']);$object=stripslashes($_POST['nome'])."\n\n";$object.="Oggetto:".stripslashes($_POST['testo']);

// inseriamo il mittente nel quartocampo della funzione$intestazioni="From:".$_POST['email'].”\r\n”;

// aggiungiamo una coppia di mail($cc_1 e $cc_2) in copia$intestazioni.="Cc:".$cc_1.”,“.$cc_2.”\r\n”;

// aggiungiamo una mail ($bcc_1) incopia nascosta$intestazioni.="Bcc:".$bcc_1.”\r\n”;

// funzione che spedisce la mailmail($to,$subject,$object,$intestazioni);?>listato 14

Per rendere più efficace lafunzione mail() si può pensaredi inserire nella pagina spedi-sci.php una serie di controlliper evitare che si possano la-sciare campi vuoti nel form, eper verificare il corretto inseri-mento dell'indirizzo mail delmittente. �

I quattro campi da compilare del form_posta.php

7

Page 18: Corso di Php (fonte: PC OPEN)

PC Open Dicembre 2004106

3a lezione

La terza puntata del corso èdivisa concettualmente indue sezioni ed è il trâit d'u-

nion tra i due oggetti di questaserie di lezioni per Web deve-loper.

Nella prima parte conclude-remo il corso di PHP sviluppa-to nelle due precedenti lezioni,approfondendo gli ultimi aspet-ti pratici di programmazione eintroducendo alcuni suggeri-menti generali in termini di ge-stione degli errori e di sicurez-za.

La seconda parte, invece, èdedicata all'introduzione dei

concetti fondamentali riguar-danti i database, concetti sen-za i quali non saremo in gradodi sfruttarne al meglio le carat-teristiche.

Capiremo cosa siano un Da-tabase System e un DBMS (Da-tabase Management System) evedremo i principi basilari perla corretta costruzione di unabase di dati.

Al termine di questa lezionesaremo quindi in grado di pa-droneggiare PHP e la teoria deiDB, pronti a unire queste dueconoscenze nelle due puntaterestanti del corso.

Nella prima le-zione abbia-mo visto co-

me installare unserver locale perpoter testare off li-ne in tutta calma lepagine PHP primadi caricarle sul no-

stro spazio Web.

L’accesso FTP del providerPer compiere questa opera-

zione il provider ci avrà asse-gnato un accesso FTP (FileTransfer Protocol) protetto dausername e password, accessograzie al quale saremo in gradodi spostare, aggiungere, can-cellare, rinominare file diretta-mente sul server remoto comestessimo utilizzando il ben co-nosciuto Esplora Risorse diWindows.

Possiamo anche fare l'u-pload di immagini, filmati, filemusicali; l'unico limite è gene-ralmente dato dalla dimensio-

ne dello spazio a nostra dispo-sizione.

Spesso solo webmaster,webdesigner e webcontent,ognuno per la sua area di com-petenza, si occupano di carica-re contenuti nel sito, ma in al-cuni casi potremmo voler darela stessa possibilità anche ainostri visitatori (o ai nostriclienti).

Pensiamo, ad esempio, al ca-so di un sito di viaggi amato-riali che voglia consentire agliutenti (meglio se registrati) dicaricare (uploadare) le imma-gini della loro ultima vacanza, oad un sito di un ente pubblicoin cui una persona designata sioccupi di caricare le delibere diinteresse pubblico senza do-ver ogni volta passare attra-verso il webmaster.

È chiaro che queste personenon devono assolutamenteavere accesso tramite FTP allastruttura del sito Web, sia permotivi di sicurezza e privacy

sia perché, accidentalmente ovolutamente, potrebbero can-cellarne tutti i contenuti.

Come effettuare l’upload dei file

La soluzione è quindi creareuna pagina Web attraverso laquale compiere l'operazione diupload dei file. A seconda deinostri scopi la pagina potrà es-sere o no protetta, consenten-do l'accesso ai soli utenti auto-rizzati.

PHP è in grado di ricevere fi-le (in forma testuale o binaria)direttamente da un form di unapagina Web e ci fornisce unaserie di funzioni di autentica-zione e manipolazione graziealle quali abbiamo un comple-to controllo su quanto vienecaricato e sulla sua gestione fu-tura.

Costruiamo per prima cosail form di inserimento, come vi-sibile nella pagina form_upload.php.

Ci sono tre cose cui prestareattenzione (listato 01): la parti-colare istruzione enctype nel-l'intestazione del form (senzala quale l'operazione non vienesvolta), l'imposizione della di-mensione massima (in byte)del file caricabile e il type “file”dell'istruzione di input.

Listato_01<form enctype="multipart/form-data"

action="file_upload.php"method="post"><input type="hidden" name="MAX_

FILE_SIZE" value="100000">File da inviare: <input name="mio"

type="file" size="40"><p><input type="reset" value="Cancella"

>&nbsp;<input type="submit"value="Invia">

</form>

Il file individuato dopo averpremuto il bottone sfoglia (obrowse se abbiamo impostatola lingua inglese di visualizza-zione) viene caricato in memo-

Lezione 1:- PHP con un server off line- Funzioni base e variabili- I costrutti di controllo

Lezione 2:- Approfondiamo PHP- Include e require- Funzioni e classi- Proteggere una pagina- Cookie e sessioni- La funzione mail

Lezione 3: PHP e i database

- La funzione upload- Lavorare con i file- La gestione degli errori- Accenni di sicurezza- DataBase: il databasesystem

- Siti Web dinamici- Teoria dei database

Le prossime puntateLezione 4: PHP e MySQLLezione 5: Gestire un sitodinamico con PHP e MySQL

IL CALENDARIO DELLE LEZIONI

di Federico Pozzato

� A scuola con PC Open

WebDeveloper PHP1 PHP e i database

I listaticompleti

sono sul CD

2 Upload di file

Page 19: Corso di Php (fonte: PC OPEN)

PC Open Dicembre 2004107

3a lezione

ria come file temporaneo equindi indirizzato alla pagina fi-le_upload.php. La dimensionemassima del file è in realtà de-finita a livello server nel php.ini(valore della riga upload_max_filesize; di default è 2 MB) e fatesto indipendentemente dalvalore scritto a livello di form.Definire qui un valore può peròrivelarsi utile per due motivi:per restringere le dimensionidei file che vogliamo far carica-re o per evitare che un utenteattenda il caricamento di un fi-le per poi vedersi restituito unerrore (le dimensioni del filesono confrontate con quantoindicato nel php.ini solo dopo ilcaricamento in memoria!).

Dopo il caricamento PHP cimette a disposizione il vettoreglobale $_FILES, grazie al qualeotteniamo una serie di infor-mazioni sul file: il nome origi-nale, il “mime type” (se il brow-ser è abilitato a fornire questainformazione), la dimensionein byte, il nome del file tempo-raneo e il codice di errore.

Queste cinque chiamate so-no riportate nel listato 02, e so-no caratterizzate da cinque pa-role chiave (name, type, size,tmp_name, error) poste dopoil nome assegnato al file da ca-ricare nell'operazione di input(nel nostro caso era <input na-me="mio" type="file" si-ze="40">):

listato_02<?php

echo "Nome del file: ".$_FILES['mio']['name']."<br>";

// esempio: “costruzione.gif”echo "Tipo di file:

".$_FILES['mio']['type']."<br>";// esempio: “image/gif”

echo "Dimensione del file:".$_FILES['mio']['size']."<br>";// esempio: 4783 bytes

echo "Nome temporaneo file: ".$_FILES['mio']['tmp_name']."<br>";// esempio: “C:\winnt\temp\php22.tmp”

echo "Tipo di errore: ".$_FILES['mio']['error']."<br>";// esempio: “0”

?>

Il valore “0” di $_FILES['mio']['error'] indica che il ca-ricamento in memoria è avve-nuto in maniera corretta (vedi icodici risultanti dall’interroga-zione più avanti nell’articolo).In questo momento il file è an-cora nella memoria tempora-nea; per effettuare fisicamentel'upload utilizziamo una funzio-ne che si occupa di spostare unfile caricato in memoria nellasua destinazione finale:

move_uploaded_file (file_caricato,destinazione);

Questa funzione restituiscetrue solo se l'operazione va abuon fine, quindi è necessarioche il file sia correttamente ca-ricato e (fondamentale) che ladestinazione sia una cartellacui siamo abilitati in scrittura(in caso di dubbio chiedere alprovider se e quali sono le car-telle cui si è abilitati in scrittu-ra volendo caricare un file daform Web).

L'esempio completo lo pote-

te vedere nella paginafile_upload.php (listato 03) e leinformazioni restituite sono vi-sibili nell'immagine 1; la cartel-la di destinazione scelta è“upload/” e il percorso è indi-cato in modo relativo. Termi-nata l'operazione il file tempo-raneo sarà cancellato dalla me-moria.

Attenzione: move_uploded_file sovrascrive file esi-stenti senza chiedere alcunpermesso.

listato_03$dir="upload/".$_FILES['mio']['name'];if (move_uploaded_file($_FILES

['mio']['tmp_name'], $dir)) { echo "Il file è stato caricato con successo. Ecco le informazioni didebug:\n<pre>"; print_r($_FILES);

}

Non è difficile impostare deicontrolli basati sulla dimensio-ne del file o sul tipo: comeesempio potete studiare la pa-gina form_upload_txt.php (cari-ca i file passando attraverso fi-le_upload_txt.php) in cui è im-postato un controllo per con-sentire solo il caricamento di fi-le tipo testo.

Non sempre, però, il valorerestituito da $_FILES['file']['ty-pe'] è sufficiente per definire iltipo di file che si sta caricando,ed inoltre questo valore in al-cuni casi dipende, purtroppo,dal browser usato dall'utente.Per evitare problemi si può agi-re in modo da ricavare l'esten-sione del file (i tre ultimi carat-teri dopo il “.”), per poi con-frontarla con un vettore diestensioni “ammesse”.

L'esempio riportato inform_upload_check.php e fi-le_upload_check.php tiene con-to anche dei file con più esten-sioni (tipo “pippo.txt. php”)estraendone solo l'ultima(quella effettivamente valida) econfrontandola con le esten-sioni consentite (listato 04).

L'esempio è utile anche perconoscere due nuove funzioni:explode (trasforma in vettoreuna lista una volta definito unseparatore dei termini) e in_ar-ray (controlla se un valore èpresente in un vettore).

listato_04<?php

$nomi=explode('.',$_FILES['mio']['name']);

// il nome del file è stato divisoin più parti registrate nel vettore

$nomi. Il separatore è il punto.$estensione=$nomi[count($nomi)-1];

// estraggo l'ultimo valore del vettore: questa è l'estensione del file originale

$ammesse=array("jpg", "gif", "txt");// questo è il vettore con le

estensioni da me consentiteif (in_array($estensione,$ammesse)) {

// con in_array controllo se l'estensione del file rientra tra quelle ammesse

[...]

Ricordiamo che va assoluta-mente impedito il caricamentodi file con estensioni PHP dalmomento che tali file potreb-bero eseguire operazioni di-struttive all'interno del nostrospazio Web: non va mai dimen-ticato, infatti, come PHP sia an-che un potentissimo linguaggiodi scripting.

È possibile anche caricarepiù file contemporaneamenteutilizzando le caratteristichedei vettori per inserire le istru-zioni input da utilizzare:

<input name="mio[]" type="file">

Con qualche controllo nellapagina ricevente (se il codiceerrore è 0 allora il file in que-stione può essere caricato, al-trimenti significa che c'è un er-rore o che la casella di carica-mento è stata lasciata vuota) inostri file verranno caricati nel-la directory scelta.

Gli esempi citati sono nellepagine form_upload_plus.php efile_upload_plus.php, disponi-bili nel CD Guida.

I codici risultantidall'interrogazione$_FILES['nomeinput']['error'] significano:

0 => il file è stato caricatocorrettamente in memoria

1 => la dimensione del file eccede quanto stabilito nel php.ini

2 => la dimensione del file eccede quanto indicato nel form

3 => il file è stato caricatoparzialmente

selezionato nessun file nel form di upload

Informazioni di debug utili per l’upload di un file

1

Page 20: Corso di Php (fonte: PC OPEN)

PC Open Dicembre 2004108

3a lezione

Abbiamo già parzialmentevisto come lavorare coi fi-le e con le directory quan-

do abbiamo introdotto le fun-zioni basename, opendir ereaddir nelle lezioni preceden-ti, e lo stesso caricamento di fi-le appena visto è un altro esem-pio di utilizzo delle funzioni fi-lesystems di PHP. Abbiamo adisposizione numerosissimefunzioni pronte all'uso (sem-pre che si abbia la pazienza dileggere il manuale), sta solo anoi trovare la maniera miglioredi operare.

Nel paragrafo precedente,ad esempio, move_uploaded_file ha rivelato il difetto di so-vrascrivere, senza avvertire, ifile presenti nella cartella. Me-glio predisporre, quindi, uncontrollo in grado di verificarela presenza o meno di un certofile nella directory esaminata.La funzione è:

file_exists ($nome);// $nome comprende il percorsodi ricerca del file e il suo nome

Potremmo anche desiderarecancellare un file presente inuna cartella: in questo caso lafunzione da utilizzare è:

unlink ($nome);// $nome comprende il percorso di ricerca del file e il suo nome

Un esempio concreto è pre-sente nella pagina checkcanc.php, attraverso la quale si puòcontrollare se un file è presentenella cartella “upload” (edeventualmente cancellarlo)semplicemente compilando il

form. Potremmo migliorare l'e-sempio (paginacheckcan_plus.php) creando unform (vedi listato 05) con unacasella a discesa nella qualesiano presenti tutti i file dellacartella “upload”: selezionan-done uno possiamo decidere dicancellarlo o di vederne alcunecaratteristiche con la funzionepathinfo (immagine 2).

Vedendo il listato originale,noterete che sono state usate@opendir e @unlink: nel prossi-mo paragrafo vedremo a cosaserve la @ davanti al nome diuna funzione.

PHP consente di lavorarenon solo con i file, ma anche“sui” file: possiamo, infatti,aprire e modificare i file scri-vendo informazioni al loro in-terno. Per questi scopi si usanouna serie di funzioni specifi-che:

$handle=fopen ($nome, mode);// il descrittore $handle apre,tramite la funzione fopen, un file in

lettura e/o scrittura, posizionando ilpuntatore all'inizio o alla fine del file.Usando un sistema windows èmeglio usare sempre l'opzioneaggiuntiva “t” come “mode” per i filetesto e “b” per i file binari.

fread ($handle, length);// legge il contenuto di un fileaperto dal descrittore $handle. Selength non è settato, il file vieneletto fino alla fine.

fwrite ($handle, $content);// scrive $content sul file aperto daldescrittore $handle

fclose ($handle);// chiude il file aperto daldescrittore $handle

Con poche nozioni siamo ingrado di creare un paio diesempi interessanti. Supponia-mo di avere nel nostro sito unapagina di link (immagine 3) e divoler sapere quali sono effetti-vamente cliccati e quante vol-te. Per avere queste informa-zioni può essere sufficientescrivere su un file di testo dellerighe che contengano l'indica-

zione del link e le informazionisul giorno e l'ora del clic: que-sto file potrà poi essere editatocon un foglio elettronico per ri-cavarne delle statistiche.

Il sorgente della paginalink.php ci mostra come otte-nere questo risultato. Per pri-ma cosa impostiamo la sezioneHTML: non ci sono difficoltà,salvo l'accortezza di indicareogni link in questo modo:

<a href="link.php?url=http://www.pcopen.it">PC Open</a><p>

// link.php è la pagina dove citroviamo. L'url del link viene quiassegnato alla variabile$_GET['url']

La sezione PHP (in testa alcodice sorgente della paginalink.php) contiene il codice checonsente di scrivere nel file (li-stato_06). Per prima cosa vienecontrollato che esista$_GET['url'], il che vuol direche qualcuno ha cliccato suuno dei link. Poi viene assegna-to un nome al file di testo doveverranno registrati i dati per lestatistiche: scegliamo di dargliun nome del tipo “annosetti-mana.txt”, in modo da avere fi-le separati per ogni settimana(usiamo le funzioni di data giàviste nella lezione 1). Il succes-sivo ciclo if si occupa di defini-re il descrittore $file e di aprire(eventualmente creare) il fileannosettimana.txt, posizionan-do il puntatore di scrittura altermine del testo già inserito.Mi occupo poi di definire la rigada scrivere, inserendo il per-corso del link, una tabulazione(“\t”), la data e l'ora del click e,

3 Lavorare con i file

Form per ricavare informazioni su un file e per cancellarlo

2

Con PHP possiamo individuare i link più cliccati di una pagina

3

listato 05<select name="nome" size="1"><option></option><?php

$cartella=@opendir('upload');while (false !== ($file = readdir($cartella))) {

$lista[]=$file;}$lista=array_slice($lista,2);

// array_slice lo uso per eliminare le indicazioni . e .. presenti in readdir. È un sistema più veloce per compiere la stessa operazione vista nella prima lezione

foreach ($lista as $nomi) {echo "<option>".$nomi."</option>";

}?></select>

Page 21: Corso di Php (fonte: PC OPEN)

PC Open Dicembre 2004109

3a lezione

per ultimo, l'indicazione di fineriga (“\n”).

Ora non ci resta che scriverela riga con fwrite, chiudere il fi-le con fclose e indirizzare il no-stro utente (in maniera del tut-to trasparente per lui) verso illink cliccato.

Il file di testo ottenuto saràdel tipo visibile in immagine 4.Adesso siamo in grado, con po-che modifiche al file originale,di aggiungere a piacere tuttauna serie di informazioni comeil browser del visitatore e il suoindirizzo remoto. E adesso nonci resta che analizzare il nostrofile settimanale delle statisti-che dei link.

Certo questo è un buon si-stema, ma non è ottimale e in-fatti si presta a piccole “mano-missioni” esterne: ad esempiosi può aggiungere una riga al fi-le di testo anche senza cliccaresu nessun link, semplicementescrivendo un URL del tipo

http://127.0.0.1/lezione_3/link.php?url=http://www.linux.org// scrive nel file di testo un link noncompreso nella pagina originale

Bisognerebbe dunque pre-vedere dei controlli di inte-grità, e senza dubbio un lavoromigliore lo si otterrebbe regi-strando i dati in un database.Ma questo lo impareremo nelleprossime lezioni; l'importantein questo frangente era solo di-mostrare come non sia troppodifficile lavorare sui file conPHP.

Il secondo esempio (pagina“contatore.php”) consente dicreare un rudimentale contato-re per le nostre pagine (imma-gine 5), mantenendo memoriz-zato il valore nel file di testo“conteggio.txt”.

Rispetto all'esempio prece-dente, in questo caso dobbia-mo prima leggere il contenutodel file conteggio.txt, asse-

gnando il valore ad una varia-bile. Quindi, chiuso il file (èbuona norma tenere i file aper-ti il meno possibile), incremen-tiamo il valore trovato e riscri-viamo il file con questo nuovovalore. Queste nuove operazio-ni sono riportate nel listato 07.Ogni volta che la pagina conta-tore.php verrà caricata vedre-mo aumentare di una unità ilvalore visualizzato.

Lavorare coi file può non es-sere sempre facile, ma abbia-

mo visto che possono rivelarsiestremamente utili anche se,per le loro caratteristiche, nonpossono sostituire i database.Come al solito, per approfondi-re e conoscere tutte le funzionifilesystems di PHP bisogna leg-gere l'ottimo manuale diPHP.net; questo anche per evi-tare, magari chiedendo aiuto inun newsgroup, di sentirsi ri-spondere con l'acronimoRTFM, ossia “Read the f... ma-nual!”.

Il file testo ottenuto indica quali link risultano più visitati

4

Un semplice contatore delle visite della pagina

5

listato 06<?php

if (isset($_GET['url'])) {$nome_file = date("YW").".txt";

// il file che verrà creato è del tipo annosettimana.txt,if ($file=fopen($nome_file, 'at')) {

// apro il file o lo creo. $file è il "descrittore"; il mode "a" servea posizionare il puntatore alla fine del file, il mode "t" serve per la modalità testo per Windows$ins = $_GET['url']."\t";$ins.= date('d/m/Y H:i')."\n";fwrite($file, $ins);

// scrivo la stringa $ins passando alla funzione fwrite il descrittore fclose($file);// chiudo il file passando alla funzione fclose il descrittore

}header("Location: ".$_GET['url']);// indirizzo l'utente al link su cui aveva cliccato

}?>

listato 07$conteggio= fread($file,filesize($visite));// assegno a $conteggio il valore che leggo nel file di testo (dove c'è solo un numero)fclose($file);$conteggio++;// incremento il contatore$file = fopen($visite,"w"); fputs ($file,$conteggio);// scrivo il nuovo valore sul file eliminando il precedente

4 La gestione degli errori

Scrivendo del codice èsempre possibile farequalche errore. Si può in-

trodurre nella sintassi qualchecostrutto errato o si possonoeseguire operazioni proibite obloccate dalle regole che le de-finiscono. Esempi possono es-sere: cercare di dividere un nu-mero per zero, oppure chiama-re una funzione con un nomeinesistente o includere un fileesterno non presente.

In tutti questi casi PHP civiene in aiuto con una serie dimessaggi di errore che spessoci consentono di capire al volocosa c'è di sbagliato nel codice.L'esempio errori.php genera imessaggi visibili in immagine 6:

Abbiamo ottenuto come ri-sultato tre avvertimenti (war-ning) e un errore grave (fatalerror). La differenza risiede nelfatto che un warning non bloc-ca la lettura della pagina, men-

tre un fatal error ne causa l'im-mediata interruzione e quindiimpedisce la lettura del codicesuccessivo (la pagina errori.php dovrebbe mostrare una ri-ga di testo alla fine).

Leggendo con attenzione ilreporting di PHP, possiamotrarre i necessari suggerimentiper correggere il nostro codice,eliminando quindi il divisorezero, creando il file pippo.txtnella cartella upload e infine

definendo la funzione somma.Questo debug è stato utile pernoi programmatori, ma potreb-be essere fonte di problemi sevenisse visto dai visitatori diquesta pagina, oltre alla bruttafigura che faremmo: l'utente,infatti, vedrebbe informazionisui listati e sulle pagine, non-ché nome e indirizzo di un fileda includere (con qualche in-tuizione, potrebbe tentare diaccedere direttamente ai file

Page 22: Corso di Php (fonte: PC OPEN)

Sicurezza è un concettoampio che coinvolge mol-teplici aspetti: i dati sul si-

stema e i dati in transito, i pro-tocolli, il server hardware, ilWeb server software, le appli-cazioni Web e le persone. Tuttiquesti aspetti sono correlati, ebasta una falla in un qualsiasipunto per rendere “insicuro”tutto il sistema.

Non è questa la sede per ad-dentrarci in disquisizioni sullepolitiche di sicurezza da adot-tare, né avrebbe senso parlaredella sicurezza server-side diApache e PHP, argomenti suiquali spesso non abbiamo con-trollo diretto e che lasciamo

agli amministratori di sistemi.Nel nostro piccolo, invece,

possiamo dedicare qualchesforzo all'evitare errori banalidi programmazione, cercandodi fare quindi la nostra partenella catena della sicurezza.Sono piccoli accorgimenti ine-renti quanto abbiamo visto inqueste puntate e di cui magariabbiamo già parlato, ma è benerichiamarli per concludereadeguatamente il discorso suPHP.

Come base di tutto, faccia-mo attenzione a cosa inseria-mo nella Web root: teniamo idati sensibili in cartelle diver-se, magari adeguatamente pro-

tette impostando i permessi,ed evitiamo anche di lasciarenella root pagine come la ph-pinfo.php che può dare infor-mazioni importanti ad un po-tenziale attaccante.

La prima accortezza, poi,consiste nel non usare mai, an-che se il settaggio di php.ini loconsentisse, gli short tag <? e?> o gli asp tag <% e %> per in-dicare al browser l'inizio delcodice PHP. Un cambio di set-taggio, infatti, renderebbe il co-dice visibile a tutti (magari in-sieme a password e parametridi connessione), oltre a impe-dire la corretta visualizzazionedelle pagine Web. Usiamo quin-

di sempre i tag standard <?phpe ?>.

Seconda accortezza: quan-do viene incluso un file (con in-clude o require) in una paginaWeb, teniamo presente chequesto file esiste fisicamentenel nostro spazio ed è accessi-bile direttamente col browserse si conosce l'indirizzo remo-to. Dal momento che gli includesono spesso usati per registra-re dati importanti, funzioni eclassi, bisogna impedirne la vi-sualizzazione diretta. Ricordia-moci, quindi, di salvare il filecon estensione finale .php,usando poi i tag php nel modoappropriato.

della cartella upload). Peggioancora, potremmo dare indica-zioni sull'indirizzo e sul nomeutente del server su cui risiedeil nostro database (lo vedremonelle prossime lezioni).

Bisogna quindi porre atten-zione alla gestione degli errori:la prima cosa da conoscere è ilsettaggio del php.ini, settaggiovisibile, al solito, tramite la pa-gina phpinfo.php (vedi primalezione). Probabilmente trove-remo:

error_reporting = 2039 (ossia tutti i messaggi di erroresono visualizzati tranne alcuniwarning che non sono consideraticomunque errati)

display_errors = Onlog_errors = Off

Questo settaggio indica chetutti gli errori verranno visua-lizzati e non saranno registratiin un file di log. Se siamo uten-ti remoti c'è solo da tenere inconsiderazione questo fatto,mentre se siamo “padroni” delnostro server andrebbe presain considerazione l'ipotesi diinibire la visualizzazione deimessaggi di errore consenten-done, al contempo, la registra-zione in un file di log. Dal mo-mento, però, che la situazionestandard è la prima (sul serverremoto non abbiamo alcun po-tere), vediamo cosa possiamofare per gestire al meglio gli er-rori.

Un intervento drastico èquello di impedire la visualiz-

zazione di tutti i messaggi di er-rore che potessero manifestar-si in una pagina inserendo, al-l'inizio del codice:

<?phperror_reporting (E_NONE);

// oppure error_reporting(0);// controllate sul manuale le opzionidi error_reporting per poterscegliere di visualizzare solo certierrori, tipo E_ERROR,E_WARNING,...

?>

Provate, come verifica, a ca-ricare la pagina errori_no.php,dopo aver controllato che il co-dice sorgente sia lo stesso del-la pagina errori.php: non verràvisualizzato nulla.

Questo, però, è un rimediodrastico, mentre PHP ci con-sente di usare anche delle so-luzioni puntuali. Una sfrutta l'o-peratore di controllo errori “at”(@): la famosa chiocciolina @davanti ad una espressionePHP impedisce l'eventuale vi-sualizzazione di un messaggiodi errore (pagina errori_at.php):

$b=0;$c = @ ($a/$b);

// non viene visualizzato il warningche ci aspetteremmo per averediviso un numero per zero

@ funziona solo quando sitrova davanti ad un'espressio-ne che deve restituire un risul-tato, quindi va bene per chia-mate di funzioni e include, ma

non davanti a cicli condiziona-li come if o foreach. Su unesempio del paragrafo prece-dente si era usata @ davanti al-l'istruzione unlink per impedireche venisse visualizzato unwarning se si tentava di can-cellare un file non presente nel-la cartella: per lo scopo dell'e-sempio, infatti, il non trovare ilfile non era da considerarsi unerrore e quindi non dovevacomparire alcun messaggio.

Nel caso di uno script (adesempio l’apertura di un file oconnessione a un database),accanto ad @ si può usare il co-strutto die (alias di exit) perbloccare il codice nel punto incui lo script fallisce (pagina er-rori_die.php):

$file = '/upload/pippo.txt';$apri = @fopen($file, 'r') ordie("<h3>Non è stato possibile aprireil file $file</h3>");

In questo esempio, la @ im-pedisce la visualizzazione delmessaggio di warning, poi il co-dice, fallita la chiamata a fopen,è bloccato da die.

Alcuni errori, invece, li pos-siamo evitare sfruttando ade-guatamente il codice. È perciòbuona abitudine utilizzare deicicli if insieme alle funzioni fi-le_exists, function_exists emethod_exists, per accertarsiche file, funzioni e metodi delleclassi cui facciamo riferimentoesistano realmente nel proget-to che stiamo sviluppando.

PC Open Dicembre 2004110

3a lezione

5 I consigli per rendere il sito (più) sicuro

In questa schermata sono raccolti alcuni errori in PHP

6

Page 23: Corso di Php (fonte: PC OPEN)

PC Open Dicembre 2004111

3a lezione

6 I database

Anche i messaggi di errorepossono causare falle nella si-curezza, quindi, oltre a con-trollare attentamente il codicescritto, si può disabilitare la vi-sualizzazione dei messaggi nel-le pagine caricate sullo spazioWeb.

L'operazione di upload di fi-le può essere pericolosissimase si lascia l'utente libero di ca-ricare qualsiasi tipo di file, ma-gari contenenti script PHP ingrado potenzialmente di can-cellare tutto il nostro lavoro.Essenziale, quindi, è porre uncontrollo sul tipo di file che èpossibile uploadare e sulle car-telle dove permettiamo il cari-camento.

Attenzione va posta ai form:in alcune circostanze abbiamobisogno di passare alcuni valo-ri “nascosti” e li inseriamo coltype=”hidden” in un'istruzioneinput. Ricordiamoci che questivalori sono perfettamente visi-bili a tutti: basta semplicemen-te visualizzare il codice sor-gente HTML della pagina. Altroaspetto importante è control-lare cosa viene inserito neicampi del form, validando sem-pre i dati. Immaginate, adesempio, di avere creato unform per consentire la cancel-lazione di record da un databa-se. Cosa succederebbe se un

utente inserisse il carattere jol-ly del linguaggio di interroga-zione “%”? Senza un controllodi validazione, il risultato finalesarebbe la cancellazione di tut-ti i record.

Le sessioni hanno un nomeidentificativo predefinito: PH-PSESSID. A questo nome si faspesso riferimento per propa-gare l'id di sessione o per regi-strarlo su un cookie. Sarebbemeglio, però, che il nome dellasessione lo assegnassimo noi:cosa succederebbe, infatti, seun domani venisse cambiatonel php.ini questo valore pre-definito? Il nostro codice nonfunzionerebbe più come ave-vamo previsto.

L'ultima raccomandazione fariferimento al settaggio regi-ster_globals di php.ini. Fino allaversione 4.2 il valore di defaultera On e questo consentiva diregistrare le variabili col loronome, indipendentemente dal-l'input. In pratica, una variabile$nome presente in una paginapoteva derivare da un input ditipo get come da un input di ti-po post o da un cookie o da unasessione.

Questo causava problemi divulnerabilità, quindi il settag-gio di register_globals è statoposto a Off e per riferirsi allevariabili si devono usare gli ar-

ray superglobali $_POST[],$_GET[], $_SESSION[] e$_COOKIE[]. In questo modo sipuò distinguere, ad esempio,$_GET['nome'] da $_SES-SION['nome'], dove il primo va-lore deriva dall'URL della pagi-na mentre il secondo deriva dauna sessione inizializzata, e alcontempo non è definita nes-suna variabile globale $nome.

Anche se il vostro provideravesse mantenuto il valore diregister_globals a On, è impor-tante comunque usare sempree solo gli array superglobaliper non incappare nel proble-ma visibile nella pagina vulne-rabile.php: poniamo che in que-sta pagina venga fatto un con-trollo su una variabile $autenti-cato definita da un cookie. Secarichiamo la pagina veniamobloccati (non abbiamo uncookie nella nostra memoriadove sia definita la variabile),ma possiamo bypassare il con-

trollo semplicemente scriven-do sul browser l'URL in questomodo: vulnerabile.php?autenti-cato=1 (immagine 7). Se inveceil controllo fosse stato su$_COOKIE['autenticato'] nonavremmo potuto fare nulla (ve-dere vulnerabile_no.php). Chia-ramente se register_globals fos-se stato Off anche il primo me-todo non avrebbe più funzio-nato.

Con questi consigli il mini-corso di PHP come strumentostand-alone si è concluso eadesso tocca ad ognuno ap-profondire la conoscenza diquesto potentissimo linguag-gio. Nelle prossime puntate ve-dremo, invece, come interfac-ciare PHP con un database inmodo da aumentare considere-volmente le nostre azioni diwebdeveloper. Ma per far que-sto dobbiamo capire bene cosasono le basi di dati, come ve-diamo di seguito.

Le tecnologie basate sui da-tabase (letteralmente “rac-colte di dati”) giocano un

ruolo critico in tutte le aree fon-damentali della nostra vita:pensiamo, ad esempio, all'usodi database per consentire lagestione del nostro conto inbanca, per prenotare delle visi-te in ospedale, per verificare gliesami effettuati all'università,per la gestione delle aziende(coi software ERP) e via dicen-do.

Ne sentiamo tanto parlare,ma cos'è realmente un databa-se? Volendo semplificare almassimo la definizione, possia-mo vederlo come una collezio-ne di dati tra loro correlati, do-ve per “dati” intendiamo dei va-lori conosciuti che possono es-sere registrati e hanno un signi-ficato implicito. Da questo pun-to di vista un'agenda personale

è certamente un database, inquanto è una collezione di datiaventi un significato implicito(nome, indirizzo, telefono) e traloro correlati. Anche la paginadi un libro, però, potrebbe es-sere vista come un database inquanto rappresenta una colle-zione di parole tra loro collega-te. Così non è, dal momentoche un database è consideratotale quando ha queste pro-prietà:• rappresenta uno o più aspettidel mondo reale (il cosiddetto“minimondo”);• è una collezione di dati logi-camente coerenti tra loro e coe-renti con la descrizione dellarealtà scelta (non è, quindi, uninsieme di dati messi a caso);• è disegnato, costruito e po-polato per un certo gruppo diutenti interessati ad interagirecon esso compiendo determi-

nate azioni (inserimento, recu-pero, aggiornamento, cancella-zione dati). Un libro, quindi,non è un database, mentre lo èun dizionario.

Un database può contenerepiù o meno dati ed essere più omeno complesso: pensiamo, adesempio, alla nostra agenda te-lefonica e alla banca dati di ungestore di telefonia. Una base didati potrebbe essere gestita an-che manualmente, ma all'au-mentare della complessitàavremo bisogno di un supportotecnologico e informatico percostruire ed utilizzare il DB, enel contesto di questo corso glistrumenti scelti sono il databa-se MySQL e PHP. Dal punto divista informatico un database èassimilabile ad una tabella tipofoglio elettronico, con i distin-guo che vedremo in un para-grafo successivo.

Il database systemLa rappresentazione grafica

un ambiente di sviluppo “mo-derno” di un database è visibilein figura 8. A valle, memorizzatoin un qualsivoglia mezzo elet-tronico, c'è il database fisica-mente esistente, composto daidati e dalle informazioni sullasua stessa struttura (meta-da-ti).

Per creare il DB, accedervi einterrogarlo utilizzeremo unDBMS (DataBase ManagementSystems), ossia un'applicazio-ne in grado di processare dellerichieste e di accedere ai dati inscrittura e lettura. MySQL è unDBMS, come lo sono anche Mi-crosoft Access e SQL Server,PostgreSQL, Oracle e moltissi-mi altri programmi.

Per utilizzare il DBMS, infine,servirà un'applicazione in gra-do di inviare una richiesta: po-

Un problema di vulnerabilità facilmente evitabile

7

Page 24: Corso di Php (fonte: PC OPEN)

PC Open Dicembre 2004113

3a lezione

trebbe essere un'interfacciadello stesso DBMS, ma può es-sere anche un software o un lin-guaggio esterno come PHP oASP. Tutte le parti qui descrittevanno a formare il database sy-stem, ossia l'insieme di softwa-re, interfacce, applicazioni cheservono all'utente per interagi-re totalmente con una base didati.

Il DBMS è il componente fon-damentale del sistema perchéconsente di gestire i processi didefinizione, costruzione e ma-nipolazione della base di dati.

Definire un database signifi-ca specificare il tipo, la struttu-ra e i vincoli dei dati che saran-no memorizzati, mentre co-struire il DB implica il processodi registrazione dei dati sul“mezzo” controllato dal DBMS.Manipolare la base di dati si-gnifica, infine, creare le interro-gazioni in grado di recuperare,aggiornare e cancellare i dati(riflettendo le variazioni del“minimondo” rappresentatodal database), nonché di gene-rare dei report (a video o astampa).

Fatte queste debite premes-

se, però, torniamo al nostrocorso. Ci serve un database?Cosa ci consente di fare rispet-to alle nostre esigenze di Web

developer? Quali vantaggi ciporta? Capito questo dovremoaffrontare la costruzione ex no-vo di un DB (un po' di teoria

sarà necessaria per eseguire illavoro nella maniera più effi-ciente) e imparare ad interro-garlo.

Programmatori e utenti

Programmi applicativi e query

Software per elaborazione programmi e query

L’”ambiente” globale di sviluppo di un database

Software per l’accesso ai dati

Databasesystem

DBMS(DatabaseManagementSystem)

Struttura(meta-dati) Dati

7 Siti Web dinamici

Alla base della creazione diun sito Web sta la fonda-mentale attività della pro-

gettazione, il momento in cui lerichieste e le idee del commit-tente devono essere esplicita-te, e spesso “tradotte” in un lin-guaggio concreto, in una seriedi punti programmatici.

Chi ci affida il lavoro, infatti,ha ben chiaro (o dovrebbeaverlo) il contenuto del mes-saggio da comunicare, il mododi comunicarlo e il target cui ri-volgersi, ma probabilmentenon ha mai pensato ai retro-scena di questi aspetti per ilpresente e il futuro.

Chi crea i testi? Con qualecadenza potrei doverli cambia-re? Se cambio un testo, qualesarà la procedura per il nuovoinserimento? È possibile/pro-babile avere esigenze di am-pliamento dei menu del sito?Se ci sono delle news chi le in-serisce? Ogni modifica cosacomporta? Chi fa la gestione?

Queste sono solo alcune do-mande che ci si deve porre. Al-

cune riguardano solo il com-mittente, ma quasi certamentela risposta a queste domanderiguarderà poi noi.

Ricordiamoci, e lo insegnaogni settore dell'economia, cheè meglio “spendere” tempo infase di progettazione (quando icosti della modifica sono bas-si) piuttosto di accorgersi in fa-se avanzata che si potevanopercorrere strade alternative: aquesto punto fare delle modifi-che diventerebbe molto costo-so perché tante decisioni distruttura sarebbero ormai ulti-mate. Il costo della modifica èchiaramente massimo quandoil progetto è realizzato. Il com-mittente potremmo anche es-sere noi stessi e la validità diquanto scritto sopra restereb-be immutata.

Prendiamo come esempioun caso concreto: supponiamodi aver realizzato un sito aven-te lo scopo di essere la “vetri-na” dei prodotti di un artigianoe di aver pattuito un compensoper un anno di aggiornamento

delle pagine da effettuare quan-do il nostro cliente volesseesporre nuovi prodotti.

Se non abbiamo esplicitatobene il significato di questo ag-giornamento, potremmo tro-varci due problemi, opposti maugualmente potenzialmentegravi: dover fare troppi aggior-namenti, o doverne fare unosolo dopo molti mesi. Nel pri-mo caso il problema per noi èdover continuamente prenderein mano il codice HTML, modi-ficare le pagine e ricaricarlenello spazio Web; nel secondocaso dovremmo riguardare delcodice scritto mesi prima, rie-saminando il progetto (che ma-gari ha condotto un nostro col-laboratore che non lavora piùper noi) e facendo infine l'ago-gnato aggiornamento. In en-trambi i casi il rischio che il co-sto del tempo utilizzato nonsia stato coperto dal prezzopattuito col cliente è alto.

Quale sarebbe potuta essereuna soluzione migliore? Utiliz-zare un DBMS per creare un da-

tabase contenente gli oggettidell'artigiano da cui estrarre idati da visualizzare sulla pagi-na Web.

In questo modo ogni modifi-ca/aggiunta/cancellazione aiprodotti andrebbe fatta diret-tamente sul database (un'ope-razione, come vedremo pre-sentando il linguaggio SQL,molto facile e per la quale po-tremmo preparare un'interfac-cia grafica, ad esempio conPHP) ed automaticamente lapagina Web sarebbe aggiorna-ta. Certo questo sistema di la-voro ci “costerebbe” di più infase realizzativa, ma ne benefi-ceremmo in seguito. Anzi, po-tremmo addirittura proporre alcliente, in cambio di un prezzomaggiore di realizzazione delsito, di fare lui stesso questeoperazioni di modifica dando-gli così anche una libertà gene-ralmente molto apprezzata.

Potremmo stabilire dellearee nelle quali riservare alcliente l'aggiornamento (noti-zie, domande e risposte, comu-

8

Page 25: Corso di Php (fonte: PC OPEN)

PC Open Dicembre 2004114

3a lezione

nicati e via dicendo) e mante-nere per noi, invece, l'aggior-namento delle altre. Insomma,un sistema di gestione a data-base può consentirci, pur pa-gando il prezzo di una proget-tazione più onerosa, di separa-re fisicamente il concepimentodella pagina (template) dal suoriempimento, rendendo que-st'ultima un'operazione piùsemplice e veloce in caso di ag-giornamenti.

Ci sono poi i casi in cui uti-lizzare dei database è assoluta-mente necessario perché lamole di dati e l'utilizzo che sene fa renderebbe impossibile lagestione di pagine “statiche”.Un esempio, che poi useremoper costruire da zero un DB,possono essere le pagine di unateneo che voglia mettere ipropri studenti in grado di ac-cedere alla lista degli esami fat-

ti con la relativa votazione. Èchiaro come non sia neppureconcepibile pensare di crearetante pagine “statiche” (tutteprotette da password) quantisono gli studenti immatricolati,vuoi per esigenze di spazio(forse il problema minore) vuoiper tutte le implicazioni di ag-giornamento che la scelta com-porterebbe. In questo caso,quindi, l'unica soluzione è crea-re il template della pagina “esa-mi”; la pagina verrà poi dina-micamente riempita con i datidello studente che effettua larichiesta di visualizzazione delsuo piano studi. I dati sarannoospitati in un database costan-temente aggiornato in manieraveloce ed economica. La strut-tura dell'interrogazione e dellarisposta è visibile schematica-mente in figura 9. Questa ge-stione porta anche un altro

vantaggio: eventuali modifichedi layout della pagina sono ese-guite, una sola volta, esclusiva-mente sul template e immedia-tamente sono attive per ogni ri-chiesta di pagina.

La stessa strutturazione latroviamo nei siti di homebanking, in quelli di commercioelettronico, nei siti Web edito-riale e l'elenco potrebbe conti-nuare a lungo.

8 Teoria dei database

La richiesta di una pagina gestita da un database da parte degli utenti A e B(tra parentesi l'ordine delle operazioni)

Avendo deciso di sfruttare ivantaggi offerti dalle basidi dati per il nostro sito, ci

troviamo adesso nella neces-sità di creare un DB efficiente.Fondamentale, ai nostri fini, èche il database non abbia infor-mazioni ridondanti (ossia nonabbia duplicazioni di dati) per-ché questo comporterebbespreco di memoria, minore effi-cienza del sistema e la probabi-le introduzione di inconsisten-ze e/o perdite di dati.

Per ottenere questo risultatosi compiono delle operazionidi modellizzazione allo scopodi esplicitare la struttura finaledel DB che andrà creata colDBMS scelto. Questo primopasso, da fare anche con cartae penna, è forse il più noioso,ma è assolutamente importan-te e vale quanto detto in prece-denza: meglio dedicare moltotempo alle fasi progettuali piut-tosto di accorgersi alla fine del-la necessità di modificare lastruttura per renderla più effi-ciente.

Come esempio di lavoro vo-gliamo creare lo schema di undatabase il cui scopo è memo-rizzare i dati degli studenti uni-versitari: in particolare ci inte-ressa conoscere la situazionedegli esami svolti, quindi do-vremo registrare dati relativi

agli studenti, dati relativi ai cor-si ed agli esami e dati relativi aiprofessori.

Il primo passo è realizzare loschema concettuale: è unoschema non utilizzabile diretta-mente dal DBMS, ma fornisceconcetti vicini a quelli utilizzatida una persona nel percepire econcettualizzare la realtà og-getto di studio (il minimondo).Useremo, data la sua diffusionee la sua intuitività, il modelloEntità-Relazione proposto daP. Chen nel 1976 (la figura 10riassume come rappresentaregraficamente lo schema con-cettuale). Questo modello uti-lizza come base il costrutto En-tità: rappresenta un oggettodella realtà che, ai fini dell'ap-plicazione di interesse, ha unapropria identità (è “distinguibi-le” dagli altri oggetti) ed ha unaesistenza fisica (es: studente,professore) o concettuale (es:corso, piano di studi). Ogni en-tità è messa in relazione con al-tre entità, da cui il nome delloschema, allo scopo di definirnele reciproche corrispondenze.L'entità è accompagnata da unaserie di attributi che ne descri-vono le proprietà elementari(es: matricola, nome, data, vo-to), ed uno di questi attributi (ola combinazione di due o più)deve definire univocamente i

dati registrati nell'entità (l'i-stanza). Ciò significa che non cipotranno essere due istanzecon lo stesso valore: questo at-tributo è detto chiave. Ancheuna relazione può conteneredegli attributi.

Ultimo sforzo è definire il vin-colo di relazione tra due entità,vincolo classificabile con una diqueste tipologie:• 1:1 (uno-a-uno; one-to-one):ad ogni istanza di E1 corrispon-de (può corrispondere) una eduna sola istanza di E2 e vice-versa;• 1:N (uno-a-molti: one-to-many): ad ogni istanza di E1corrispondono (possono corri-spondere) più istanze di E2,mentre ad ogni istanza di E2corrisponde (può corrisponde-re) una sola istanza di E1;• N:N (molti-a-molti; many-to-many): ad ogni istanza di E1 o

di E2 corrispondono (possonocorrispondere) più istanze del-l'altra entità coinvolta.

Un esempio, con la rappre-sentazione dei tipi di relazionee degli attributi, è visibile inve-ce in figura 11. Le entità coin-volte sono quattro (studente,piano studi, corso, professore)ed esemplificano i tre vincoli direlazioni previste:• studente - inserisce - pianostudi = relazione 1:1 -> ogni stu-dente deve inserire un solo pia-no di studi, e ogni piano di stu-di deve essere riferito ad un so-lo studente. In questo esempioabbiamo assunto che non visiano piani di studi standard trai quali uno studente possa sce-gliere (la relazione sarebbe sta-ta 1:N)• studente - fa la tesi con - pro-fessore: relazione 1:N -> ognistudente può (se ha concluso

Lo schema concettuale: modello Entità-Relazione

9

10

Page 26: Corso di Php (fonte: PC OPEN)

PC Open Dicembre 2004115

3a lezione

gli esami) fare la tesi con un so-lo professore (il relatore ufficia-le), mentre ogni professore puòavere N tesisti.• studente - fa esami del - corso:relazione N:N -> ogni studentepuò dare gli esami di N corsi, edogni corso può essere oggettodi esami da parte di N studenti.

Terminato lo schema concet-tuale, per creare fisicamente ilDB dobbiamo passare allo sche-ma logico il quale sarà imple-mentabile direttamente nelDBMS. Vi sono vari tipi di sche-ma, ma il miglior compromessotra qualità e semplicità è datodal modello relazionale propo-sto da E. Codd (primi anni '70).Il modello si basa, semplice-mente, su un unico costruttodetto relazione. Questa relazio-ne è una tabella (useremo daadesso questo termine per noningenerare confusione con loschema concettuale) con le se-guenti caratteristiche (figura12):• un numero prestabilito di co-lonne (detti anche campi o at-tributi) di cui va stabilito il tipodi valori (testo, numerico, ecc)e il loro eventuale dominio;• un numero variabile di righe(dette anche record o tuple oistanze);• uno o più campi formerannola chiave primaria della tabella,il cui valore identificherà uni-vocamente un record.In linea di massima si potrebbeanche pensare di costruire unDB con una sola grandissimatabella, ma questo manifeste-rebbe immediatamente proble-mi di ridondanze e anomalie. Ilmodello di Codd, per evitarequesto, si basa sulla teoria ma-tematica dei sistemi e per ga-rantire l'integrità e le coerenzadei dati vi sono delle regoleaventi lo scopo di creare N ta-belle, più piccole possibili, damettere in collegamento tra lo-ro attraverso i valori delle chia-vi. Per passare dallo schemaconcettuale a quello logico siusa un algoritmo di “traduzio-ne” (mapping):• per ogni relazione 1:1 si crea-no due tabelle corrispondentialle entità coinvolte. Tra i cam-pi di una delle due tabelle si ac-clude, come chiave esterna, lachiave dell'altra tabella;• Per ogni relazione 1:N si crea-no due tabelle corrispondentialle entità coinvolte. Tra i cam-pi della tabella del ramo N si ac-clude, come chiave esterna, lachiave della tabella del ramo 1;

• per ogni relazione N:N si crea-no tre tabelle corrispondentialle due entità coinvolte ed allarelazione che intercorre tra lo-ro. Quest'ultima tabella avrà co-me chiave primaria la combi-nazione delle chiavi delle altredue tabelle.

Lo schema che ne esce è vi-sibile in figura 13. L'ultimo sfor-zo prima di avere uno schemaefficiente si chiama normaliz-zazione: è un procedimento, inpiù fasi, che interviene sullastruttura delle tabelle di un da-tabase e sui collegamenti tra es-se. La trattazione approfonditadel tema esula dal presente cor-so, ma vale la pena accennare atre consigli previsti dalle FormeNormali.

Il primo prevede di usare intutte le tabelle attributi univoci(non ripetuti) e semplici (noncomposti). Questo vuol direche un'ipotetica tabella “stu-denti” non deve mai compren-dere una serie di colonne del ti-po Esame1, Esame2... EsameN(l'attributo è sempre Esame, enon va mai ripetuto), né devecomprendere un campo Esamese all'interno di questo voglioregistrare più di un dato (es: co-dice esame, votazione, data,professore). In entrambi i casiva prevista la creazione di unatabella da legare a quella stu-denti: in effetti è quello che ab-biamo fatto nel nostro esempio.

Il secondo consiglio è dicreare una nuova tabella cui fa-re riferimento se siamo costret-ti ad inserire continuamente va-lori ripetuti. Un esempio banalepotrebbe essere il dipartimentodi appartenenza di un profes-sore: a forza di inserire il nomedel dipartimento rischiamo dicommettere errori di digitazio-ne pregiudicando ricerche fu-ture, e inoltre se un diparti-mento cambiasse nome do-vremmo modificare uno a unotutti i valori già inseriti.

Meglio, quindi, creare una ta-bella “Dipartimenti” cui fare ri-ferimento: in questo modo nonci sarebbero errori di inseri-mento, l'aggiornamento verreb-be fatto in un unico punto edautomaticamente propagato atutti i record interessati dellatabella Professori.

Ultimo consiglio è di non in-serire in una tabella dei campiche non siamo direttamente di-pendenti dai campi chiave del-la tabella stessa. Un esempiopossono essere i campi CAP eProvincia che potremmo inse-

rire, come anagrafica, nella ta-bella Studenti: questi campi di-pendono solo dal Comune di re-sidenza indicato, non dalla ma-tricola dello studente che è lachiave della tabella. Anche inquesto caso va prevista una ta-bella esterna che leghi un Co-mune al suo CAP ed alla Pro-vincia di appartenenza.

Un altro accorgimento, dibuon senso, è di non memoriz-zare mai dati che possano es-sere calcolati, quindi mai regi-strare un campo “Età” se si ha adisposizione l'anno di nascita.

Se abbiamo rispettato quan-

to scritto, il nostro DB è giàmolto affidabile ed efficiente,ed è pronto per essere inseritonel DBMS.

Nella prossima puntata ve-dremo come creare il DB conMySQL e come compiere leoperazioni di inserimento, ag-giornamento e cancellazioneimparando ad usare il linguag-gio universale di interrogazionedelle base di dati: SQL, ovverolo Structured Query Language.Infine vedremo come usarePHP per interfacciarsi con My-SQL e portare su Web i risultatidelle operazioni compiute. �

Schema concettuale: un esempio dimodello Entità-Relazione

Esempio di una relazione (tabella) nel modello Relazionale

ESAMEMatricolaCodice corsoDataVoto

PIANO STUDICodicePresentato il

CORSOCodice corsoAnnoAulaOrario

STUDENTEMatricolaNomeCognomeCittàCodice pianoIn tesi con

PROFC.F.NomeCognomeCittà

N

N

1 1

11

1

Schema logico: esempio di modellorelazionale con indicazione degliattributi di ogni tabella

11

12

13

N

Page 27: Corso di Php (fonte: PC OPEN)

4a lezione

La terza lezione del corso ci èservita per imparare i con-cetti fondamentali relativi

alla costruzione di un databaseefficace ed efficiente. Prenden-do spunto da un caso reale(creare una base di dati per me-morizzare la carriera universi-taria di uno studente), abbiamovisto come costruire uno sche-ma concettuale ed il conse-guente schema logico, tenendoconto delle tecniche di norma-lizzazione per garantire l'inte-grità del database e la rilevanzadei dati. Quanto descritto havalidità assolutamente genera-le: adesso, però, è il momentodi implementare i nostri schemisu un DBMS e rendere interatti-va la nostra base di dati.

Per queste operazioni usere-mo MySQL, le istruzioni SQL(Structured Query Language) eil linguaggio PHP che ci forni-sce adeguati strumenti di in-terrogazione e gestione remotadel DB.

Se qualcuno ha avuto diffi-coltà ad installare o configura-re i programmi citati nelle scor-se puntate e quelli introdotti inquesta lezione (come Apache,PHP, MySQL e PhpMyAdmin),provi a fare riferimento al sitoeasyPHP (http://www.ea-syphp.org). Questo sito, di ori-gini francese e tradotto anchein lingua italiana, è chiaro e ag-giornato e fornisce in un unicopacchetto autoinstallante i pro-grammi citati.

Lo schema logico di una ba-se di dati va implementatoutilizzando un DBMS (Data-

base Management System), ilcomponente software che con-sente di operare i processi didefinizione, costruzione e ma-nipolazione del database.

Per il corso, coerentementecon la scelta opensource effet-tuata nelle lezioni precedenti, èstato scelto MySQL, un RDBMSlibero (free) distribuito con li-cenza GPL, basato sullo stan-dard SQL e disponibile per am-bienti Linux, Macintosh e Win-dows. L'acronimo non è sba-gliato: la R indica la parola “Re-lational” a sottolineare comeMySQL (così come Postgre-SQL, MS Access, Oracle e altri)sia un DBMS basato sul con-cetto basilare di relazione tratabelle.

MySQL nasce grazie alla sve-dese TcX (ora MySQL AB), unasocietà cui serviva un DB velo-ce, flessibile e affidabile. Nontrovandolo tra i prodotti esi-stenti, i progettisti svedesi de-cisero di crearselo distribuen-dolo poi con licenza GPL (vediriquadro “Licenza GPL e licen-za commerciale di MySQL”). Ilrisultato è un sistema in gradodi gestire con efficienza e sicu-rezza enormi moli di dati, conuna velocità di esecuzione ditutto rispetto. Ci sono ancoradei passi da fare per rendereMySQL veramente completo(vedi “il futuro di MySQL” piùavanti nell’articolo), ma co-munque le caratteristiche diquesto database ne fanno unpunto di riferimento assolutodel settore. Non solo sul Web,dove è uno dei principali attori,

ma anche come DBMS per so-luzioni interne ad un'attività,ad esempio per gestire la con-tabilità, le spedizioni, le bustepaga o semplicemente per or-dinare una volta per tutte lapropria infinita collezione di li-bri. Il simbolo di MySQL è il del-fino Sakila, per cui tuffiamocinel processo di installazionedel software e nella creazionedel nostro primo database.

Installazione e avvio del server

MySQL è un cosiddetto da-tabase server, e quindi per po-ter funzionare necessita nonsolo del software installato maanche di un server attivo (Apa-che, IIS, Xitami e via dicendo).Il nostro server è già impostato(vedi prima lezione), quindiconcentriamoci sulla parte di

mera installazionedi MySQL. Scari-chiamo da http://dev.mysql.com/downloads/ l'ultima ver-sione stabile di MySQL databa-se server and standard clientsper Windows (disponibile an-che nel CD Guida 1 nella cartel-la PDF\Corsi\PHP) e procedia-mo come al solito. Il processo ètotalmente automatico se si ac-cetta di installare il programmasulla cartella predefinita c:/my-sql: approfittiamo di questa op-portunità lasciando l'alternati-va a chi voglia perdere qualcheminuto in più per il settaggiosuccessivo del file my.ini.

Terminata l'installazione fac-ciamo doppio clic sul file c:/my-sql/bin/winmysqladmin.exe peravviare per la prima volta il no-stro server MySQL. Ci verràchiesta una coppia user-pas-

Lezione 1:- PHP con un server off line- Funzioni base e variabili- I costrutti di controllo

Lezione 2:- Approfondiamo PHP- Include e require- Funzioni e classi- Proteggere una pagina- Cookie e sessioni- La funzione mail

Lezione 3: PHP e i database- La funzione upload- Lavorare con i file- La gestione degli errori- Accenni di sicurezza

- Il database system- Siti Web dinamici- Teoria dei database

Lezione 4:- PHP e MySQL- MySQL, databaseopensource

- Costruzione e interrogazionedi un database: il linguaggioSQL

- Interfaccia GUI: PhpMyAdmin- Integrazione MySQL e PHP

La prossima puntataLezione 5: Gestire un sitodinamico con PHP e MySQL

IL CALENDARIO DELLE LEZIONI

di Federico Pozzato

� A scuola con PC Open

WebDeveloper PHP1 MySQL e PHP

I listaticompleti

sono sul CD

2 MySQL, un database opensource

Page 28: Corso di Php (fonte: PC OPEN)

4a lezione

sword: possiamo anche la-sciarla in bianco dal momentoche questi parametri servonosolo in caso di amministrazio-ne remota del server MySQL. Aquesto punto avremo accessoal pannello di gestione, rappre-sentato da una icona a forma disemaforo posta nella traybar(immagine 1). Se il semaforo èverde, siamo pronti a creare ilnostro primo database.

Cliccando col tasto destrodel mouse sul semaforo e sce-gliendo show me si apre la fine-stra di gestione: potremo vede-re sulla linguetta Environment(immagine 2) l'indirizzo IP lo-cale del nostro server (lo stes-so di Apache o IIS) e sulla lin-guetta my.ini Setup i valori delfile my.ini: la riga che più ci in-teressa è la datadir che ci forni-sce il percorso di registrazionedei dati (utile saperlo per unbackup). Sempre grazie al no-stro semaforo potremo ferma-re e far ripartire il servizio chepresiede al funzionamento delserver MySQL. In alternativaper compiere la stessa opera-zione possiamo usare l'utilityServizi che abbiamo a disposi-zione in Pannello di controllo,Strumenti di amministrazione.

Client e sicurezzaIl server MySQL è stato av-

viato, ma da solo non basta:per la gestione e per tutte leoperazioni inerenti i databaseabbiamo infatti bisogno di uti-lizzare un client. L'installazione

appena effettuata ci mette a di-sposizione un client con unaspartana interfaccia a caratte-ri, addirittura lanciata attra-verso una finestra DOS.

La cosa non è così strana co-me potrebbe sembrare a primavista: MySQL, infatti, è un'ap-plicazione server e l'interfacciaclient a caratteri consente di la-vorare con qualsiasi computerindipendentemente dalle inter-facce grafiche installate e per-mette di inviare facilmente co-mandi via telnet da un compu-ter collegato in rete. Inoltre ga-rantisce velocità e flessibilità,chiedendo solamente di cono-scere pochi comandi e le basidel linguaggio SQL.

Naturalmente ci sono molteinterfacce grafiche già pronte(una la vedremo tra poco) persemplificarci la vita, però al-meno una volta è opportunoutilizzare lo strumento di de-fault fornitoci, per capire le rea-li potenzialità di MySQL senzafarci distrarre da nessun aspet-to grafico.

Sulla barra di Windows clic-chiamo su Start, Esegui e scri-viamo cmd per aprire una con-sole DOS. Al prompt scrivia-mo: cd mysql\bin per portarcisulla cartella di sistema di My-SQL.

MySQL è studiato per appli-cazioni client-server, quindi,per motivi di sicurezza, utilizzala gestione dei profili di acces-so degli utenti: a seconda delleautorizzazioni concesse (i co-siddetti “privilegi”) gli utentipotranno, ad esempio, solo fa-re la gestione dei dati di data-base specifici oppure crearenuovi database ma senza poteraccedere ad altri oppure soloinserire dati. L'amministratore

del sistema, la persona cui èconcesso il controllo assolutodi MySQL, è l'utente root. Win-dows crea automaticamentequattro profili identificati dauser, password e server di pro-venienza (localhost e remoto).I profili, tutti generati senzapassword predefinite, sono:

- root connesso da localhost: tutti i privilegi;

- root connesso da remoto: tutti i privilegi;

- utente anonimo connesso dalocalhost: tutti i privilegi previsti per idatabase presenti nel server;

- utente anonimo connesso da remoto:privilegi da assegnare.

Questa configurazione è ac-cettabile finché usiamo il DB inlocale e lo curiamo solo noi, maè chiaramente pericolosa nelmomento in cui al DB avesseroaccesso altre persone o quan-do fosse messo in rete. La rac-comandazione, quindi, è dicancellare subito l'utente ano-nimo connesso da localhost,assegnare le password a root ecreare degli utenti reali cui as-segnare i privilegi voluti.

Il manuale che si trova nelladirectory di installazione(C:\mysql\Docs\manual.html)è molto completo (salvato co-me file PDF occupa quasi 1.300pagine di formato A4) e si ri-manda alle pagine specificheper queste operazioni. Per leesigenze didattiche di questocorso vediamo però come in-serire la password “pluto” perl'utente root (connesso da lo-calhost, ossia dal nostro serverinterno) scrivendo questa riga(dalla console DOS):mysqladmin -u root -p password pluto(verrà chiesto di inserire la passwordvecchia: era vuota quindi basta solopremere invio)

Fermiamo e facciamo ripar-tire il server MySQL per carica-re i nuovi privilegi. Da adessoci collegheremo al server e alclient MySQL con l'identità diroot e la password inserita.

Le prime istruzioniUtilizzeremo l'istruzione my-

sqladmin per compiere opera-zioni “una tantum” che interes-sano il server nella sua genera-lità: interrogazioni sullo stato,cambiare password, ma anchecreare e distruggere database(cosa possibile anche utiliz-zando il client) o fermare il ser-

vizio. Ad esempio per fermareil server si può scrivere:mysqladmin -u root -p shutdown(viene chiesta la password di root perrendere effettiva l'istruzione)

Useremo invece l'istruzionemysql per aprire il client e agi-re sul database prescelto se-condo quanto previsto dai no-stri privilegi di accesso. Percollegarci scriviamo:mysql -u root -p

e inseriamo la password. Se citroviamo di fronte un prompt(immagine 3) del tipo:mysql>

Siamo pronti a gestire un da-tabase. Il client accetta due tipidi inserimenti: comandi MySQLo istruzioni SQL (da conclude-re sempre con un segno di pun-to e virgola “;”). I comandi My-SQL sono relativamente pochi(scrivere help per vederli) e ciinteressano in particolar modoUSE (per agire su un databasespecificato) e QUIT (per usciredal client). Alle istruzioni SQL èinvece dedicato il prossimo pa-ragrafo. Come esempio scrivia-

Il semaforo verde conferma l'attivazionedel server MySQL

1

Licenza GPL e licenzacommercialedi MySQLLa licenza GPL (GNU GeneralPublic License) è la base delsistema GNU/Linux e delsoftware libero. Compilata daRichard Stallman, questa licenzaimpone, tra le altre cose, diridistribuire liberamente il codicesorgente di un programma chesia basato tutto, o in parte, sudel codice soggetto a licenzaGPL. È il cosiddetto “effettovirale” (ossia contagioso) dellalicenza GPL. Dal 2001 MySQLAB, società che detiene i dirittidi MySQL ha deciso di fornire ilDB con una duplice licenza: GPLe commerciale. La versione commerciale (apagamento) serve appunto asuperare il vincolo di liberaredistribuzione del codice:chiunque, pertanto, desideriusare MySQL per applicazioni dicui non vuole rendere pubblico ilcodice sorgente dovràacquistare una licenzacommerciale da MySQL AB.

I pannelli di configurazione del tool WinMySQLadmin

2

Page 29: Corso di Php (fonte: PC OPEN)

4a lezione

mo queste righe attraverso lequali accediamo al database“mysql” (è un DB installato inautomatico e serve per la ge-stione del DBMS. Non va can-cellato per nessun motivo) perpoi vedere le tabelle che locompongono e infine uscire dalclient:

mysql > USE mysql(accediamo al DB mysql. Attenzione èun DB di sistema)mysql > SHOW tables;(vediamo i nomi delle tabelle checompongono il DB)mysql > DESCRIBE db;(vediamo al struttura della tabella db:immagine 4)mysql > QUIT(usciamo dal client)

La prima e la quarta riga nonnecessitano del “;” perché so-no comandi MySQL, mentre laseconda e la terza sono istru-zioni SQL. Se dimenticassimo il“;” otterremmo solo l'effetto diandare a capo (col nuovo

prompt “->”) e potremmo con-tinuare a scrivere l'istruzionecome fossimo sulla riga prece-dente. La chiusura dell'istru-zione necessita il “;” oppure ilcostrutto “\g”.

Il futuro di MySQLPur essendo un eccellente

prodotto per caratteristiche divelocità e di gestione dei dati,MySQL non è ancora completosotto tutti i punti di vista.

L'integrità referenziale, adesempio, è implementata soloper le tabelle di tipo InnoDBma non per le MyISAM. Ricor-diamo che l'integrità referen-ziale serve ad impedire che ilvalore di un campo di una ta-bella possa fare riferimento adun valore di campo chiave nonancora esistente in una secon-da tabella. Questa è una funzio-nalità importantissima per ga-rantire la coerenza dei dati enon essendo ancora supporta-ta dalle MyISAM dovremo, sevogliamo usare queste tabelle

mantenendo l'integrità referen-ziale, creare dei controlli al mo-mento di implementare l'inter-faccia PHP.

Altro limite è il mancato sup-porto delle views: le “viste” so-no delle tabelle virtuali genera-te da query e saranno utilissi-me per semplificare il codice eottimizzare le ricerche. Per le

prossime release MySQL AB hagià dato dei punti fermi: con laversione 4.1 troveranno sup-porto le sottoquery (serviran-no a semplificare le chiamatenidificate di tabelle che hannolo scopo di creare un filtro diricerca), con la 5.0 le views econ la 5.1 l'integrità referenzia-le per le tabelle MyISAM.

Le risposte del server alle nostre prime interrogazioni: show e describe

4

3 Costruzione e interrogazione di un database:il linguaggio SQL

Per costruire un database efarlo funzionare adeguata-mente abbiamo bisogno in

primis di conoscere il tipo didati che dovranno essere me-morizzati, passo necessarioper imparare a costruire unatabella. Dovremo poi assegna-re il campo chiave, eventualiindici, valori predefiniti, il ran-ge di inserimento e così via.Successivamente dovremo ap-prendere come gestire la no-stra base dati tramite le azionidi inserimento, modifica, can-cellazione e interrogazione.

Un esempio è necessario,quindi partiremo dallo schemalogico sviluppato nella scorsalezione. Lo scopo è creare undatabase in grado di monitora-re la situazione degli studenti

di una ipotetica università (ve-di lezione n.3 su PC Open di di-cembre 2004, disponibile an-che in formato PDF nel CD Gui-da 3).

Per compiere queste opera-zioni, la creazione e la gestionedel database, è indispensabileconoscere il linguaggio SQL(Structured Query Language).

SQL, il cui nome originarioera SEQUEL, fu inizialmente im-plementato nei laboratori IBMe venne poi standardizzato gra-zie allo sforzo congiunto di AN-SI (American National StandardInstitute) e ISO (InternationalStandard Organization) cheportò alla prima release stan-dard denominata SQL1 (ANSI1986). A questa sono seguiteSQL2 (SQL-92), SQL3

(SQL:1999) e SQL:2003. Indi-pendentemente dalla release,la cosa fondamentale è avere adisposizione per tutti i databa-se un linguaggio standardavente due specifiche caratte-ristiche:• è un linguaggio di definizionedei dati (DDL, ossia DataDefini-tion Language)• è un linguaggio di manipola-zione dei dati (DML, ossia DataManipulation Language)

Nei prossimi paragrafi ve-dremo nello specifico comeusare SQL nel nostro RDBMS.

Tipi di datiMySQL è in grado di gestire

qualsiasi tipo di dato, e il ter-mine “qualsiasi” comprendeanche dati multimediali come

filmati, immagini, file audio. Èchiaro che l'efficienza del data-base sarà direttamente pro-porzionale alla corretta sceltadel tipo di dato di ogni campo(colonna): minore sarà lo spre-co di spazio, più veloci sarannotutte le operazioni compiutesul DB. Fondamentale, quindi,è conoscere i tipi di campo cheabbiamo a disposizione e sce-gliere quello più adatto (attri-buti compresi) alle nostre esi-genze. Rimandando al manualedi MySQL per i dettagli, mentrenel box “I formati dei dati” rias-sumiamo brevemente i tipi didato.

La costruzione di una tabellaMySQL consente di creare

diversi “tipi” di tabelle alle qua-

il client mysql è pronto ad accettare istruzioni e comandi

3

Page 30: Corso di Php (fonte: PC OPEN)

li corrispondono performancedi risposta diverse. Le due piùdiffuse sono le MyISAM e le In-noDB. Le prime usano pocamemoria e sono gestite in ma-niera velocissima, però nonhanno ancora tutte le funzio-nalità che si potrebbero desi-derare, mentre le InnoDB, puressendo più complete, sonopiù lente e chiedono un mag-gior carico di memoria.

Inizialmente useremo le ta-belle MyISAM, visto che sonoquelle accettate di default.Apriamo un client MySQL col-legandoci come root (in mododa avere tutti i permessi possi-bili): al prompt la prima opera-zione da fare è creare il databa-se UNIVERSITAS:

NB: in MAIUSCOLO sono indicate leistruzioni specifiche di SQLmysql> CREATE DATABASE universitas;

Se volessimo cancellarlo l'i-struzione sarebbe:mysql >DROP DATABASE universitas;

Dobbiamo creare quattro ta-belle: una con i dati degli stu-denti, una con i dati dei profes-sori, una con i dati dei corsi euna con i risultati degli esami.Ogni tabella andrà inizializzataindicandone prima il nome equindi tutti i campi che la com-pongono, tipi di dato e attribu-ti compresi. La tabella STU-DENTE sarà quindi implemen-tata in questo modo (le istru-zioni di creazione della tabellasono su più righe solo per ren-dere più comprensibile il lista-to):

mysql> USE universitas;(entriamo nel database appena creato:all'apertura del client è semprenecessario indicare quale DB useremocome riferimento per le istruzionisuccessive)

mysql> CREATE TABLE studente (-> matricola CHAR(8) NOT NULL,-> nome VARCHAR(30) NOT NULL,

-> cognome VARCHAR(30) NOT NULL,-> data_nascita DATE,-> tesi_con CHAR(13),-> PRIMARY KEY(matricola),-> INDEX(cognome, nome);-> );mysql> EXPLAIN studenti;(per vedere la struttura della tabellaappena costruita)

Abbiamo creato una tabelladefinendo tutti i campi (duehanno un numero di caratterifissi, due hanno un numero dicaratteri variabili, uno è unadata di nascita), indicando ilcampo chiave (la matricola) ecome indicizzare la tabella (pri-ma per cognome e poi per no-me). Gli indici sono fondamen-tali per abbreviare le fasi di ri-cerca, ma attenzione che indi-care troppi indici porterebbead un peggioramento delle pre-stazioni.

La tabella ESAMI sarà invececosì costruita:mysql> CREATE TABLE esame (-> matricola VARCHAR(8) NOT NULL,-> cod_corso SMALLINT UNSIGNED

NOT NULL,-> voto TINYINT NOT NULL,-> lode ENUM(no,si) DEFAULT no NOT

NULL,-> data DATE NOT NULL,-> PRIMARY KEY (matricola,

cod_corso),-> );

Qui si è introdotto un valorebooleano grazie al tipo di datoENUM (i valori possono esseresolo “no” o “si”. Il primo è il va-lore di default). Volendo essereprecisi, anche il campo votoavrebbe potuto essere unENUM con valori compresi tra18 e 30, ma visti i tempi di cam-biamento lasciare libero il cam-po è forse meglio.

Capito il sistema, lasciamo ailettori il compito di costruire lealtre tabelle: l'unica accortezza èporre il campo codice nella ta-bella CORSO (immagine 5) comeTINYINT con l'opzioneAUTO_INCREMENT (è una chia-

ve). Chi non volesse scriveretutto il codice può approfittaredel file universitas_db.sql: i file.sql sono dei file testo che con-sentono di effettuare, tra le al-tre cose, la procedura dibackup. Grazie a questi file sia-mo in grado di esportare (e im-portare) la struttura del data-base (o della singola tabella)ed eventualmente anche i datiinseriti. Questa opportunità sirivelerà utilissima non solo persalvare i dati, ma anche peresportare su un server in Inter-net il nostro fiammante data-

base creato off line sul PC di ca-sa: tutti i provider fornitori diquesto servizio consentono, in-fatti, sia l'importazione che l'e-sportazione di file .sql.

I comandi da eseguire, dalprompt del DOS una volta usci-ti dal client, sono:mysqldump -u root -ppluto universitas> universitas_db.sql(backup di tutte le tabelle del database“universitas”, al momento senza dati.Il file creato si chiamerà“universitas_db.sql”)

Attenzione: a causa di un

I formati dei datiIl primo formato da esaminare è quello numerico, suddivisibile in numeriinteri e decimali. Per i numeri interi (positivi e negativi) i campi disponibili(in ordine crescente di occupazione di byte) sono: TINYINT (1 byte),SMALLINT (2 byte), MEDIUMINT (3 byte), INT (4 byte) e BIGINT (5 byte).Questo significa che un dato SMALLINT avrà un range totale di 2(2x8) =65.536 valori divisi tra negativi e positivi (da – 32.768 a +32767, 0compreso). Se gli attribuissimo l'opzione UNSIGNED i valori sarebberosolo positivi, quindi da 0 a 65.535. Un altro importante attributo deicampi numerici interi è AUTO_INCREMENT: ogni nuovo recordincrementerà di una unità il valore del record precedente, e quindi diventaun campo chiave. Per i numeri decimali abbiamo a disposizione FLOAT,DOUBLE e DECIMAL (M,D). L'ultimo è particolarmente utile perchéconsente di definire il numero di cifre decimali (D) e il numero massimo(M) di caratteri del numero, comprensivo di segno positivo o negativo edella virgola.Secondo formato è quello testuale (stringa). Se la stringa contiene menodi 255 caratteri possiamo usare CHAR (M) o VARCHAR (M), con M numeromassimo di caratteri. La differenza è che un campo CHAR occupa sempreM byte indipendentemente dalla stringa inserita nel record, mentreVARCHAR occupa un numero di byte uguale al numero di caratteri (più uno)della stringa. Se il testo è maggiore di 255 caratteri useremo TINYTEXT,TEXT, MEDIUMTEXT e LONGTEXT. Quest'ultimo consente di memorizzareuna stringa di testo di 4 GB! L'attributo BYNARY trasforma il testo instringa binaria: la conseguenza è che MySQL distinguerà, nell'ordinamentodelle ricerche, i caratteri minuscoli dai maiuscoli.Altro tipo di dato sono le stringhe di testo predefinite, rappresentate daENUM e SET. In questo caso il valore del campo (unico nel caso di ENUM,anche multiplo nel caso di SET) può essere scelto solo tra valori predefinitida noi in fase di creazione del campo.Il formato multimediale è registrato come stringa di caratteri binaria nelleforme di TINYBLOB, BLOB (Binary Large Object), MEDIUMBLOB eLONGBLOB (4 GB di spazio!).Date e ore possono essere salvate in forma completa o parziale. Nelprimo caso abbiamo a disposizione TIMESTAMP (4 byte occupati, ma datelimitate dal 1970 al 2037 su macchine a 32 bit) e DATETIME (8 byteoccupati, dall'anno 1000 al 9999). Il formato di TIMESTAMP predefinitooccupa 14 caratteri ed è memorizzato come AAAAMMGGHHMMSS;esistono comunque altri formati minori che possono essere maggiormenteadatti alle esigenze di costruzione del DB. Il formato di DATETIME èvariabile e dipende dai dati effettivamente inseriti. Date e ore “parziali”sono gestibili, pur nei limiti loro assegnati di default, con DATE (dal 01-01-1000 al 31-12-9999), TIME (consente valori negativi e superaabbondantemente le 24 ore: il formato è usabile, quindi, anche per calcolisugli angoli) e YEAR (dall'anno 1901 al 2155).Un piccolo spazio merita l'attributo NULL che può essere assegnato adogni tipo di dato. Cos'è un valore null? Null vuol dire proprio “nessunvalore” e non è né una stringa vuota (per un testo) né il valore zero (per inumeri). Se sappiamo che un campo non potrà mai essere null è beneomettere questo attributo: in caso contrario verrebbe sempre salvato unbit extra per ogni campo che potrebbe essere null.

L'istruzione explain ci mostra la composizione della tabella CORSO

5

4a lezione

Page 31: Corso di Php (fonte: PC OPEN)

4a lezione

bug di alcune versioni (la 4.0.13ad esempio) la password diroot (la nostra “pluto”) in que-sta istruzione va inserita im-mediatamente dopo l'opzione“-p” senza spazi intermedi. Ingenerale è sempre comunquepossibile inserire la passwordin questo modo in ogni istru-zione di comando dalla shelldel DOS. Se la versione che ave-te installato è esente dal bug,fate a meno di inserire la pas-sword sulla riga di comando,scrivendola invece solo quan-do richiesto come visto in pre-cedenza. Altri comandi che po-tremmo scrivere sono:

mysqldump -u root -ppluto -duniversitas studente corso >universitas_parz.sql

(backup dei soli dati delle tabelle'studente' e 'corso' del database“universitas”: il file creato è“universitas_parz.sql”. L'opzione -tavrebbe fatto il backup della solastruttura senza i dati. Va inserita lapassword di root)

mysql -u root -p universitas <universitas_db.sql

(ripristino o inserimento, nel databasegià creato “universitas”, delle tabelleoggetto di backup contenute nel file“universitas_db.sql”. Le tabelle nonvengono sovrascritte)

Eseguendo l'ultima istruzio-ne avrete il vostro database uni-versitas completo della struttu-ra di tutte le tabelle e pronto adessere gestito. Se il file universi-tas_db.sql non fosse nella car-tella “bin” di mysql (quella doveci troviamo per eseguire il co-mando), andrà indicato il per-corso assoluto completo (adesempio: D:\backup\mio\uni-versitas_db.sql).

Da questo momento in poidaremo per scontato di essereconnessi al client MySQL e ditrovarci nel database universi-tas (istruzione use universitas).

La gestione dei datiIl database è adesso solo

uno scheletro vuoto, ma que-sta era la parte più difficile. Ge-stire i dati è, al confronto, un'o-perazione piuttosto agevole evedremo come fare l'inseri-mento, la cancellazione la mo-difica dei medesimi usandosempre le istruzioni SQL.

L'inserimento può essere fat-to in più modi:

INSERT INTO tabella SET campo_1=valore_1, campo_2=valore_2,...;

INSERT INTO tabella VALUES(campo_1, campo_2, ...);

La differenza tra le due istru-zioni è che la prima consente diindicare (nell'ordine che prefe-riamo) solo i campi che voglia-mo effettivamente riempirecon dei valori (gli altri sarannocompletati in accordo con lecaratteristiche definite per icampi della tabella), mentre laseconda istruzione ci imponedi scrivere tutti i valori deicampi di un record (compresequindi stringhe vuote, valorinull o predefiniti) esattamentenell'ordine in cui è costruita latabella. L'utilizzo dell'una o del-l'altra istruzione dipende daltipo di inserimento che dob-biamo fare.

Poniamo di voler inserire unvalore nella tabella studenti:mysql> INSERT INTO studente SET

cognome=”Rossi”, nome=”Antonio”,matricola=”912345IG”,data_nascita=”19780427”;

(ho inserito nella tabella studente,nell'ordine che volevo, solo i dati cuivolevo attribuire un valore. Svantaggioè che devo ricordare i nomi corretti deicampi)

Equivalente sarebbe stata l'i-struzione:mysql> INSERT INTO studente VALUES

(“912345IG”, “Antonio”, “Rossi”,“19780427”, null);

(qui avrei dovuto inserire tutti i valorinel giusto ordine, compreso l'ultimovalore null perché questo studenteancora non è in tesi con alcunprofessore. Il vantaggio in questo casoè che non devo inserire i nomi deicampi)

Chiaramente se tentassimodi inserire una matricola (cam-po chiave) già esistente ci ver-rebbe segnalato un errore (im-magine 6). Notiamo che l'inse-rimento della data va fatto nelformato corretto (AAAAMMGG) e che ad un eventuale pro-fessore con cui si fa la tesi ci sideve riferire tramite il codice fi-scale, ossia il campo chiavedella tabella “prof”.

Non ci viene dato errore seinseriamo nel campo“tesi_con” un valore di riferi-

mento alla tabella “prof” nonesistente. La stessa cosa acca-de se, al momento di registrareil voto di un esame, inseriamouna matricola errata o un codi-ce di un corso inesistente. Que-sto, è dovuto al mancato sup-porto dell'integrità referenzialedelle tabelle MyISAM.

Se volessimo avere questosupporto avremmo dovuto de-finire tutte tabelle (ogni tabellaci sono riferimenti a valori dichiave esterni) utilizzando il“type” InnoDB e i comandi FO-REIGN KEY - REFERENCES diSQL:mysql> CREATE TABLE studente(matricola CHAR(8) NOT NULL, nomeVARCHAR(30) NOT NULL, cognomeVARCHAR(30) NOT NULL, data_nascitaDATE, tesi_con CHAR(13), PRIMARYKEY(matricola), INDEX (tesi_con,cognome, nome), FOREIGN KEY(tesi_con) REFERENCES prof(cod_fisc))TYPE=INNODB;(il riferimento alla tabella prof è datocon l'istruzione FOREIGN KEY: bisognaperò ricordare di indicare il campo“tesi_con” anche negli indici)

Così facendo siamo obbliga-ti ad inserire nel campo “te-si_con” un valore già presentenella tabella “prof”. A titolo diesempio, nel CD trovate il fileuniversitas_innodb.sql che con-tiene la struttura del databasecostruita con tabelle InnoDB etutte le integrità referenziali ri-spettate. Caricando queste ta-belle si noterà l'impossibilità dicaricare dati non coerenti conquanto definito in termini diintegrità referenziale. Lo spaziooccupato dalle tabelle, però,aumenta considerevolmente ecalano le performance di velo-cità.

Torniamo al DB con tabellaMyISAM: il file universitas_da-ti.sql contiene dei valori diesempio da caricare per popo-lare il database. Carichiamoquesto file come abbiamo giàimparato e proseguiamo la le-zione.

La cancellazione dei dati diuna tabella può essere fatta inmaniera “completa” ossia can-cellando tutti i record oppure,ed è il caso più frequente, indi-

cando una condizione da ri-spettare per cancellare la riga ole righe in questione:DELETE FROM tabella [WHEREcondizione];(la clausola where è opzionale: se c'èvengono cancellati solo i record cherispettano la condizione, altrimentivengono cancellati tutti i record dellatabella)

Ad esempio se volessi can-cellare tutti gli studenti di co-gnome “Rossi”, l'istruzionesarà:mysql> DELETE FROM studenteWHERE cognome=”Rossi”;

La modifica dei dati può es-sere fatta su tutti i record diuna tabella o su delle tuple se-lezionate con un'apposita con-dizione:UPDATE tabella SET campo_1=

aggiornamento_1, campo_2=aggiornamento_2, ... [WHERE condizione];

(la clausola where è opzionale e servea restringere il numero di record daaggiornare)

Un esempio potrebbe essereun cambio del professore concui fare la tesi da parte di unostudente ben preciso, identifi-cato con la sua matricola:mysql> UPDATE studente SET

tesi_con=”BBBCCC52B41A123B”WHERE matricola=”123456IG”;

Altro esempio: supponiamodi dover trasformare tutti i vo-ti (al momento espressi in tren-tesimi) in voti centesimali. Ba-sta una modifica su tutta la ta-bella “esame” (immagine 7):mysql> UPDATE esame SET

voto=voto*10/3;

Esiste poi anche il comandoREPLACE che combina le ca-ratteristiche di INSERT e UP-DATE e quindi può fare al con-tempo funzioni di inserimentoe aggiornamento.

Interrogazione dei dati (query)

L'interrogazione (query, dalverbo “to query” = interroga-re) del database è senza dub-bio l'operazione più utilizzatanella gestione di un database,ed è al contempo facile e com-plessa. La facilità deriva dallastrutturazione dell'interroga-zione standardizzata da SQL,mentre la sua complessità de-riva dalla strutturazione rela-zionale della base di dati che ciimpone spesso di dover estrar-MySQL ci indica un errore se tentiamo di inserire due studenti con la stessa matricola

6

Page 32: Corso di Php (fonte: PC OPEN)

re informazioni da più tabelletra loro collegate. Quest'ultimaoperazione prende il nome diJOIN.

Una query nella sua struttu-ra più completa è così scritta(le clausole tra parentesi qua-dre sono opzionali):SELECT campi_tabella/eFROM tabella/e[WHERE condizione];[GROUP BY raggruppamento][HAVING condizione_raggruppamento][ORDER BY campi_tabella/eASC/DESC]

Alcuni esempi sono:

mysql> SELECT cognome, nome FROMstudente;

(selezioniamo solo le colonnecognome e nome, con quest'ordine,dalla tabella studente)

mysql> SELECT * FROM studente;(con l'asterisco selezioniamo tutte lecolonne dalla tabella studente)

mysql> SELECT * FROM studenteWHERE cognome=”Rossi”;

(selezioniamo solo i record dellatabella studente per i quali il valore di“cognome” è “Rossi”)

Spesso, però, avremo biso-gno di operare un join, ossia la-vorare con più tabelle correla-te. Supponiamo di voler saperequali sono gli esami sostenutidallo studente con matricola123456IG. Una query come laseguente è formalmente esattaperché ci dà i codici dei corsi,però non ci restituisce i nomidegli esami corrispondenti (im-magine 8):mysql> SELECT cod_corso, voto, lodeFROM esame WHEREmatricola=”123456IG” ORDER BYdata;

quindi per dare leggibilità al ri-sultato dobbiamo fare un join(“to join” = unire) per sostituireal codice il corrispondente no-me del corso ricavato dalla ta-

bella “corso” (immagine 9):mysql> SELECT corso.nome,esame.voto, esame.lode-> FROM corso, esame-> WHERE corso.cod_corso=esame.

cod_corso->AND esame.matricola=”123456IG”-> ORDER BY data;

Un join, quindi, si fa estraen-do i dati utili da più tabelle (inomi dei campi vanno indicatianteponendo il nome della ta-bella cui fanno riferimento) eimponendo, nella clausolaWHERE, una condizione diuguaglianza tra determinati va-lori delle tabelle: in questo ca-so il join è fatto sul campo cheidentifica il codice numericodel corso, campo chiave ester-no per la tabella “esame” ecampo chiave effettivo per latabella “corso”. Abbiamo intro-dotto anche la clausola ORDERBY che serve a ordinare i risul-tati (di default in manieraascendente, altrimenti si deveaggiungere DESC) dell'interro-gazione.

Introduciamo la parola chia-ve DISTINCT: serve ad elimina-re da un risultato eventuali tu-ple duplicate che si otterreb-bero. Supponiamo di volere sa-pere il numero di matricola de-gli studenti che hanno supera-to almeno un esame: questematricole saranno presenti nel-la tabella esame, ma una querysemplice presenterebbe dupli-cati se uno studente avessepassato più di un esame. Perevitarlo e avere il risultato vo-luto si scriverà:mysql> SELECT DISTINCT matricolaFROM esame;

Molto utili, infine, sono lefunzioni aggregate che agisco-no sulla totalità dei recordestratti, secondo una precisacondizione di raggruppamen-to: COUNT (conta il numero direcord), SUM (somma i valori),MAX (trova il valore più alto),

MIN (trova il valore più basso)e AVG (calcola la media). Senon sono specificati raggrup-pamenti queste funzioni agi-ranno tenendo conto di tutti irecord estratti: ad esempio persapere quanti sono gli studentinati dal 1980 in poi:mysql> SELECT COUNT(*) FROMstudente WHERE data_nascita >=”19800101”;

Il raggruppamento si rivele-rebbe utilissimo se volessimosapere la media voti di ognistudente (immagine 10). Usoanche la funzione alias AS cheserve ad assegnare un nomenuovo momentaneo (in genereper motivi di maggiore chiarez-za) ad un campo (esistente ocreato con la query) o ad unatabella:mysql> SELECT matricola, AVG(voto)AS media-> FROM esame-> GROUP BY matricola;

Sulla clausola di raggruppa-mento potremmo porre delleulteriori condizioni tramiteHAVING per rendere ancora piùinteressanti le nostre interro-gazioni.

Ad esempio poniamo di vo-ler conoscere il nome degli stu-denti che hanno fatto almenotre esami:mysql> SELECT studente.nome,studente.cognome FROM studente,esame-> WHERE studente.matricola=

esame.matricola-> GROUP BY esame.matricola-> HAVING COUNT(*)>=”3”;(“having” agisce solo su una clausola“group by”)

Queste sono le principaliistruzioni di una query. SQLcomprende poi una ulterioreserie di utili operatori su insie-mi (UNION, EXCEPT, INTESECT,CONTAINS), operatori “quanti-ficatori” (ALL, ANY, IN, NOT IN,SOME) e operatori di verifica(EXISTS, NOT EXISTS, UNIQUE)che si lasciano al libero studiodegli interessati ad approfon-dire l'argomento.

Operazioni sulle query:comandi principali

Sui record estratti da unaquery si può agire in un secon-do momento, ad esempio inter-venendo coi costrutti di PHP,oppure si può agire diretta-mente al momento dell'estra-zione del risultato. SQL, infatti,fornisce una libreria completa

di operatori aritmetici, logici, diconfronto, di ricerca e binari.Abbiamo a disposizione fun-zioni numeriche (ABS, LOG,COS, ...), funzioni di controllodei cicli (IF, IF NULL, CASE),funzioni per agire sulle strin-ghe (CONCAT, UPPER, ...), fun-zioni di data e ora e funzioniper la sicurezza (PASSWORD,ENCRYPT,...). Ad esempio perestrarre le date di nascita deglistudenti rendendole “leggibili”,potremmo usare (immagine11):mysql> SELECT CONCAT(nome, “

“,cognome) AS nome_studente, DATE_FORMAT(data_nascita, “%d-%m-%Y”) AS data

-> FROM studente-> ORDER BY cognome, nome;

Risultato di un update completo sulla tabella esame

7

Una query esatta ma che non consenteuna leggibilità immediata

8

La stessa query con un join diventa moltopiù significativa e leggibile

9

Come calcolare la media voti usando laclausola di raggruppamento e la funzioneAVG di SQL

10

Il risultato di una query può esseresottoposto a varie operazioni prima diessere stampato

11

4a lezione

Page 33: Corso di Php (fonte: PC OPEN)

4a lezione

4 Un’interfaccia GUI: PhpMyAdminFinora, per i motivi già scrit-

ti di universalità, abbiamousato l'interfaccia a caratte-

ri per agire su MySQL, però incerte occasioni un'interfacciagrafica può aiutarci a compierecerte operazioni di cui, magari,non ricordiamo perfettamentela costruzione.

Introduciamo quindi una uti-le GUI (Graphic User Interface)rilasciata sotto licenza GPL etotalmente scritta in PHP perinteragire con MySQL:PhpMyAdmin.

L'installazione non compor-ta problemi: è sufficiente, infat-ti, scompattare il file zippato(lo trovate nel CD oppure suhttp://www.phpmyadmin.net/home_page/) in una cartella chechiameremo “phpMyAdmi” daporre nella “Document Root”del server Apache (ossia dovefinora abbiamo posto le nostrepagine PHP per verificarle off-li-ne, la cartella dove il nostroserver va a leggere quando sul-la barra dell'indirizzo scrivia-mo, ad esempio, http://lo-calhost o http://127.0. 0.1).

Per far funzionare phpMyAd-min entriamo nella cartella diinstallazione tramite GestioneRisorse e apriamo, con un qual-siasi editor di testo, il file con-

fig.inc.php. Cerchiamo la rigacontenente $cfg['PmaAbsolu-teUri'] e dopo il segno di ugua-glianza indichiamo il percorsoda raggiungere tramite server:$cfg['PmaAbsoluteUri'] =

'http://127.0.0.1/phpMyAdmin';(o http://localhost/phpMyAdmin o ...)

Poi immediatamente dopocerchiamo $cfg['Servers'][$i]['host']

e scriviamo l'indirizzo IP delnostro server MySQL interno:$cfg['Servers'][$i]['host'] = “localhost”(o 127.0.0.1 o ...)

e poi di fianco a $cfg['Servers'][$i]['auth_type']

scriviamo:$cfg['Servers'][$i]['auth_type'] = ”http”

A questo punto apriamo ilnostro browser preferito e scri-viamo l'indirizzo dove è instal-lato phpMyAdmin: sarà qual-cosa del tipo http://127.0.0.1/phpMyAdmin.

Si aprirà una finestra di ri-chiesta di accesso. Indicandouser e password (quelle di rooto quelle di un utente preceden-temente creato) avremo acces-so al pannello di controllo (im-

magine 12) da cui possiamopartire per fare praticamentetutto quello che vogliamo (sene abbiamo i permessi) su da-tabase, tabelle e singoli dati.Possiamo inserire i privilegi de-gli utenti, esportare e importa-re database salvati in formato.sql o .zip, scrivere query aiu-tati dalla grafica, inserire, mo-dificare e cancellare dati, con-trollare lo stato del server My-SQL, vedere l'ingombro delletabelle e la loro velocità di ri-sposta, e agire anche su dei co-

mandi MySQL per analizzare eottimizzare le tabelle della ba-se di dati.

PhpMyAdmin è un ottimostrumento e vale sicuramentela pena usarlo per applicazioniinterne, ma ricordate che il vo-stro provider potrebbe fornirviun'interfaccia grafica diversa, oaddirittura non fornirvela af-fatto.

Per tutte le opzioni di confi-gurazione, veramente molte, sirimanda al manuale fornito colprogramma.

5 L’integrazione fra MySQL e PHP

Abbiamo imparato a co-struire un database par-tendo da schemi puramen-

te concettuali per arrivare alloschema logico generale e infineall'implementazione fisica al-l'interno del Relational DBMSscelto per ospitare i dati. Siamoin grado di popolare il databasee di gestire aggiornamenti, can-cellazioni e interrogazioni an-che di una certa complessità.

Il problema è che solo noisiamo in grado di farlo, e co-munque non è sempre facile ri-cordare tutti i passaggi. Ma seci fossero, ed è assolutamentenormale sia così, altre personecoinvolte nella gestione dellabase di dati? E se dovessimousare i dati “grezzi” estratti daMySQL per fornire informazionia degli utenti esterni? Non pos-

siamo certo pretendere che tut-ti imparino il linguaggio SQLper interrogare un database,anche perché comunque do-vremmo prima spiegare loro glischemi alla base della costru-zione della base di dati.

Risolvere questi problemiequivale a fare l'ultimo passoverso l'ambiente “globale” de-scritto nella lezione 3 e quindicreare un completo DatabaseSystem. Per fare questo dob-biamo unire le potenzialità diPHP a quelle di MySQL, alloscopo di creare delle soluzioniuser-friendly di gestione del da-tabase. Nel caso particolare delnostro corso, il Web developerPHP dovrà essere in grado di:

• creare un database efficienteo comunque capirne il fun-

zionamento nel caso l'archi-tetto del DB sia un'altro pro-fessionista;

• interrogare il database utiliz-zando SQL;

• utilizzare i record risultatoper comporre informazionie/o pagine Web;

• fornire un facile sistema di ge-stione al web content.

PHP è un linguaggio forte-mente votato al connubio conun database e può dare unamarcia in più al Web. PHP, inol-tre, non è “sposabile” solo conMySQL: potremo altrettanto fa-cilmente usarlo per interfac-ciarci con database come DB2,Firebird, MSSQL, Oracle, Post-greSQL, Sybase e anche, trami-te i driver ODBC, con MicrosoftAccess.

La prima cosa da fare è con-nettersi al database.

Connessione al serverMySQL

È piuttosto semplice effet-tuare la connessione al serverMySQL che ospita il nostro da-tabase Universitas. Sono ri-chiesti tre parametri: indirizzodel server MySQL, user e pas-sword di un utente (root o al-tro):mysql_connect (server, user,

password);

In caso di successo la fun-zione restituisce un identifica-tivo di connessione che ri-marrà invariato fino alla chiu-sura della stessa, mentre in ca-so negativo viene restituito unvalore false.

Il pannello di controllo di PHPMyAdmin

12

Page 34: Corso di Php (fonte: PC OPEN)

Effettuata la connessione alserver, si deve indicare su qua-le database vogliamo agire.Con l'interfaccia a caratteri siusava il comando use, mentrecon PHP utilizziamo:mysql_select_db (nome_db,identificativo di connessione);

Il risultato sarà un valoretrue o false (se il DB non esisteo se non si è riusciti ad effet-tuare la connessione al server),e nel primo caso il databasescelto sarà attivo per tutte leprossime azioni.

Per connetterci al databaseuniversitas del nostro serverlocale (come utente root) pos-siamo scrivere un file PHP co-me quello visibile nel codicesorgente della pagina connes-sione_prima.php. La pagina cidice se siamo connessi al data-base universitas, e in caso dierrore (provate ad esempio abloccare il server MySQL o acancellare il database universi-tas) stampa una riga di scuseinvece del messaggio di errore.Le righe di connessione sonovisibili nel listato connessio-ne_prima.php.

Le connessioni mysql_con-nect (non persistenti) restanoaperte fino alla chiusura dellapagina oppure fino alla chia-mata della specifica istruzioneche chiude la connessione in-dicata o comunque l'ultimaaperta:mysql_close();// essendo senza argomenti, la

funzione chiuderà l'ultima connessioneaperta

Interazione PHP-MySQLLa libreria MySQL di PHP

consente di inviare query e co-

mandi SQL e inoltre fornisceuna serie di utili funzioni con lequali possiamo interrogare ilserver, interagire con esso evalutare le prestazioni del da-tabase.

L'istruzione fondamentale èmysql_query: grazie ad essapossiamo inviare una query aldatabase attivo (o specificareuna connessione diversa).Chiaramente mysql_query ciconsentirà di effettuare sul da-tabase solo operazioni coeren-ti col nostro profilo utente.

La tipica costruzione di unaquery in PHP è:$q = “SELECT * FROM studente”;$ris = mysql_query ($q);

Il valore di $ris può essere:• false in caso di errore: la

query potrebbe essere erra-ta;

• un identificativo di risorsa sela query è del tipo SELECT,SHOW, EXPLAIN o DESCRIBE.In questo caso nulla vienedetto sul risultato ottenuto(ad esempio non si sa il nu-mero di righe restituito);

• true in tutti gli altri casi: adesempio con UPDATE, DELE-TE, DROP TABLE, ecc.

Un identificativo di risorsapuò essere passato come argo-mento alla funzione mysql_fet-ch_array la quale carica tutti icampi del primo record del ri-sultato in un array.

Per richiamare i valori del-l'array possiamo fare riferi-mento alla solita chiave nume-rica (il primo elemento hachiave zero) oppure usare co-me chiave il nome del campodedotto dalla query. Una suc-cessiva chiamata alla stessafunzione mysql_fetch_arraycaricherebbe il secondo re-cord, e così via fino a raggiun-gere l'ultimo record dopo ilquale verrebbe restituito unvalore false. Un ciclo while,quindi, è perfetto per consen-tirci di recuperare tutti i re-cord di una qualsiasi query diselezione (listatoquery_uno.php), come si puòvedere aprendo la paginaquery_uno.php che elenca glistudenti presenti nel DB (im-magine 13).

Se volessi recuperare il ri-sultato di una riga ben specifi-ca, ad esempio l'ultima, dovreiusare altre due funzioni: my-sql_num_rows che estrae il �il risultato di una query SQL recuperato con istruzioni PHP

13

listato connessione_prima.php<?php //Creo una connessione con il database universitas$nome_db = "universitas"; $id_connessione=@mysql_connect("127.0.0.1","root","pluto") or die("Non è possibileaccedere al server");// mysql_connect apre la connessione al server, e mysql_select_db la sfrutta per accedere ad uno specifico database@mysql_select_db($nome_db,$id_connessione) or die(“Non è stato possibile accedere al database”);?>

listato query_uno.php$q="SELECT nome, cognome, matricola, date_format(data_nascita,'%d-%m-%Y') AS data FROM studente ORDER BYcognome, nome";$id_ris=@mysql_query($q) or die("Non è possibile eseguire la query");// mysql_query restituisce un identificativo di risorsa. mysql_fecth_array estrae come array la prima riga del risultato dellaquery. Con un ciclo while estraggo tutte le righe della query. Uso o chiavi numeriche o chiavi corrispondenti ai nomi usatinella select

while ($record=mysql_fetch_array($id_ris)) {echo "Matricola: ".$record[matricola]."<br>$record[1] $record[0] - data di nascita: ".$record[data]."<p>";}

listato query_due.php$q="SELECT nome, cognome, matricola, date_format(data_nascita,'%d-%m-%Y') AS data FROM studente ORDER BY

cognome, nome";$id_ris=@mysql_query($q) or die("Non è possibile eseguire la query");$numero_righe=mysql_num_rows($id_ris);echo "Gli studenti presenti nel DB sono $numero_righe<p>";mysql_data_seek($id_ris,$numero_righe-1);// mysql_data_seek sposta il puntatore del risultato all'ultimo record, e mysql_fetch_array estrae un array corrispondente a questa posizione$record=mysql_fetch_array($id_ris);echo "Ecco l'ultimo studente presente nel database:<br>Matricola: ".$record[matricola]."<br>$record[1] $record[0] - data di nascita: ".$record[data]."<p>";

4a lezione

Page 35: Corso di Php (fonte: PC OPEN)

4a lezione

numero di righe risultanti dallaquery, mentre mysql_data_seek sposta il puntatore del ri-sultato ad una riga indicata neisuoi attributi (in questo casola riga sarà l'ultima). L'utilizzosarà chiarito dal seguenteesempio (listatoquery_due.php):

Se vogliamo dare maggioreinterattività alle nostre pagi-ne, possiamo iniziare con unesempio utile e semplice: sele-zionare da una casella a disce-sa uno studente inserito neldatabase per ricavare tutte leinformazioni su di lui (anni,esami sostenuti, media, se è intesi con qualche professore).Costruiamo due pagine: la pri-ma servirà alla selezione dellostudente (stud_select.php),mentre nella seconda “stam-peremo” la sua scheda(stud_cv.php). La query dellaprima pagina assomiglia aquanto visto nel listatoquery_uno.php, però abbiamoconcatenato tre campi (matri-cola, cognome e nome). Neltag “select” del form passere-mo questo campo come valoreda visualizzare, ma alla sceltafatta corrisponderà il valoredella matricola che è il campochiave (listatostud_select.php).

Selezionato lo studente, nel-la seconda pagina si tratta so-lamente di far eseguire al ser-ver MySQL, tramite PHP, alcu-ne query con join: il listatostud_cv.php riprende solo unadelle tre query previste (si ri-manda al file per il codicecompleto). Il risultato, conuna formattazione di massima,è visibile nell'immagine 14.

L'ultimo esempio (file vo-to_gestione.php) riguarda l'in-serimento e la cancellazionedei dati dal nostro database. Atale scopo predisponiamo unapagina dalla quale inserire (o

eliminare) un esame svolto dauno studente. La pagina con-terrà un form con due pulsan-ti per inserire o cancellare lavotazione. Notate le due casel-le a discesa di selezione: ser-vono a preservare l'integritàreferenziale del database, im-pedendo di inserire nella ta-bella “esame” una matricolanon esistente o un corso nonattivato.

Chiaramente se si tentassedi inserire un voto di un esamegià sostenuto non si otterreb-be alcun risultato perché sa-rebbe una violazione dellachiave della tabella. Per il con-trollo usiamo la funzione my-sql_affected_rows che resti-tuisce il numero di record in-teressati dalla query: se il va-lore ottenuto è zero significache si è cercato di inserire unvoto che già c'era o di cancel-lare un voto che non esisteva.Il listato voto_gestione.php favedere il particolare delleistruzioni di inserimento o

cancellazione del record (at-tenzione all'uso “compatto”degli if interni). Si lascia al let-tore la rifinitura della funzio-ne, ad esempio per impediredi effettuare un inserimentose il voto non è stato scrittonel form, o impedire di asse-gnare la lode ad un voto mino-re di 30.

Con questa doverosa intro-duzione sul rapporto tra PHPe MySQL si chiude anche laquarta puntata del corso. Laprossima sarà totalmente de-dicata ad approfondire esempipratici di applicazioni PHP-My-SQL e vedremo come gestirein tutte le sue parti un sitoWeb dinamico.

Approfondimenti:

http://www.mysql.comhttp:/www.mysql.com/documentationhttp://www.mysql.com/downloadshttp://www.php.net/mysqlhttp://www.phpmyadmin.nethttp://www.easyphp.org

La scheda dello studente selezionato

14

listato stud_select.php<select name="stud_nome"><?php

while ($record=mysql_fetch_array($id_ris)) {echo "<option value=".$record[matricola].">".$record[0]."</option>";

}mysql_close();

?></select>

listato stud_cv.php// Terza operazione: se lo studente è in tesi, stampare i dati del professore che lo segueif (!is_null($record_1[tesi_con])) {

$q_3="SELECT prof.cognome AS cognome, prof.nome AS nome, prof.dipartimento AS dipartimento FROM prof,studenteWHERE studente.matricola='".$record_1[matricola]."' AND prof.cod_fisc=studente.tesi_con";

$id_ris_3=@mysql_query($q_3) or die("Non è possibile eseguire la query");$record_3=mysql_fetch_array($id_ris_3);echo "<h3>Lo studente è in tesi col prof. ".$record_3[cognome]." ".$record_3[nome]." del Dipartimento di ".$record_3[dipartimento]."</h3>";

}

listato voto_gestione.phpif (isset($_POST['inserisci'])) {

$q_3="INSERT INTO esame VALUES ('".$_POST['stud_nome']."','".$_POST['stud_es']."','".$_POST['voto']."','".$_POST['lode']."','".$_POST['data']."')";mysql_query($q_3);if (mysql_affected_rows()==1) echo "Il voto è stato inserito";else echo "Attenzione: il voto non è stato inserito perché lo studente selezionato ha già sostenuto quell'esame";

}elseif (isset($_POST['elimina'])) {$q_4="DELETE FROM esame WHERE matricola='".$_POST['stud_nome']."' AND cod_corso='".$_POST['stud_es']."'";

mysql_query($q_4);if (mysql_affected_rows()==1) echo "Il voto è stato cancellato";else echo "Attenzione: il voto non è stato cancellato perché non era mai stato inserito prima";

}

Page 36: Corso di Php (fonte: PC OPEN)

Innanzitutto per lavorare almeglio dobbiamo avere chiarii punti di partenza e di arrivo

del progetto che ci apprestia-mo a realizzare.

L'obiettivo (il goal) è la crea-zione di un sito nel quale inse-rire articoli, opinioni e ap-profondimenti (in generale:commenti) su una o più macroaree, a loro volta suddivise inargomenti: le aree (l'object), adesempio, potrebbero essere laletteratura, il cinema, la politi-ca, l'ambiente e via dicendo.

Inizialmente si partirà conun paio di aree (ambiente einformatica), da incrementarein seguito. Il sito si rivolgerà (iltarget) a visitatori desiderosi diapprofondire argomenti speci-

fici di loro interesse. Il portaledeve essere assolutamentesemplice e fruibile in manieraimmediata da parte dell'utente,che in pochi attimi deve riusci-re a individuare la sua area diinteresse e a leggere i commen-ti inseriti.

Si deve anche prevedere unminimo di interattività, dandoai visitatori la possibilità di scri-vere le proprie opinioni e diiscriversi ad una mailing list.

Gli articoli saranno affidata apiù persone (“giornalisti”),esperte nel loro campo. Questepersone operano da luoghi di-versi (anche da casa), quindideve essere predisposto un si-stema Web grazie al quale pos-sano inserire i loro scritti nelportale dopo una autenticazio-ne di accesso.

Bisogna poi prevedere unamministratore unico del sito, icui compiti principalmente sa-ranno:• convalidare o cancellare com-

menti e foto inseriti dai gior-nalisti;

• inserire, modificare e cancel-lare le macro aree e gli argo-menti (in accordo con l'edito-re del sito);

• aggiungere, modificare o eli-minare i giornalisti;

• gestire la mailing list e spedi-re la newsletter;

• gestire i testi di presentazionedelle pagine.C'è un vincolo (un manda-

tory) importante: sia i giornali-sti che l'amministratore sonoutilizzatori Web, ma non sannonulla di HTML, PHP, SQL o da-tabase. Va quindi fornito unportale “chiavi in mano”, sem-plice e pronto all'utilizzo ancheper quanto riguarda la gestio-ne.

In termini progettuali, quan-to scritto nelle righe preceden-ti rappresenta il briefing (vedifigura 1) del compito assegna-toci: “to brief”, infatti, significariassumere, dare istruzioni aqualcuno. Mancherebbero unpaio di dettagli fondamentalicome il tempo di realizzazione(il timing) e i soldi a disposi-zione (il budget), ma per il no-stro esempio sono irrilevanti.

Il ciclo di realizzazione di unprogetto Web

5a lezione

Le quattro lezioni pubblicatedel corso “Web DeveloperPHP” ci hanno insegnato le

basi del linguaggio PHP, basinecessarie per sviluppare unsito dinamico utilizzando comeDBMS il database open-sourceMySQL. Abbiamo visto anche

un po' di teoria dei database,dal momento che uno svilup-patore non può essere digiunodi un aspetto sempre più fon-damentale nell'evoluzione delWeb.

Quest'ultima lezione riuni-sce molti dei concetti visti dan-

do loro un taglio ancora piùpratico ed esemplificativo: loscopo finale, infatti, è creare uncompleto portale Web di com-menti tematici, comprensivodi una zona protetta di ammi-nistrazione e gestione. La sfidapiù interessante è rendere que-

sto portale espan-dibile fin da subito.

L'esempio, capi-ta la logica di fon-do, potrà poi essereusato come spuntoper Web site piùcomplessi.

Lezione 1:- PHP con un server off line- Funzioni base e variabili- I costrutti di controllo

Lezione 2:- Approfondiamo PHP- Include e require- Funzioni e classi- Proteggere una pagina- Cookie e sessioni- La funzione mail

Lezione 3: PHP e i database- La funzione upload- Lavorare con i file- La gestione degli errori- Accenni di sicurezza- Il database system- Siti Web dinamici- Teoria dei database

Lezione 4:- PHP e MySQL- MySQL, databaseopensource

- Costruzione e interrogazionedi un database: il linguaggioSQL

- Interfaccia GUI: PhpMyAdmin- Integrazione MySQL e PHP

Lezione 5:- La gestione di un sitodinamico

- Il sito Web da sviluppare- Il compito del WebDeveloper- Il database- La struttura del sito- La costruzione del sito: la parte pubblica

- La costruzione del sito: le pagine di gestione

IL CALENDARIO DELLE LEZIONI

di Federico Pozzato

� A scuola con PC Open

WebDeveloper PHP1 La gestione di un sito dinamico

I listaticompleti

sono sul CD

2 Progettare un sito Web di notizie e commenti

COMMITTENTE UTILIZZATORI

BRIEFING

WEB DEVELOPER

REALIZZAZIONE

1

Page 37: Corso di Php (fonte: PC OPEN)

La prima operazione dacompiere, quella che poinecessariamente guiderà la

realizzazione delle pagine, è ladefinizione della struttura dellabase di dati da realizzare.

Come visto nella lezione 3, sideve definire uno schema con-

cettuale Entità-Relazione (vedifigura A), da trasformare suc-cessivamente in uno schemalogico relazionale normalizza-to. Le entità non sono molte: icommenti, le aree, gli argo-menti e i giornalisti. Non ci so-no le immagini: per loro usere-

mo una gestione che non ne-cessita di una tabella. Neppurel'amministratore è inserito nel-lo schema perché non sono de-finite relazioni con altre Entità:chi amministra, infatti, sovrin-tende tutte le attività e pertan-to non è legato direttamente anessuna.

Dallo schema concettualederiva lo schema logico (figuraB) in cui è indicata la composi-zione di ogni tabella. I campichiave sono in grassetto, men-tre i campi con l'asterisco rap-presentano una colonna che,pur non essendo chiave, con-tiene solo valori numerici unicied è quindi utilizzabile come ri-ferimento esterno per altre ta-belle. Nello schema finale man-cano alcune tabelle che, pur fa-cendo parte del database, pos-siamo definire di servizio gene-rale al sito e sono quindi dota-te di vita propria indipenden-

temente dalla struttura definitaper il DB.

Queste tabelle sono:

• amministrazione: nome (chiave),user, password, e-mail• mailing: nome, e_mail (chiave)• testi_admin: id_testo (chiave),descrizione, testo

Costruire il DB è un ottimoesercizio (lezione 4), comun-que nel CD allegato alla rivistaè presente il file commenti.sqlche contiene la struttura com-pleta del database e alcuni da-ti di esempio. Aprendo il filecon un editor di testo si può ve-dere nel dettaglio la strutturaed i tipi di dato di ogni tabella.

Se scegliamo di caricare il fi-le, creiamo prima il databaseCommenti, quindi importiamostruttura e dati usando gli ap-positi comandi di PhpMyAd-min (vedi immagine 1 e imma-

5a lezione

Lo schema Entità-Relazione del database Commenti

Al primo briefing seguiràpoi un lavoro ciclico dichiarimento (non sempre

è possibile realizzare quelloche il cliente vorrebbe alle suecondizioni), al termine del qua-le il Web Developer sarà prontoa realizzare il sito unendo, senecessario, le sue competenzecon quelle di altri professioni-sti Web. Per semplicità assu-meremo di essere in grado dicreare il sito da soli.

Viste le premesse e i vincolidi progetto, è chiaro che dovre-mo sviluppare un portale dina-mico utilizzando un DBMS co-me MySQL e integrandolo conil linguaggio PHP. Predisporre-mo due differenti profili di ac-cesso alla gestione del databa-se per amministratore e giorna-listi, realizzando per loro un'ap-posita interfaccia grafica Webdi gestione. Escludiamo di darea queste persone accesso di-retto al client MySQL (sia essografico o a caratteri), per moti-vi di praticità (le persone coin-volte sono solo utilizzatori delWeb) e anche per motivi di si-curezza (mai da sottovalutare).

Partendo da questo punto,stabiliamo una via di sviluppo,tra le tante possibili, per la par-te pubblica del portale.

L'home page dovrà presen-tare brevemente il sito, spie-garne l'obiettivo e dare delle in-dicazioni di navigazione. I testisaranno scritti dall'ammini-stratore del sito e potranno es-sere modificati in qualunquemomento. Servirà poi una se-zione dalla quale accedere allalista generale dei commenti, or-dinati in due modi: per numerodi click o per data di inseri-mento. Terzo punto da realiz-zare sarà l'elenco di tutte learee e dei relativi argomenti,con link cliccabili. Per ogniarea, inoltre, prevediamo di in-serire due link diretti al com-mento più letto e all'ultimocommento inserito. È chiaroche questa terza parte sarà to-talmente gestita dal database:una volta scritto il codice dellapagina non dovremo più preoc-cuparci di fare nessun aggior-namento. In calce alla homepage, infine, ci saranno i link adue form: uno per scrivere una

mail e uno per iscriversi allamailing list (o cancellarsi).

La pagina principale, quellache conterrà la cosiddetta “bi-blioteca dei commenti”, avràdifferenti tipi di visualizzazionedipendenti dalle scelte effet-tuate nella pagina stessa o nel-la home page. Si potrà, infatti,visualizzare (scegliendo unodei due ordinamenti possibili)tutto l'elenco dei commenti,oppure l'elenco dei commentidi un'area o di un suo argo-mento, oppure vedere il com-mento stesso comprensivo diimmagini. In ogni caso, questapagina dovrà prevedere unabarra di navigazione per poter-si spostare tra le pagine del si-to e un menu grazie al qualescegliere il tipo di visualizza-zione e il tipo di ordinamento.Ulteriore attenzione va postaall'elenco dei commenti: perevitare che diventi troppo lun-go (e quindi poco fruibile) use-remo delle sottopagine, visua-lizzando i dati sintetici di 5commenti per ogni sottopagi-na. Questa pagina è completa-mente gestita grazie al databa-

se sviluppato: la difficoltà, aquesto punto, è solo di pro-grammazione SQL.

Vi sono poi altre due pagine“accessorie”:• scrivici: consente di spedire

commenti sul sito;• mailing list: consente di in-

serire la propria mai per rice-vere la newsletter o per can-cellare l'iscrizione.Le pagine saranno dinami-

che, nel senso che la loro mo-difica sarà determinata diretta-mente dagli aggiornamenti deldatabase e non da modifiche dicodice sui listati HTML e PHP.A noi basterà quindi creare iltemplate della pagina senza oc-cuparci dei contenuti e del lorocambiamento.

La parte amministrativa saràcreata tenendo presente la ne-cessità di stabilire due diffe-renti profili per amministratoree giornalisti. Il primo avrà ac-cesso a tutte le parti configura-bili del database, mentre chiscrive gli articoli avrà un ac-cesso che gli consentirà solo diinserirli nel sistema e modifi-carli (immagini comprese).

3 Il compito del Web Developer

4 Il database

su

Giornalista Commentoscrive

appartiene AreaArgomento

A

1 N

N

1N 1

Page 38: Corso di Php (fonte: PC OPEN)

5a lezione

gine 2). Usando il client a ca-ratteri di MySQL scriviamo in-vece dalla shell DOS (dalla car-tella c:\mysql\bin):

mysql -u root -p// inseriamo la password per entrarenel clientmysql> CREATE DATABASE commenti;mysql> EXIT// siamo usciti dal client mysqlmysql -u root -p commenti <

commenti.sql// eventualmente scrivere il percorsoassoluto del file commenti.sql

5 La struttura del sito

Innanzitutto vediamo il signi-ficato delle cartelle presentinella root del portale :

• nella root c'è solo l'homepage “index.php” dalla qualela navigazione ha inizio. È sem-pre buona norma lasciare solol'home page nella root;

• la cartella “pagine” ospitale pagine che ci consentono divedere i commenti, spedireuna mail, iscriverci alla mailinglist. Sono le pagine “pubbliche”del sito;

• la cartella “servizi” ospita idati della connessione, il fogliodi stile responsabile del layout,

due icone e la pagina che ci re-stituisce i parametri del parserPHP installato (nel caso ci ser-visse controllare i settaggi diPHP;

• le cartelle “admin” e“giorn” servono per la gestionedelle aree protette riservate adamministratore e giornalisti;

• la cartella “img” contienele immagini caricate per illu-strare meglio i commenti. Que-sta cartella dovrà avere i per-messi di scrittura abilitati inmodo da poter effettuare unupload da una pagina Web.

Vista la loro importanza ge-nerale, guardiamo due paginecontenute nella cartella “servi-zi”.

Il file conn.php (listato 1)contiene le impostazioni dellaconnessione al server MySQL(lezione 4) che ospita il data-base “commenti”. Chiaramentequesta pagina deve sempre es-sere “inclusa” nelle altre primadi effettuare qualsiasi tipo dioperazione sulla base di dati.

Il file commenti.css (vedi unapiccola parte nel listato 2, conlo stile applicato per il tagbody) ospita invece le defini-zioni delle formattazioni usatenel sito (tipici esempi possono

essere i colori, i caratteri, le di-mensioni e via dicendo). È untipico foglio di stile e ci facilitanella scrittura della pagina enella gestione delle opzioni dilayout.

Creiamo il database Commenti

1

Azioni per importare struttura e dati nel database Commenti

2

Schema logico relazionale del database Commenti

GIORNALISTA

id_giornalistanomeuserpassworddesce-maildata_inizioattivo

B

1 N

N

N

1

COMMENTO

id_commentoid_giornalistaid_argomentotitolotestodata_inspubblicabileclick

ARGOMENTO

id_argomento*argomentoid_area

AREA

id_area*area

1

NB: le pagine del sito sitrovano tutte all'interno dellacartella CD2/PDF/Corsi/PHP/lezione_5/commenti nel CDGuida 2 che è la radice (root)del sito. Ad essa si farà sempreriferimento indicando ilpercorso relativo della pagine

<?php$nome="commenti";$id_connessione=@mysql_connect('127.0.0.1','root','pluto') or die('Non è possibile accedere al database');

// dati connessione: user=root, password=pluto, indirizzoserver=127.0.0.1, nome database=commenti

@mysql_select_db($nome,$id_connessione) or die("Non èstato possibile accedere al database");

?>Listato 1: servizi/conn.php

body {background-color: #FFFF99;font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;font-size: 11px;width: 750px;

}Listato 2: servizi/commenti.css

Page 39: Corso di Php (fonte: PC OPEN)

5a lezione

6 La costruzione del sito: la parte pubblica

L'home page “index.php”(immagine 3) sarà com-posta da:

• tre testi editabili dall'ammini-stratore del sito. I testi sonoquelli visibili su sfondo giallo;

• una sezione “testi commenti”che consente di vedere tuttigli articoli “pubblicabili” pre-senti nel database;

• N sezioni tante quante sonole aree trattate (nel nostrocaso sono due, ambiente einformatica): per ogni areasarà presente l'elenco degliargomenti e due link veloci al-l'ultimo articolo inserito e al-l'articolo più letto;

• un'ultima sezione in bassocoi link per scrivere i propricommenti al sito o per acce-dere alla mailing list.Per visualizzare i tre testi

scriveremo una query e memo-rizzeremo i risultati su un array$home da richiamare nei puntiopportuni della pagina (listato3). Avremmo anche potutoscrivere tre query diverse perestrarre ogni volta il valore deltesto voluto, ma con la soluzio-ne scelta si fa una sola richiestaal server. I testi sono memoriz-zati nella tabella di servizio “te-sti_admin” e hanno la peculia-rità di contenere la stringa “ho-me_” nell'id_testo che li defini-sce univocamente. Per sfrutta-re questa particolarità utiliz-ziamo la clausola LIKE nellaquery SQL: LIKE consente di fa-re delle ricerche su stringhe ditesto e il carattere di percen-tuale “%” indica il carattere jol-ly. L'array $home memorizzatoin questo modo ha la caratteri-stica di avere come chiave l'i-dentificativo del testo che sivuole stampare e come valoreil testo stesso. È quindi sempli-ce visualizzare il testo volutocon una istruzione echo (necompariranno quindi tre inquesta home page).

<?php// estraggo le descrizioni della homepage e le salvo nell'array $home perusare poi la descrizione dove serve$sql="SELECT id_testo, testo FROM

testi_admin WHERE id_testo LIKE'home_%'";

$ris=mysql_query($sql);while ($tab=mysql_fetch_array($ris)) {$home[$tab[id_testo]]=$tab[testo];}// visualizzo il testo che nella tabella

testi_admin corrispondeall'identificativo 'home_p'echo $home[home_p];?>listato 3: index.php

La sezione “testi commenti”contiene solo istruzioni HTMLperché è sempre fissa: cliccan-do sul titolo si accede alla pa-gina commenti.php visualizzan-do i commenti in ordine decre-scente di data di inserimento,mentre cliccando sul link nelprosieguo del testo si visualiz-zano gli articoli dal più letto almeno letto. In questo secondocaso avremo l'accortezza di in-serire nell'indirizzo del link unavariabile di tipo GET (lezione1) di nome 'ord' e di valore'plus':

// link ai commenti ordinati per datadecrescente<a href="pagine/commenti.php"class="tema">Tutti i commenti</a>// link ai commenti ordinati dal più almeno letto<a href="pagine/commenti.php?

ord=plus" class="arg">commentipiù letti</a>

Più complesso è visualizzareogni singola area con i relativiargomenti e link ai commenti.Dovremo usare delle query ni-dificate: con la prima estrarre-mo nome e codice di ogni re-cord dalla tabella “area”, poi

utilizzando questo codice scri-veremo una seconda query cheestrarrà, dalla tabella “argo-mento”, gli argomenti che si ri-fanno ad esso. Una terza e unaquarta query, infine, sempreusando il codice dell'area, ciconsentiranno di scrivere i linkall'ultimo commento inserito eal più letto.

La prima query $sql_1 è or-dinata in base al nome dell'a-rea: introduciamo nel tag <a>del link una nuova variabileGET di nome “area” il cui valo-re sarà l'identificativo univocodell'area (listato 4). Grazie aquesta variabile cliccando sullink visualizzeremo solo i com-menti di quell'area.

$sql_1="SELECT id_area,testo_areaFROM area ORDER BY testo_area";

$ris_1=mysql_query($sql_1);while ($tab_1=mysql_fetch_array

($ris_1)) {// per ogni area estratta inserisco illink dell'area stessa e scrivo unaquery per ricavare gli argomenti relativiall'areaecho "<div class='tem'><a href=

'pagine/commenti.php?area=".$tab_1[id_area]."'

class='tema'>".$tab_1[testo_area]."</a>

listato 4: index.php

La seconda query, nidificatanel ciclo while della query pre-cedente, serve a scrivere i link

riferiti a tutti gli argomenti del-l'area. Notiamo la presenza (li-stato 5) nella query $sql_2 diun join (legame tra una o più ta-belle che fanno riferimento leune alle altre. Vedi lezione 4): laclausola WHERE, infatti, lega ivalori dell'identificativo dell'a-rea della tabella “area” e dellatabella “argomento”. I link con-tengono una nuova variabileGET di nome “arg” che ha co-me valore l'identificativo uni-voco dell'argomento.

$sql_2="SELECT argomento.testo_argomentoAS testo, argomento.id_argomento AS id FROM argomento,area WHERE argomento.id_area=area.id_area ANDarea.id_area='".$tab_1[id_area]."' ORDER BYargomento.testo_argomento";

$ris_2=mysql_query($sql_2);echo "<span class='normale'> Argomenti: </span>";

while ($tab_2=mysql_fetch_array ($ris_2)) {

// scrivo i link a tutti gli argomenti diquell'areaecho "<a href='pagine/commenti.php

?arg=".$tab_2[id]."' class='arg'>". $tab_2[testo]."</a> | ";

}listato 5: index.php

La terza query $sql_3 (lista-to 6) e la quarta $sql_4 estrag-gono un solo record dalla ta-bella “commento”: rispettiva-mente il codice e il titolo del-l'ultimo commento inserito edel più letto. Ovviamente ilcommento deve appartenereall'area selezionata ed esserestato definito “pubblicabile”dall'amministratore. Il link di-retto al commento è reso pos-sibile dalla presenza della va-riabile GET di nome “comm”che ha come valore l'identifica-tivo univoco del commento:

$sql_3="SELECT commento.titolo, argomento.testo_argomento,commento.id_commento FROM commento,argomento WHEREcommento.pubblicabile='si' ANDcommento.id_argomento=argomento.id_argomento ANDargomento.id_area='".$tab_1[id_area]."' ORDER BY commento.data_ins DESC LIMIT 0,1";

$ris_3=mysql_query($sql_3);$tab_3=mysql_fetch_array($ris_3);echo "<p><span class='normale'>Ultimo articolo inserito: </span>

Home page del portale dei commenti

3

Page 40: Corso di Php (fonte: PC OPEN)

5a lezione

<a href='pagine/commenti.php?comm=".$tab_3[2]."' class='art'>".$tab_3[0]."</a>&nbsp;<spanclass='normale'>[".$tab_3[1]."]</span>";

listato 6: index.php

Ultima annotazione: l'estra-zione di un solo record è con-sentita dalla clausola LIMITpresente nel codice SQL:

LIMIT (X,Y)

Questa clausola limita il ri-sultato ottenuto dall'esecuzio-ne della query, estraendo Y re-cord a partire dalla posizione Xdei record estraibili.

La pagina “biblioteca deicommenti” (file pagine/com-menti.php, immagine 4) sarà in-vece composta da:• una barra di navigazione per

spostarsi tra le pagine;• un menu di navigazione divi-

so per aree tematiche, a lorovolta suddivise per argomen-ti con l'indicazione del nume-ro di articoli inseriti;

• un'area di visualizzazione:cliccando sul nome di un'areao su un argomento si potràvedere la lista dei commenti,lista limitata a 5 commentiper sottopagina. Se un titoloattirasse l'attenzione, basteràcliccarci sopra per ottenerela visualizzazione dell'artico-lo stesso, completo di even-tuali foto.Per la costruzione della bar-

ra di navigazione si rimanda al-la lezione 2. Il codice che con-tiene la barra è nel file pagi-ne/testata.php: il file viene in-cluso in ogni pagina, adattan-dosi dinamicamente alla situa-

zione (il nome della pagina incui ci troviamo sarà scritto ingrassetto e non sarà cliccabi-le).

Il menu di navigazione a si-nistra segue la logica vista nel-la costruzione della home pa-ge. Le differenze riguardanol'aggiunta, a fianco di ogni scrit-ta, di una icona col segno “+” edel numero di commenti con-tenuti in ogni argomento. Clic-cando sull'icona + si ottiene lalista dei commenti ordinatadall'articolo più letto al menoletto: questo è reso possibiledall'aggiunta della variabileGET di nome “ord” e valore“plus” nel riferimento del link.Cliccando sulle scritte, invece,questa variabile non è presentee si otterrà una lista ordinataper data di inserimento decre-scente. Ecco i due link a con-fronto:

echo “<ahref='commenti.php?area=".$tab_1[id_area]."&ord=plus'><imgsrc='../servizi/bluplus.gif' alt='Piùletti' title='Ordina per i piùletti'></a>&nbsp;&nbsp;<ahref='commenti.php?area=".$tab_1[id_area]."'class='tit'>".$tab_1[testo_area]."</a></div>";

Interessante è capire comericavare il numero di articoli diogni argomento. Si usa la clau-sola SQL di raggruppamentoGROUP BY (lezione 4), rag-gruppando tutti i commentipubblicabili che hanno lo stes-so argomento e operando su diessi una operazione di sommadei record (listato 7). Il sugge-rimento è salvare questi valori

in un array $list che ha comechiave l'identificativo univocodell'argomento e come valore ilconteggio appena fatto. Sfrut-tando questo vettore posso ri-cavare anche quanti commentici sono in ogni area (creo il vet-tore $tot_area) facendo unasemplice somma durante il ci-clo while che visualizza gli ar-gomenti di ogni area. I valoriappena ricavati serviranno poiper creare le sottopagine diogni scelta. Sommando tutti ivalori dell'array (con la funzio-ne PHP array_sum) posso an-che ottenere il numero totale didocumenti pubblicabili pre-senti nel database.

// conto quanti record ci sonoraggruppandoli per id_argomento, eregistro il numero nel vettore $list

$sql_3="SELECT id_argomento,COUNT(*) AS num FROM commento WHERE commento.pubblicabile='si'GROUP BY id_argomento";

$ris_3=mysql_query($sql_3);while ($tab_3=mysql_fetch_array

($ris_3)) {$list[$tab_3[id_argomento]]=$tab_3

[num];}listato 7: pagine/commenti.php

La creazione dell'area di vi-sualizzazione di destra è la par-te più complessa della pagina.Dobbiamo infatti controllarel'URL della pagina per verifica-re se ci sono delle variabili GETla cui presenza, col relativo va-lore, determina la costruzionedella pagina. In particolare, al-cune variabili escludono la pre-senza di altre a seconda dellaprecedenza assegnata. Nel no-

stro caso la precedenza è dal-l'alto in basso:• $_GET[comm]=x : verrà vi-

sualizzato (testo e immagini)il commento avente identifi-cativo x;

• $_GET[arg]=y : visualizzazio-ne della lista dei commentiche fanno parte dell'argo-mento di codice y;

• $_GET[area]=z : visualizza-zione della lista dei commen-ti che fanno parte dell'area dicodice z;

• nessuna della variabili prece-denti: viene visualizzata la li-sta completa dei commenti.Altre due variabili possono

trovarsi nell'URL e sono affian-cate alle precedenti:• $_GET[pg]=w : viene visua-

lizzata la sottopagina w (senon c'è vuol dire che non cisono sottopagine);

• $_GET[ord]=plus : ordina-mento dall'articolo più lettoal meno letto.Cosa succede quando nel-

l'URL c'è la variabile “comm”?Con una query estraiamo i datiche ci servono, quindi “stam-piamo” questi dati per visualiz-zare l'articolo (immagine 5).Può essere interessante osser-vare il codice (listato 8) per no-tare un paio di particolari. Leimmagini, ad esempio, posso-no essere al massimo due percommento ($imm1 e $imm2) eil loro nome è legato al codicedel commento (es: il commen-to “12” può avere collegate dueimmagini, nella cartella “img”,denominate “12_1.jpg” e“12_2.jpg”). Con la funzione “fi-le_exists” controlliamo se l'im-magine è effettivamente pre-sente, e solo in caso positivo la

La pagina di navigazione di tutti i commenti pubblicati

4

La visualizzazione di un articolo (con due immagini)

5

Page 41: Corso di Php (fonte: PC OPEN)

visualizziamo. Con questa ge-stione si può evitare di memo-rizzare sul database il legametra il nome dell'immagine e ilcodice del commento. Avendoscelto di vedere l'articolo, inol-tre, devo incrementare il valoredei “click” ad esso riferiti (que-sto valore serve poi a stabilireuno dei due ordinamenti deicommenti): ciò si ottiene conun'opportuna istruzione UP-DATE.

Se invece nell'URL c'è unavariabile “arg” o “area” o nes-suna delle precedenti (il chevuol dire che vanno presiestratti tutti i commenti), dob-biamo scrivere tre query diver-se per ricavare la lista degli ar-ticoli. Le query sono abbastan-za simili, quindi esaminiamoquella che ci consente di vede-re tutti i commenti lasciando ailettori la costruzione delle altredue (c'è solo una condizioneWHERE da aggiungere) vistoche la logica è esattamente lastessa (si deve sempre fare unjoin che coinvolge le tabellecommento, giornalista, argo-mento e area):

$sql_r="SELECT area.testo_area,argomento.testo_argomento,commento.titolo, giornalista.nome,commento.id_commento,date_format(commento.data_ins,'%d-%m-%Y'), commento.click FROMcommento, argomento, area,giornalista WHEREcommento.pubblicabile='si' ANDcommento.id_argomento=argomento.id_argomento ANDargomento.id_area=area.id_area ANDcommento.id_giornalista=giornalista.id

_giornalista ".$ordine." LIMIT".$start.",".$vis;

La variabile $ordine indica iltipo di ordinamento dei recorddella query e si ricava da un ci-clo if effettuato controllando ilvalore di $_GET[ord]: se èuguale a “plus” l'ordinamentosi basa sui click, altrimenti l'or-dinamento si basa sulla data diinserimento:

if (isset($_GET[ord]) AND $_GET[ord]=='plus') $ordine="ORDER BY click DESC, data_insDESC";

else $ordine="ORDER BY data_ins DESC, click DESC";

Per visualizzare N commentiper ogni sottopagina (in questocaso sono 5) usiamo una clau-sola LIMIT nella query: $vis è ilnumero di commenti da visua-lizzare su ogni sottopagina,mentre $start indica da qualerecord partire per ricavare i 5commenti. $start è dinamica,nel senso che il suo valore di-penderà dal numero di sotto-pagina sulla quale ci troviamo.Il database ha 11 commentipubblicabili (2 non sono anco-ra approvati), quindi avremo 3sottopagine (vedi immagi-ne_04): se ci troviamo sulla pri-ma $start avrà valore 0 (il pri-mo record ha sempre posizio-ne 0), sulla seconda $start avràvalore 5, sulla terza $start avràvalore 10.

Il valore di $start sarà quindidipendente dalla variabile$_GET[pg] che indica la sotto-pagina da visualizzare (di de-

fault la sottopagina è una solaed ha quindi valore uno):

if(isset($_GET[pg]) AND $_GET[pg]>0)$sottopagina=$_GET[pg];else $sottopagina=1;// $vis=5 è il numero di commenti davisualizzare per ogni pagina. $start èusato dall'attributo LIMIT delle query$vis=5;$start=($sottopagina-1)*$vis;

Un ultimo sforzo (listato 9)ci consente finalmente di stam-pare l'elenco e creare i link pervedere le sottopagine.

Per prima cosa ci serve il to-tale dei commenti $tot, e que-sto valore lo ricaviamo som-mando i valori dell'array $listdel listato 6. Poi calcoliamo ilresto della divisione (con l'o-peratore “modulo”, lezione 1):se è zero il numero di sottopa-gine sarà dato dalla semplicedivisione $tot/$vis, mentre se èdiverso da zero dovremo ag-giungere 1 al risultato (intero)che si ottiene dalla divisione.

Infine se le sottopagine sonopiù di una faremo eseguire unciclo for per ottenere i link conl'opportuno valore assegnatoalla variabile pg di tipo GET.Cliccando sul link della sotto-pagina, “commenti.php” vienericaricata (le altre variabili GETrestano invariate) e quindi ilvalore $start viene ricalcolato.Infine visualizzare la lista deicommenti con un ciclo while èormai un gioco da ragazzi.

// $tot è il numero di commentipresenti nel DB. Uso la funzione PHPdi somma dei valori di un array

$tot=array_sum($list);$url="";$ur="";// $url e $ur sono usati percompletare il testo del link dellasottopagina. In questo caso sonovuoti, ma se avessimo scelto divisualizzare un'area o un argomentoavremmo dovuto dare loro i valori chepoi consentono di mantenere ilriferimento alla selezioneif ($_GET[ord]==plus)

$url="ord=plus";echo "<em>Elenco di tutti

i commenti:</em><br />";$mod=$tot%$vis;if ($mod==0) $pagine=$tot/$vis;else $pagine=(int) ($tot/$vis)+1;if ($pagine>1) {echo "<span class='colore'>pagine:

</span>";for ($i=1;$i<=$pagine;$i++) {

echo "<a href='".basename ($_SERVER[PHP_SELF])."?".$url.$_

GET[$ur]."&pg=".$i."'>$i</a> ";}echo "<p>";}$ris_r=mysql_query($sql_r);while

($tab_r=mysql_fetch_array($ris_r)) {echo "<strong>".$tab_r[0]." - <em>

".$tab_r[1]."</em></strong><br /><a href='commenti.php?comm=".$tab_r[4]."' class='cap'>".$tab_r[2]."</a> [di ".$tab_r[3]."]<br/><span class='normalemini'>Data:".$tab_r[5]." - click:".$tab_r[6]."</span><p>";

}listato 9: pagine/commenti.php

La pagina “scrivici” (file pa-gine/formmail.php) è un formper spedire una mail all'ammi-nistratore del sito (lezione 2).Compilati i campi, si apre unafinestra (file pagine/risposta-mail.php) che ci informa del-l'avvenuta spedizione dellamail o dell'impossibilità di spe-dirla se anche solo un campo èvuoto. C'è un controllo java-script a monte che verifica senel campo mail c'è una @: vabenissimo usare dei controllijavascript che verificano i cam-pi prima di spedirli al server(PHP lo fa dopo!), però tenetepresente che javascript può es-sere disabilitato da parte del vi-sitatore e quindi i controlli PHPserver-side vanno comunqueinseriti! Per spedire la maildobbiamo estrarre con unaquery l'indirizzo mail dell'am-ministratore: ormai dovrebbeessere un semplice esercizio.

Anche quando si compila lapagina della mailing list vieneaperta una pagina di risposta

5a lezione

$sql_r="SELECT area.testo_area, argomento.testo_argomento, commento.titolo, giornalista.nome, commento.testo,date_format(commento.data_ins,'%d-%m-%Y'), commento.click, giornalista.email, giornalista.descri,commento.id_commento FROM commento, argomento, area, giornalista WHERE commento.pubblicabile='si' ANDcommento.id_commento='".$_GET[comm]."' AND commento.id_argomento=argomento.id_argomento ANDargomento.id_area=area.id_area AND commento.id_giornalista=giornalista.id_giornalista";

$ris_r=mysql_query($sql_r);$tab_r=mysql_fetch_array($ris_r);echo "<strong>".$tab_r[0]." - <em>".$tab_r[1]."</em></strong><p><span

class='titoletto'>".$tab_r[2]."</span><br />[di ".$tab_r[3]."*]<br />";// visualizzo le immagini solo dopo averne verificato la presenza

$imm1="../img/".$_GET[comm]."_1.jpg";$imm2="../img/".$_GET[comm]."_2.jpg";if (file_exists($imm1)) echo "<img src='".$imm1."' class='vis'>";if (file_exists($imm2)) echo "<img src='".$imm2."' class='vis'>";echo "<br />".$tab_r[4]."<p><span class='normalemini'>Data: ".$tab_r[5]." - click: ".$tab_r[6]."<p>*:

".$tab_r[8]."</span><p>";// incremento il valore dei click del commento scelto estraendo il valore attuale, aumentandolo di uno e facendo unaquery di aggiornamento

$cont=$tab_r[6]+1;$incr="UPDATE commento SET click='".$cont."' WHERE id_commento='".$tab_r[9]."'"; mysql_query($incr);

listato 8: pagine/commenti.php

Page 42: Corso di Php (fonte: PC OPEN)

5a lezione

(file pagine/rispostamailing.php) che ci informa se tutto èandato bene (immagine 6) omeno. Questa pagina verifica lacorrettezza dei dati inseriti(per cancellarsi basta inseriresolo la mail, per iscriversi ser-ve anche il nome) e “capta” iltasto premuto sul form: se ci sivuole iscrivere viene eseguitauna query di inserimento:

$query="INSERT INTO mailing (email,nome) VALUES

('".$_POST['email']."','".$_POST['nome']."')";

mysql_query($query);

altrimenti viene eseguita unaquery di cancellazione:$query="DELETE FROM mailing WHERE email='".$_POST['email']."'";

mysql_query($query)In entrambi i casi viene spe-

dita una mail di conferma (èuna ottima abitudine farlo!) al-l'indirizzo mail inserito e al-l'amministratore.

Il sito pubblico è costruito,ma adesso bisogna gestirloinserendo commenti, imma-

gini, aree, argomenti, giornali-sti, testi. In poche parole vacreata l'area di gestione. Nelnostro caso la situazione è an-cor più complessa perché diaree di gestione dovremocrearne due: una per l'ammini-stratore e una per i giornalisti.

Area di gestionedell'amministratore

Tutte le pagine sarannochiaramente protette da ac-cessi indesiderati grazie ad unsistema di autenticazione ba-sato su username e password.Nella lezione 2 avevamo vistocome implementare un siste-ma statico di accesso memo-rizzando user e password di-rettamente nella pagina Web,ma usare MySQL ci consentedi registrare i dati su una ta-bella, rendendoli quindi facil-mente modificabili in caso dibisogno.

La prima operazione dacompiere, quindi, è validarel'inserimento dei dati, propa-gando poi l'accesso a tutte lepagine oggetto di gestione sen-za che si debbano reinserire idati di autenticazione. Per farequesto useremo le sessioni: al

login (to log in = connettersi)verificheremo i dati inseriti, ein caso di riscontro positivosalveremo questa risposta inuna variabile di sessione cheverrà cancellata al momentodel logout (e comunque allachiusura del browser)

Per accedere ad una paginaprotetta dobbiamo per primacosa creare un form di autenti-cazione (immagine 7) dei dati(file admin/index.php) compo-sto da due caselle di testo“user” e “pwd” (listato 10):

<form action="admin.php" method="post">

<input type="text" name="user" size="30"> username<br />

<input type="password" name="pwd" size="30"> password<p>

<input type="submit" name="invio" value="Connetti">

</form>listato 10: admin/index.php

I dati inseriti (i nostri soliti“root” e “pluto”) vengono spe-diti alla pagina admin/ad-min.php e lì controllati richia-mando il file “admin/auth.inc.php”. Questo file compie duecontrolli (vedi listato 11):• per prima cosa avvia una

sessione controllando se esi-sta già la variabile di sessio-

ne $_SESSION['ok']. Se esiste,verifica che il suo valore sia“true” e in caso positivo con-cede l'accesso alla pagina.Questo controllo serve adevitare di reinserire i dati diautenticazione nel caso tor-nassimo a questa pagina dauna delle altre pagine di am-ministrazione;

• se il primo controllo fallisce(ossia non c'è alcuna sessio-ne già iniziata che abbia unavariabile di nome “ok” convalore “true”) parte il pro-cesso di autenticazione veroe proprio. La prima verificacontrolla che i campi delform esistano, quindi, dopoaver effettuato il collegamen-to al database, viene eseguitala query $sql che ritornerà,se i dati inseriti sono corret-

ti, l'unico record della tabella“amministrazione”. Verificoche il risultato dell'interro-gazione contenga una sola ri-ga: in questo caso è consen-tito l'accesso alla pagina eviene registrato il valore“true” per la variabile di ses-sione “ok”, altrimenti il cari-camento della pagina è bloc-cato e compare un messag-gio di avvertimento.Chiaramente il file auth.inc.

php sarà incluso in testa adogni pagina di amministrazio-ne.

È da notare l'uso nella query$sql della funzione PASSWORDla quale crittografa (a 16 bit) ilvalore inserito nel form e loconfronta col valore, anch'es-so crittografato, contenuto nel-la tabella. Questo serve esclu-

7 La costruzione del sito: le pagine di gestione

L’iscrizione alla mailing list è andata a buon fine

6

Form di connessione alle pagine di gestione dell'amministratore

7

Una parte delle opzioni di gestione dell'amministratore

8

Page 43: Corso di Php (fonte: PC OPEN)

sivamente per aumentare la si-curezza: anche se una perso-na, infatti, avesse casualmenteaccesso alla tabella “ammini-strazione”, non avrebbe la pos-sibilità di recuperare la pas-sword. Possiamo anche usarealtre funzioni di crittografia co-me MD5() e SHA1().

Finalmente abbiamo acces-so alla pagina generale di am-ministrazione (immagine 8, file“admin/admin.php”). La pagi-na è composta da tanti formche rimandano a pagine in cuisi compiono le azioni specifi-che deputate al ruolo di ammi-nistratore. Una della azioni, adesempio, è quella di approvare

e rendere pubblicabili i com-menti inseriti dai giornalisti.Per far questo il form ci con-sente di scegliere uno tra gli ar-ticoli non ancora pubblicatigrazie ad una casella a discesaalimentata da una query:

<select name="id" size="1" class="but">

<?php$sql="SELECT id_commento,

LEFT(titolo,40) FROM commentoWHERE pubblicabile='no' ORDER BY data_ins";

$ris=mysql_query($sql);while ($tab=mysql_fetch_array($ris)) {echo "<option value='".$tab[0]."'>".

$tab[1]."</option>";

}?></select>

Nella casella a discesa sonovisualizzati i primi 40 caratteridel titolo del commento, ma al-la pagina successiva è passatocon la variabile $_POST[id] ilvalore dell'identificativo delcommento (ossia la chiave).La pagina che si apre (non c'èbisogno di reinserire i dati diamministratore perché la ses-sione è già stata validata inprecedenza) riporta l'articolocome verrebbe pubblicato.L'amministratore può renderlodisponibile sul sito cliccando

su “Approvato”, oppure torna-re alla pagina generale di am-ministrazione senza convali-darlo. Nel primo caso (listato12) viene eseguita una query diaggiornamento su quel com-mento (il valore chiave delcommento è memorizzato su$_POST[id] che dobbiamocontinuare a propagare inse-rendolo come valore nascostoanche nel form di questa pagi-na. In alternativa avremmo do-vuto salvare il valore in una va-riabile di sessione), modifican-do il valore del campo “pubbli-cabile” da 'no' a 'si', e viene an-che mandata una e-mail all'au-tore del commento, dopo aver-ne estratto l'indirizzo mail, perinformarlo che il suo articolo èadesso disponibile per la lettu-ra sul sito.

Cliccando su “Approvato” ècomparsa (se avete javascriptattivato) una finestrella di con-ferma (immagine 9) che vichiede se siete sicuri dellascelta fatta: questa finestra,utile per evitare di fare erroridovuti alla fretta, si ottienesemplicemente inserendo “on-submit” nella riga di intesta-zione di un form:

<form method="post" action="adminnews.php"class="formadmin" onsubmit="return window.confirm('Sei sicuro? Confermi la scelta?');">

La pagina (file admin/ad-mincomm.php) che consentela cancellazione di un com-mento e delle immagini ad es-so collegato è molto simile allaprecedente, salvo che la querysarà di cancellazione e le im-magini, se ci sono, sarannocancellate con la funzione un-link (lezione 3):

$cancellato="DELETE FROMcommento WHERE

id_commento='".$_POST[id]."'";mysql_query($cancellato);// cancello le immagini$imm1="../img/".$_POST[id]."_1.jpg"; �

5a lezione

<?phpsession_start();// dopo aver inizializzato la sessione, faccio il primo controllo per verificare se era già stata fatta l'autenticazioneif (isset($_SESSION['ok'])) {if ($_SESSION['ok']!==true) die ("interrompi tutto");}// se è la prima volta che accedo in questa sessione, verifico i dati inseriti nel formelse {if (!isset($_POST['user']) or !isset($_POST['pwd'])) {die("Per accedere a questa pagina devi inserire login e password");}// questo include mi rimanda alla pagina coi dati di connessione al databaseinclude "../servizi/dati.php";$sql="SELECT * FROM amministrazione WHERE user='".$_POST['user']."' AND pwd=PASSWORD('".$_POST['pwd'] ."')";$ris = mysql_query($sql);$righe=mysql_num_rows($ris);if ($righe==0) {// non c'era alcuna riga nella tabella che avesse quei valori di user e passworddie ("Mi spiace, user e password non sono corrette. Controlla meglio l'inserimento");}elseif ($righe==1) {// accesso consentito e contemporanea registrazione della variabile di sessione$_SESSION['ok']==true;}}?>listato 11: admin/auth.inc.php

$approvato="UPDATE commento SET pubblicabile='si' WHERE id_commento='".$_POST[id]."'";mysql_query($approvato);echo "<span class='titoletto'>Il commento è stato approvato ed è quindi adesso disponibile sul sito Internet.

E' stata spedita una mail di conferma all'autore.</span><p>";// da qui in poi creo la mail automatica da mandare all'autore$sql_g="SELECT commento.titolo, giornalista.email FROM commento, giornalista WHERE

commento.id_commento='".$_POST[id]."' AND commento.id_giornalista=giornalista.id_giornalista";$ris_g=mysql_query($sql_g);$tab_g=mysql_fetch_array($ris_g);$to=$tab_g[1];$subject="Approvazione commento";$object="Ciao, il tuo commento dal titolo \"".$tab_g[0]."\" è stato approvato ed è quindi disponibile da adesso nel

sito internet.\n\nL'amministratore";$sql="SELECT email FROM amministrazione";$ris=mysql_query($sql);$tab=mysql_fetch_array($ris);$from="From:".$tab[email];mail($to,$subject,$object,$from);listato 12: admin/adminconv.php

Una semplice richiesta di conferma (injavascript) ci può far evitare dicommettere errori

9

Page 44: Corso di Php (fonte: PC OPEN)

5a lezione

// percorso e nome dell'eventualeimmagine 1$imm2="../img/".$_POST[id]."_2.jpg";// percorso e nome dell'eventualeimmagine 2if (file_exists($imm1)) unlink($imm1);if (file_exists($imm2)) unlink($imm2);

Le pagine che consentono diinserire nuove aree (file ad-min/adminarea.php), nuovi ar-gomenti (file admin/admi-narg.php) o nuovi giornalisti(file admin/admingiorn.php)contengono un form compilatonel quale viene eseguita unaquery di tipo INSERT. Dallestesse pagine possiamo anchemodificare o cancellare aree,argomenti e giornalisti: in que-sto caso avremo di fronte unform vuoto e due pulsanti permodificare o cancellare i datidel record già selezionato nellapagina generale (l'identificati-vo del record è sempre tra-smesso e propagato con unavariabile POST). L'azione dimodifica (il listato 13 si riferi-sce alla modifica di un argo-mento) si basa su una serie diif che controllano se i campidel form siano vuoti: se non losono viene aggiunta l'istruzio-ne specifica che finirà poi nellaquery UPDATE effettuata sulrecord selezionato.

La cancellazione, invece, im-pone un controllo preliminareper conservare l'integrità deldatabase: un giornalista, infat-ti, si può eliminare solo se nonha mai scritto commenti e, allostesso modo, argomenti e areepossono essere cancellati solose non sono già legati ad un ar-ticolo.

Per compiere la verifica siscrive una query come que-sta:

$sql_c="SELECT id_commento FROMcommento WHEREid_argomento='".$_POST[id]."'";

Se da questa query non èestratta alcuna riga(mysql_num_rows=0) alloraposso effettuare la cancella-zione, altrimenti l'operazionenon può essere effettuata.

Nel caso dei giornalisti lacosa è aggirabile grazie al cam-po “attivo”: modificando il va-lore di questo campo e ponen-dolo a 'no' è possibile bloccarel'attività del giornalista (nonpotrà più accedere all'area ri-servata e inserire articoli) sen-za cancellare i suoi dati dal da-tabase.

Ormai siamo esperti e modi-ficare i testi o i nostri dati diamministratore (la nuova pas-sword va inserita due volte perevitare errori di battitura) e gliiscritti alla mailing list non cispaventa.

Può essere interessante ve-dere come viene gestita la spe-dizione della newsletter. L'ulti-ma data di spedizione è me-morizzata nella tabellatesti_admin, e questa data vie-ne usata, al caricamento dellapagina admin/adminnews. php,per estrarre la lista degli arti-coli (immagine 10) che sonostati pubblicati da quella datain avanti:

$q="SELECT testo, date_format (testo,'%d-%m-%Y') FROM testi_adminWHERE id_testo='news'";

$r=mysql_query($q);$t=mysql_fetch_array($r);echo "L'ultima volta che hai spedito

la newsletter era il giorno <strong>".$t[1]."</strong><br/>Dopo di allora sono stati pubblicati questi commenti:<p>";

$sql="SELECT titolo, date_format(data_ins,'%d-%m-%Y') FROM commento WHERE pubblicabile='si' AND data_ins>=".$t[0]." ORDER BY data_ins";

L'amministratore deve solo,se vuole, inserire un testo di ac-compagnamento alla newslet-ter e poi premere il tasto “Spe-disci”: automaticamente lanewsletter verrà spedita agliiscritti (per rispetto della pri-vacy tutti gli indirizzi sarannoin campo nascosto Bcc) e con-terrà l'indicazione dei nuovicommenti. Sempre automatica-

mente viene aggiornata la datadi ultima spedizione della new-sletter inserendo la data odier-na (lezione 1):

// aggiorno la data dell'ultimaspedizione con la data odierna$agg="UPDATE testi_admin SET

testo='".date('Y').date('m').date('d')."' WHERE id_testo='news'";

mysql_query($agg);

Adesso non ci resta che clic-care su logout (lezione 2) euscire dalla gestione dell'am-ministratore.

Area di gestione del giornalista

Ogni giornalista presente neldatabase (in stato attivo) puòaccedere ad un'area di gestionespecifica dalla quale potrà in-serire e modificare commenti efoto, chiederne la cancellazio-ne all'amministratore (non puòfarlo direttamente per sceltadell'editore) e infine modificare

Elenco dei commenti pubblicati dall'ultima spedizione della newsletter

10

$mod="";if (trim($_POST[arg])!="") $mod.= "testo_argomento='".trim($_POST[arg])."', ";if (trim($_POST[area])!="") $mod.= "id_area='".trim($_POST[area])."', ";if ($mod!=="") {$mod=rtrim($mod,", ");// questo rtrim elimina la virgola e il carattere vuoto che si trovavano nellaparte destra di $mod$modifica="UPDATE argomento SET".$mod." WHERE

id_argomento='".$_POST [id]."'";mysql_query($modifica);echo "<span class='titoletto'> Aggiornamento dell'argomento effettuato

</span><p>";}listato 13: admin/adminarg.php

$sql="SELECT id_giornalista FROM giornalista WHERE attivo='si' AND user='".$_POST['user']."' AND password=PASSWORD('".$_POST['pwd']."')";

$ris = mysql_query($sql);$tab=mysql_fetch_array($ris);$righe=mysql_num_rows($ris);if ($righe==0) {die ("Mi spiace, user e password non sono corrette o non sei più inserito nel database dei giornalisti.

Controlla meglio l'inserimento");}elseif ($righe==1) {// accesso consentito e contemporanea registrazione della variabile di sessione di accesso e di una variabile disessione che distingue un giornalista dall'altro$_SESSION['ok']=true;$_SESSION['id_giorn']=$tab[0];}listato 14: giorn/auth.inc.php

Page 45: Corso di Php (fonte: PC OPEN)

5a lezione

i propri dati di accesso.La logica di accesso è uguale

a quanto visto, ma diversa-mente dal caso dell'ammini-stratore unico, l'autenticazio-ne (il form di accesso si trovanel file giorn/index.php) dovràmemorizzare l'identificativounivoco del giornalista e verifi-care lo stato della sua registra-zione bloccando l'accesso aigiornalisti disattivati.

Usiamo allo scopo il filegiorn/auth.inc.php (listato 14)introducendo un nuovo con-trollo sulla query di accesso einizializzando una variabile disessione di nome “id_giorn”che memorizza il valore dellachiave identificativa del gior-nalista.

Questa nuova variabile ser-ve ad impedire che un giornali-sta possa vedere e modificaregli articoli e i dati degli altrigiornalisti.

Entriamo nella pagina gene-rale (immagine 11): inseriamocome user il nome del giornali-sta (es: “giuseppe”) e comepassword il cognome (es: “ver-de”), entrambi minuscoli. Pro-viamo poi a vedere cosa succe-de usando il giornalista giovan-ni bianchi che è stato disabili-tato.

Riguardo le pagine di gestio-ne coinvolte, vale la pena spen-dere due parole sull'inserimen-to delle immagini (lezione 3),operazione contestuale all'in-serimento del testo di un com-mento (file giorn/giornins.php).

Nel caso decidessi di inseri-re una o due immagini dovrò ri-

spettare tre condizioni decisein fase di costruzione del sito:larghezza e altezza dovrannoessere minori di 120 pixel el'immagine dovrà essere di tipoJPG.

Per controllare il rispetto diqueste regole uso la funzionePHP getimagesize, registrandoi valori ottenuti (larghezza, al-tezza, tipo e attributi dell'im-magine) in una serie di variabi-li grazie alla funzione list:

list($width1, $height1, $type1, $attr1) = getimagesize($_FILES ['immag']['tmp_name'][0]);

// l'immagine sarà caricata se$width1<=120, $height1<=120 e

$type1=2 (il valore 2 indica un file jpg)

Passati questi controlli devocaricare l'immagine sul serverdandole come nome il codicedel commento cui si riferisce.Per ricavare il codice identifi-cativo (chiave) uso la funzionemysql_insert_id che mi resti-tuisce proprio il codice checerco (estrae il valore del cam-po autoincrementale presentenell'ultima query di inserimen-to dell'articolo), quindi caricol'immagine con move_uploa-ded_file e infine rinomino (fun-zione rename) l'immagineusando la codifica decisa in fa-se progettuale:

$percorso="../img/";$dir1=$percorso.$_FILES['immag']['name'][0];

$id_c=mysql_insert_id();if($_FILES['immag']['name'][0]) {move_uploaded_file($_FILES['immag']

['tmp_name'][0], $dir1);

rename ($dir1,$percorso.$id_c."_1.jpg");

}

Contestualmente all'inseri-mento del commento vienemandata una mail all'ammini-stratore (copia al giornalista)per avvertirlo che c'è un nuovocommento da approvare per lapubblicazione sul sito.

Un giornalista può poi modi-ficare (file “giorn/giornmod.php”) uno dei suoi articoli(comprese le immagini), peròin questo caso il commentomodificato viene reso nuova-mente “non pubblicabile” e vie-ne mandata una mail all'ammi-nistratore per informarlo chedeve ricontrollare il commentomodificato per approvarlo.

Il giornalista non può can-cellare i propri articoli, ma puòchiedere all'amministratore, at-traverso il form della pagina“giorn/giorncanc.php”, di far-lo: anche in questo caso all'am-ministratore arriverà una mailcon la richiesta.

Con il logout usciamo ancheda questa area di amministra-zione

Il sito dei commenti è adessopronto per essere gestito e ag-giornato, e tutte queste opera-zioni non saranno più compiu-te modificando il codice dellepagine. Il compito del WebDe-veloper è finito!

ConclusioniIl corso WebDeveloper PHP

(e MySQL) finisce qui, dopo 5lezioni, con questo esempio ap-plicativo da studiare e riadat-tare secondo le proprie esigen-ze.

Lo scopo del corso era far in-tuire le potenzialità di un lin-guaggio open-source server si-de come PHP, utilizzabile conprofitto sia in modalità standalone sia in coppia con un qual-siasi DBMS allo scopo di svi-luppare siti dinamici. E proprioin un'ottica di completezza diformazione del WebDeveloper,sono stati approfonditi anche iconcetti di base, teorici e pra-tici, della creazione di un data-base.

Gli esempi trattati sono statipresi da esperienze reali “sulcampo”, ma, al solito, possonoessere considerati solo un pun-to di partenza per raggiungerenuovi traguardi... il limite, ge-neralmente, è dato dalla nostrafantasia.

Buon lavoro a tutti! �

Le opzioni di gestione del giornalista

11

Gli altri corsida Webmasterdisponibilinel CDNel CD Guida 2 allegatoa questo numero di PCOpen, all’interno dellacartella PDF/Corsi, trovatedue corsi completi chepossono essere un utilecomplemento al corso PHP.Uno è il corso WebDeveloper ASP, 97 paginesuddivise in quattro lezioniper capire come realizzaresiti dinamici in tecnologiaASP.

Il corso Webmaster spiega,invece, in 88 paginesuddivise in otto lezioni tuttoquello che bisogna sapere per costruire un sito e imparare il linguaggioHTML 4.01, i CSS (fogli di stile), Java Script e CGI. Il corso è completato da utiliconsigli per promuovere il proprio sito on line.