Il sito per imparare gratuitamente a fare pagine Web

Corso PHP














Questa guida non è stampabile per volontà del suo stesso autore Claudio Curci.



Guida PHP scritta da Claudio Curci - Aggiornamenti di Max Kiusso

lezione 10: Un guestbook PHP, un solo file

Sommario lezione

. Un unico file????
. Come PHP legge gli altri campi form
. Reference mysql: i campi stringa



Un unico file????

Nella scorsa lezione abbiamo "irrobustito" il guestbook. In questa, ne creeremo una variante. Il guestbook creato finora non avrà nulla da invidiare a quello che programmeremo oggi. Non pensate però di trovarvi di fronte ad una lezione inutile!
I passaggi e le istruzioni che vedremo oggi si riveleranno fondamentali per capire altre applicazioni PHP. Il guestbook si presta bene ad illustrare con approccio pratico il discorso, perciò lo utilizziamo volentieri.
L'applicazione creata nelle precedenti lezioni é basata su tre file:

. un comune modulo ("form") html;
. un file che elabora i dati provenienti dalla form e li inserisce nel database;
. un file di lettura dati inseriti

"Spalmare" un guestbook su tre file non comporta errori, ma una gestione basata in un unico documento facilita la manutenzione del codice. Utilizzeremo quest'opportunità per chiarire definitivamente il discorso delle variabili passate dalla url (ho visto sul forum un pò di confusione in merito) ed introdurre aspetti avanzati della programmazione PHP. Alcuni di voi staranno magari pensando che di "aspetti avanzati" poco interessa, ma sicuramente in futuro vi troverete davanti script scaricati dalla rete da personalizzare, da oscommerce a phpnuke ad un forum. Se volete padroneggiare gli script scaricati, gli "aspetti avanzati" diventano "aspetti imprescindibili".

Per gestire un'applicazione in un unico file, non occorrono soluzioni geniali. Basta trasferire su pc la stessa tecnica che utilizza un comune essere umano. Una persona è solitamente dotata di gambe, braccia, bocca, occhi, mani, piedi.. ma non usa contemporaneamente tutti queste cose! Se cammina, muoverà una gamba alla volta, e bilancerà l'andatura con il braccio opposto; se con una mano scrive, con l'altra difficilmente pianterà un chiodo su una parete.
Si tratta quindi di dotare il nostro file delle funzioni necessarie per la gestione del guestbook (e fin qui basterebbe prendere i tre file, copiarli ed incollarli in uno), creando però un sistema di gestione che gli faccia capire quando deve visualizzare la form, quando deve elaborarla, quando deve leggere i dati.
Una possibile soluzione è di inserire il codice dentro uno switch. La condizione valutata può essere passata nella url.
Ad esempio:

guestbook.php?azione=inserisci
visualizza la form;

guestbook.php?azione=elabora
elabora i dati inseriti;

guestbook.php?azione=leggi
mostra in output i messaggi.

Le variabili passate nella url sono raggiungibili dal codice attraverso l'array $_GET. Vale lo stesso discorso che abbiamo visto nella lezione sulla form (array nuovi, vecchi ecc.). Il funzionamento di $_GET è lo stesso di $_POST. Unica differenza, il primo elabora i dati passati nella url, il secondo quelli di una form (sempre che il method sia stato impostato a POST, altrimenti sarà GET).
$_GET['azione'] sarà quindi la base del nostro switch.
Creiamo il nostro file "guestbook.php":

<?php
$connessione=mysql_connect("localhost", "root", "");
$selezione_db=mysql_select_db("guestbook", $connessione);
?>
<html>
<head>
<title>Guestbook</title>
</head>
<body>
   <?php
     switch($_GET['azione']){
       case "inserisci":
       break;
       case "elabora":
       break;
       case "leggi":
       break;
   }//switch sulla variabile "azione" passata nella url
   ?>
</body>
</html>

Abbiamo cosi creato lo "scheletro" della nostra pagina. Sotto ciascun case, possiamo adesso inserire lo stesso codice dei famosi tre file creati nelle due precedenti lezioni.
Ovviamente, basterà inserire il solo codice PHP di gestione del guestbook, evitando i tag html di apertura/chiusura pagina head,title ecc. (ormai tutto è contenuto in un solo file).
Abbiamo tre modi di inserire il codice nello switch. Il primo consiste in un semplice copia/incolla. E' una soluzione alquanto scomoda. Pensate di dover prendere il codice di form.html e doverlo incollare sotto il primo case. Quella pagina non contiene istruzioni php, ma semplice html.. Se lo copiassimo brutalmente sotto il case avremmo un errore. Possiamo inserire html in frammenti php con l'istruzione echo, vista nella prima lezione.
Rimane però il problema dei doppi apici. La prima riga del form era:

<form name="moduloGuest" action="elabora_guest.php" method="post">

Gli attributi del tag (name, action, method) contengono tutti doppi apici, cosi php non saprebbe quando terminare la stringa e genererebbe errore. Dobbiamo ricorrere al carattere di escape:

echo "<form name=\"moduloGuest\" action=\"elabora_guest.php\" method=\"post\">";

Dover passare a mano tutte le righe html alla ricerca di doppi apici è davvero scomodo.
Nulla ci vietà però di "mischiare" PHP e html, chiudendo temporaneamente il tag di codice. Avvertiamo la pagina dicendo "valuta lo switch, se è valido il primo case, non eseguire php ma interpreta quanto segue come codice html". Un esempio pratico (mi limito alla prima riga della form):

<?php
switch($_GET['azione']){
case "inserisci":
?>
<form name="moduloGuest" action="elabora_guest.php" method="post">
<php?
break;

Ricordatevi, al termine del codice html della form, di riaprire il tag php, altrimenti non verreppe eseguito il resto dello switch (a prescindere dal fatto che le altre istruzioni non saranno verificate come vere, trovereste un errore perchè PHP inizierebbe lo switch ma non riuscirebbe a trovare la parentesi graffa di chiusura..)

Ai più attenti non sarà sfuggito che l'action della form va ovviamente cambiata (gestiremo tutto in un solo file, non serve un "elabora_guest"), ma su questo ci concentreremo in seguito.

La seconda soluzione è quella di creare un file da includere, inserendo dentro il codice html della form.

<?php
switch($_GET['azione']){
case "inserisci":
include("modulo.html");
break;

Attenzione: in modulo.html va soltanto il codice della form (e della tabella che la impagina), non i tag html di apertura/chiusura pagina perchè quelli sono già in guestbook.php! L'include fa esattamente quello che faceva la prima soluzione, in modo però più leggibile e facile da gestire.

Con l'istruzione include() il parser capisce che deve prendere e dare in output il contenuto del file modulo.html nella pagina. Non occorrono quindi nè caratteri di escape, nè chiusure/riaperture dei tag php. Rispetto alla prima soluzione, si tratta di un bel passo avanti. Possiamo creare altri due file copiando/incollando il codice php di elabora_guest e read_guest. In questo caso ricordatevi di aprire, all'inizio di questi due file, il tag php e di chiuderlo alla fine, altrimenti l'include() non riuscirebbe ad interpretarli.

La seconda soluzione proposta ci riporta però al punto di partenza.. invece di tre file ne abbiamo addirittura quattro! Il meccanismo utilizzato ci è però "trampolino di lancio" per capire uno dei concetti fondamentali di PHP e dei linguaggi C-Like (Javascript compreso): le funzioni.
Una funzione (detto anche "metodo") migliora la gestione del codice.
Possiamo creare una funzione "read_guest()" (le parentesi dopo il nome sono obbligatorie, vedremo poi a cosa servono) e scrivere il codice creato in precedenza.

Ecco una prima bozza del nostro file (a proposito, il codice di read_guest è completo del "compitino" della scorsa settimana, quindi stampa a video le righe a colori alternati):

<?php
$connessione=mysql_connect("localhost", "root", "");
$selezione_db=mysql_select_db("guestbook", $connessione);
?>
<html>
<head>
<title>Guestbook</title>
</head>
<body>
<?php
function read_guest(){
$lettura_risultati=mysql_query("select nome_utente, messaggio, date_format(data_ora, 'in data %d/%m/%Y - ore %H:%i:%s') as data_formattata from messaggi order by data_ora")or(die(mysql_error()));
if(mysql_num_rows($lettura_risultati)>0){
echo "<table>";
$flag_colore=0;
while($scatola_temporanea=mysql_fetch_array($lettura_risultati)){
echo "<tr>";
if($flag_colore==0){
echo "<td bgcolor=\"#FFFF00\">";
$flag_colore=1;
}
else{
echo "<td bgcolor=\"#C0C0C0\">";
$flag_colore=0;
}
echo "L'utente " . stripslashes( $scatola_temporanea['nome_utente'] ) . ", " . $scatola_temporanea['data_formattata'] . ", ha scritto:<br><br>" . stripslashes( $scatola_temporanea['messaggio'] ) . "</td>";
echo "</tr>";
} //fine ciclo while che scorre la query e piazza i risultati nell'array temporaneo
echo "</table>";
}
else{ //se non ha trovato record
echo "complimenti! nessuno ha finora inserito un messaggio.. tu puoi essere il primo!! <a href=\"form.html\">che aspetti??</a>";
}
}//fine function read_guest()

switch($_GET[azione]){
case "inserisci":
break;
case "elabora":
break;
case "leggi":
read_guest();
break;
}//switch sulla variabile "azione" passata nella url
?>
</body>
</html>

Purtroppo il codice diventa ormai parecchio, e non conviene indentarlo in html a forza di "&nbsp;". Per questo a volte torno ad utilizzare le textarea, dove gli spazi sono automatici. Non sempre però una riga riesce a stare nello schermo (ci vorrebbero.. 3000 pixel), quindi ricordate di andare a capo soltanto quando trovate il punto e virgola. In ogni caso, se copiate e incollate il testo della textarea su un editor, gli a capo originali vengono riconosciuti.
Lanciate adesso il file (dopo aver avviato easyphp) guestbook.php. Ricordate però anche il parametro dalla url, altrimenti non entrerebbe mai nello switch:

http://localhost/guestbook/guestbook.php?azione=leggi

Se avete messaggi nel db, dovreste vederli adesso a colori alternati.
Cosa è accaduto? Abbiamo scritto una funzione, read_guest() (potevamo chiamarla come volevamo, attenti però ad evitare caratteri strani, numeri e segni di spazio nel nome). Il codice adesso è li, pronto per venir eseguito. La funzione sta buona buona finchè qualche parte del programma non la chiama, ed è quello che fa lo switch quando incontra la variabile azione (passata nella url) con valore "leggi". E' quello che facciamo noi umani con la mano.. la nostra function mano() è pronta per l'uso, ma afferrerà qualcosa soltanto quando il cervello darà l'ordine di farlo. Così la nostra function bocca() sa come si parla, ma lo farà quando avrà qualcosa da dire.

Lo "switch" smista e regola, come il nostro cervello o come un regista in una squadra di calcio, i comportamenti verso le function adatte.

Se il discorso vi è un pò indigesto, rileggete la lezione e chiedete nel forum di web-link. Se capirete le function potrete mettere mano a codici "mostruosi" (per ampiezza e complessità) come quelli dei portali.
L'esempio fin qui creato funziona solo nella lettura del guest, per gli altri case servono altre due funzioni.
Lascio a voi il compito di elaborarle, credo sia il modo migliore per apprendere concetti. Prima però é bene che veniate a conoscenza di un paio di nozioni. Per la funzione che stampa a video la form (normale html), vi conviene chiudere i tag. Esempio:

function paint_form(){
?>
<form name="modulo" ecc.>
<?php
}//chiusura function paint_form()

La funzione che invece elabora la form, deve risalire alle variabili passate dalla pagina precedente.
Una function non può gestire variabili esterne, se queste non sono dichiarate globali. Eseguite questo esempio per toccare con mano (o per visualizzare a video, come volete :) il discorso:

<?php
$variabile_prova="Diego";//questa variabile è creata all'esterno della function
echo $variabile_prova;
function testa_variabile(){
echo "<br>la variabile di prova ha valore: " . $variabile_prova . "<br>"; //cosa vi stampa?
}
//richiamiamo adesso la funzione, altrimenti non verrebbe mai eseguita
testa_variabile();
?> 

Avete visto cosa succede? La variabile $variabile_prova è stata dichiarata fuori dalla function. Le è stato anche assegnato un valore stringa. Se proviamo ad utilizzarla dentro una function (nel nostro esempio, una stampa a video) vediamo che non otteniamo nulla. E' come se la variabile non esistesse.
Provate invece quest'altro esempio:

<?php
$variabile_prova="Diego";//questa variabile è creata all'esterno della function
echo $variabile_prova;
function testa_variabile(){
global $variabile_prova;
echo "<br>la variabile di prova ha valore: " . $variabile_prova . "<br>"; //cosa vi stampa?
}
//richiamiamo adesso la funzione, altrimenti non verrebbe mai eseguita
testa_variabile();
?> 

Con l'istruzione global $nomevariabile abbiamo istruito la funzione in modo che risalga alla variabile esterna.
Nel primo esempio, la function stampava una variabile nulla; nel secondo, la variabile dichiarata precedentemente.

Utilizzando l'array $_POST o $_GET, non avete bisogno di dichiarare globali i dati della form.
$_POST e $_GET vengono infatti riconosciuti come "superglobale" da PHP, ovvero visibile ovunque, anche all'interno delle function.

Ultimo suggerimento: l'action della form deve essere "guestbook.php?azione=elabora". Per lanciare il file visualizzando la form dovete passare nella url la variabile azione. Potete creare un menù con normali link html, oppure digitare a manina nel browser "guestbook.php?azione=leggi", "azione=inserisci" ecc.
A questo punto avete a vostra disposizione tutte le informazioni per risolvere il guestbook con un unico file.

Non vorrei annoiarvi troppo con la lezione sulle function (in futuro la troverete "preziosa", ma per ora magari vi sembra solo una difficoltà in più), vediamo qualcosa di pratico.
Prima riepiloghiamo però i concetti base delle funzioni:

Le funzioni facilitano il lavoro
Rendono più leggibile il codice, più intuibile l'interpretazione dei costrutti switch/if, semplificano il lavoro di più persone sulla stessa applicazione;

Le funzioni contengono normale codice php
Le function ospitano, al loro interno, lo stesso codice PHP visto finora. Il loro scopo è quello di renderlo più utilizzabile (anche in visione di future applicazioni)

Le funzioni rispettano una sintassi precisa
Ogni funzione deve essere preceduta dalla parola "fuction" e seguita da due parentesi (aperta/chiusa).
Il nome di una funzione è arbitrario, ma non deve iniziare o contenere caratteri particolari. Le funzioni sono case-sensitive, per cui miafunzione() è diversa da MIAFUNZIONE(). E' bene utilizzare sempre lettere minuscole nel nome. Infine, le istruzioni interne ad una funzione vanno delimitate dalle parentesi graffe.

Nelle funzioni le variabili non sono visibili
Le variabili dichiarate all'esterno di una function non sono utilizzabili all'interno della stessa, a meno che non siano dichiarate global. Fanno eccezione gli array globali $_POST e $_GET (ed altri array globali non menzionati in queste pagine).

Come PHP legge gli altri campi form

Usciamo adesso dal discorso sulle funzioni e vediamo qualcosa di più pratico e divertente :)
Nel guestbook abbiamo utilizzato, in fase di immissione dati, due tipi di campo: text e textarea.
Come sapete, esistono altri tipi di input. PHP gestisce tutto in modo semplice ed intuibile. Nella tabella sottostante illustriamo, per ciascun tipo di campo, le principali caratteristiche.

Tipo campoSintassi htmlEsempioDato PHPCaso nullo
text<input type="text" name="testo" size="20" maxlength="15">E' possibile risalire al valore digitato nel campo con la variabile $_POST['nomeCampo']Se viene inviata la form con il campo vuoto, esiste comunque la variabile relativa $_POST['nomeCampo'], con valore stringa vuota
Password<input type="password" name="pwd" size="20">Si comporta esattamente come un normale campo text. Le differenze sono solo a livello di html (dati criptati con asterisco). Nella pagina PHP avremo a disposizione il testo effettivamente inserito (non "camuffato" dagli asterischi)Si comporta come un campo text.
Textarea<textarea name="areaTesto" cols="10" rows="3"></textarea>Si comporta esattamente come un campo text. Per visualizzare gli "a capo" inseriti, bisogna ricorrere alla funzione nl2br().Si comporta come un campo text.
select<select name="selezione"> <option value="primo">Primo</option> <option value="secondo">secondo</option> <option value="terzo">terzo</option> </select>Viene elaborata una variabile, con la solita sintassi $_POST['nomeCampo'], contenente il value dell'opzione selezionataUna select html può assumere valore nullo solo in assenza di tag option (quindi in presenza di un'anomalia..). Anche se viene omesso l'attributo value, viene comunque creata una variabile $_POST['nomeCampo'], con valore vuoto.
checkbox<input type="checkbox" name="provaScelta" value="uno">Se la casella viene checkata (spuntata con il mouse), viene creata una variabile $_POST['nomeCampo'] con il valore dell'attributo html value="". Se viene omesso nell'html della form l'attributo value, verrà creata lo stesso la variabile $_POST['nomeCampo'], che avrà valore "on"Se la casella non viene selezionata, non verrà creata la variabile $_POST['nomeCampo']
radio<input type="radio" name="unica" value="uno">I radio button vengono utilizzati in casi di risposta unica (ad esempio, il campo "sesso" in un modulo di iscrizione ad un sito: è possibile selezionar un'unica scelta tra "M" e "F"). La variabile $_POST['nomeCampo'] avrà il valore dell'attributo "value" dell'opzione selezionata.Se nessuna radio del gruppo è stata selezionata, non viene creata la variabile $_POST['nomeCampo']. Se viene omesso l'attributo value, verrà creata la variabile con valore "on". Questo secondo caso è una chiara anomalia nel codice html, frutto di qualche svista. A differenza dei checkbox, non ha senso nei radio sapere se uno è stato flaggato o meno: quello che conta è sapere QUALE è stato scelto. Un valore "ON" dice solo che uno, chissà quale, è stato selezionato..

Esistono, in html, anche i bottoni (submit / reset / button) ma ovviamente non serviranno a granchè in php, visto che non consentono di inviare dati. Sono fondamentali per la gestione lato utente (richiamo javascript, pulizia video, invio form). Il pulsante di submit crea, all'invio, una variabile nell'array $_POST['nomeCampo']. Grazie a questa variabile, potremo controllare che l'utente abbia inviato la form (per verificare che non sia capitato nella pagina "manualmente", magari digitando nel browser l'url di elaborazione dati):

if( isset( $_POST['nomeCampoInvio'] ) ){
//elabora i dati della form
}

Per quanto riguarda il campo di tipo "file", ne parleremo in una lezione apposita.
A questo punto, potete creare tutti i campi form che volete. Nella prossima lezione, creeremo un modulo di iscrizione (classici campi nome/cognome, sesso, indirizzo, cap, nickname ecc.).
Vi invito però in questa settimana a "giocare" con tutti i campi form. Come ho scritto in precedenza, solo cosi potrete acquisire confidenza con la programmazione. Provate, intuite, ragionate, sbagliate, correggete.. se qualcosa non è chiaro, ci vediamo ovviamente sul forum!

Reference mysql - 2: campi testuali

Terminiamo questa lezione con una reference mysql sui campi testuali. La reference pubblicata nella scorsa lezione, unita a questa, migliora le vostre conoscenze sulla programmazione php/mysql e vi rende in grado di creare applicazioni complesse come un form di registrazione/iscrizione utente.

2) Tipi di campo mysql: valori stringa
I valori stringa contengono testo.

. char/varchar
Sia char che varchar possono contenere, al massimo, 255 caratteri. A differenza dei valori numerici visti nella scorsa lezione, che occupano sempre lo stessa memoria (a prescindere dal valore memorizzato), i campi stringa occupano uno spazio variabile.
Se dichiariamo un campo char(12), ad esempio, questo occuperà 12 bytes. Se proviamo ad inserire in questo campo una stringa superiore a 12 caratteri, mysql la memorizzerà senza generare errore, tuttavia sarà troncata.
La differenza tra char e varchar consiste nella gestione della memoria. Un campo char(12) occuperà sempre 12 bytes, anche se utilizzato per memorizzare soltanto il valore "diego". I restanti 7 caratteri saranno riempiti di spazi vuoti.
Un campo varchar(12) occuperà invece un byte per ogni carattere effettivamente inserito, più uno per memorizzare la lunghezza. Nell'esempio sopra citato, se inseriamo "diego" in un varchar(12), verranno utilizzati 6 bytes: 5 per la stringa, uno per memorizzare la lunghezza (ovvero il valore 5).
Quando utilizzare uno e quando l'altro? Se abbiamo a che fare con stringhe di lunghezza variabile (come un campo "nome_utente", che può contenere sia "Aldo" che "Pier Francesco") conviene il campo varchar, visto che usa occupa spazio di un byte superiore alla stringa effettiva. Se però abbiamo a che fare con un campo di lunghezza fissa (come un campo "codice_fiscale", sempre e comunque 16 caratteri) conviene un CHAR. Segue una tabella di esempio:

stringa esempiocampo charspazio occupatocampo varcharspazio occupato
"ciao"char(20)20 bytesvarchar(20)5 bytes
"via lemanidalnaso"char(20)20 bytesvarchar(20)18 bytes
"diego"char(20)20 bytesvarchar(20)6 bytes

Attenzione: se definite una colonna varchar con lunghezza minore di 4, mysql la converte automaticamente a char.

. blob/text
I campi blob e text sono praticamente la stessa cosa, l'unica differenza è che i blob sono case-sensitive (distinguono, in fase di query, maiuscole e minuscole). Il loro funzionamento è simile a varchar, quindi memorizzano i bytes effettivamente occupati più uno aggiuntivo per la lunghezza della stringa.
Si dividono, a seconda della dimensione, in:
- tinytext / tinyblob (massimo 255 caratteri, praticamente uguale a varchar);
- text / blob (massimo 65535 caratteri);
- mediumtext / mediumblob (oltre 16 milioni di caratteri);
- longtext / longblob (oltre 4 miliardi di caratteri);


Esistono infine due particolari tipi di campo, enum e set.
Con enum possiamo decidere di limitare un input ad un insieme ben definito. Può essere enum ad esempio un campo che memorizzi il sesso di un utente iscritto al sito:
enum('m','f').
Non permette ovviamente l'inserimento di valori differenti da quelli proposti. Possiamo impostare fino a 65535 opzioni.
set funziona come enum, unica differenza è che permette l'inserimento di più valori in uno stesso campo. Nell'esempio sopra, un campo set() permetterebbe l'inserimento, per lo stesso utente, sia del valore "M" che "F".



Se avete domande potete scrivere sul forum di supporto, gratuito e aperto a tutti.



Claudio Curci e Max Kiusso per Web-Link.it