Laboratorio
di Sistemi Informativi
Interrogazioni
con PHP
Adesso che abbiamo imparato come accedere ad un database MySQL da PHP,
vorremmo imparare come realizzare una interrogazione di tipo un po'
più complesso, che presenti una qualche forma di interazione
con
l'utente. Interrogazioni di questo tipo hanno tipicamente una struttura
a due fasi:
- l'utente seleziona i
parametri di ricerca
- all'utente vengono
presentati i dati che soddisfano i parametri
immessi.
Nel nostro caso, vogliamo che l'utente sia in grado di visualizzare i voli disponibili da un aeroporto di partenza a uno di destinazione a scelta. Prima di realizzare questo obiettivo, bisogna però affrontare un problema: le fasi 1 e 2 sono realizzate da pagine web distinte, eppure la fase 2 utilizza informazioni provenienti dalla fase 1. Come fare a passare queste informazioni da una pagina web ad un'altra?
Passaggio di parametri e FORM
in HTML
Con l'architettura vista finora sembra non ci sia alcun modo di passare
dei parametri al programma PHP. Se fosse veramente così, le
capacità di costruire una applicazione interattiva sarebbero
fortemente limitate. Come fare se, per ogni aereo della nostra
compagnia, volessimo avere una pagina web che mostri all'utente le
informazioni disponibili su quell'aereo. L'unica possibilità
sembrerebbe quella di creare un file HTML o PHP distinto per ogni
aereo. Fortunatamente, le cose non stanno in questo modo!
Il modo più diretto di passare dei parametri a PHP
è
tramite l'URL. Se si utilizza un URL del tipo:
http://nomehost/script.php?param1=val1¶m2=val2
quello che succede è che il file script.php
viene trattato come
un file PHP normale, ma in più è
possibile accedere
ai parametri param1 e param2 tramite l'array associativo predefinito
_GET.
La sintassi generale è quella di scrivere, dopo il nome
della pagina, un punto interrogativo e una lista di coppie <parametro>=<valore>.
Ogni elemento della lista è separato dal successivo con una
e
commerciale (&). Quando lo script PHP viene eseguito, per ogni
coppia <parametro>=<valore>
si ha che la variabile $_GET["<parametro>"]
viene inizializzata con <valore>
.
È possibile fare degli esperimenti con questa pagina PHP di
esempio:
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Prova
PHP con
parametri</title>
</head>
<body>
<?php
require
'error.php';
echo "Il parametro
param1
vale :
",$_GET["param1"],"<br>";
echo
"Il parametro param2 vale :
",$_GET["param2"],"<br>";
?>
</body>
</html>
Salvarla col nome param.php
dentro public_html
e
provare ad accedere all'URL http://localhost/~studente/param.php?param1=<v1>¶m2=<v2>
per differenti valori di v1 e v2. Notare che le URL vanno codificate in
maniera particolare. Ad esempio
il simbolo "+"
rappresenta uno spazio, mentre con la notazione "%xx"
si indica il carattere il
cui codice ASCII è xx (in esadecimale). Non andremo comunque
in
dettaglio in questo problema della codifica dell'URL. Notare quello che
succede se non si fornisce param1
o param2.
Ovviamente questo metodo può essere utilizzato per testare
velocemente i propri script, ma in generale bisogna trovare un sistema
più amichevole per passare i parametri dal browser alle
pagine
PHP. Il modo classico per farlo è tramite le form in HTML.
Consideriamo ad esempio la seguente pagina:
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Prova
PHP con
parametri</title>
</head>
<body>
<form
action="param.php"
method="GET">
Inserire
il testo per il
parametro 1:
<input
type="text"
name="param1" size="10" maxlength="30">
<br>
Scegliere
il valore per il
parametro 2:
<select
name="param2"
size="1">
<option
value="Valore
1">v1</option>
<option
value="Valore
2">v2</option>
<option
value="Valore
3">v3</option>
</select>
<br>
<input
type="submit"
value="Procedi!">
</form>
</body>
</html>
Questa definisce una form con tre campi di input. Un campo di tipo text,
dove è possibile
inserire del testo a piacere, un campo di tipo select
che consente di
scegliere dei valori in un elenco prefissato, e un pulsante di tipo submit.
Quando si preme il
pulsante di submit, il browser passa alla pagina "param.php"
(indicata
come attributo del tag FORM) specificando (tramite l'URL) i valori
inseriti nei vari campi di input. I nomi dei parametri sono quelli
indicati nell'attributo name
mentre il valore è quello inserito dall'utente del browser.
Ad
esempio, se si scrive "ciao" dentro il campo di testo, si seleziona
"Valore 1" sul campo a scelta multipla e si clicca poi sul pulsante
Procedi!, viene richiamato l'URL param.php?param1=ciao¶m2=v1.
Questo provoca il caricamento dell pagina param.php e la
visualizzazione di
Il
parametro param1 vale : ciao
Il
parametro param2 vale : v1
Notare, a questo proposito, la struttura del tag option
:
<option value="Valore
1">v1</option>
Il valore dell'attributo value è quello che viene
visualizzato
dal browser, mentre la stringa tra i tag <option>
e
</option>
è
quello che viene passato allo
script param.php
.
Questo è il motivo per cui
selezionando Valore 1
viene passata allo script
successivo la stringa v1
.
Interrogazione a due fasi:
primo tentativo
Vediamo di integrare le funzioni di accesso a MySQL con il sistema di
gestione dei parametri visto adesso. Vogliamo realizzare una
interfaccia, pensata per un utente che si collega al sito web della
nostra compagnia aerea, che consenta di vedere quali sono i voli
disponibili tra due aeroporti a scelta. Partiamo da una
interfaccia molto rudimentale, e vediamo come perfezionarla.
L'idea è di avere una pagina in cui inserire gli aeroporti
di
partenza e destinazione dalla quale si accede ad un altra pagina con i
risultati della interrogazione. Il tutto è
realizzato da
questi due file:
Per far funzionare questi script (come altri che vedremo in seguito) è necessario avere il file include error.php, che contiene la funzione mysql_showerror() vista nella scorsa lezione.
Invece di avere due file distinti, uno per la form e l'altro per i risultati, si può integrare il tutto in un unico script PHP. Quando viene chiamato senza parametri, visualizzerà la form di richiesta, altrimenti visualizzerà i risultati della interrogazione. Si ottiene il seguente file:
- form-totale.php:
contiene sia
la form di richiesta che lo script che preleva i risultati
Questa soluzione può essere vantaggiosa in modo da tenere in
un
unico file tutto il codice PHP e HTML richiesto per una applicazione
ben
specifica (la richiesta di voli tramite aeroporti di partenza e
destinazione). D'altronde la soluzione con due file distinti
è
più modulare... occorre giudicare dai casi.
Interrogazione a due fasi:
secondo tentativo
La form che abbiamo visto finora per l'interrogazione del database non
è proprio adatta ad un utente comune. Quest'ultimo non
è
detto che sia a conoscenza dei codice degli aeroporti. Sarebbe molto
più utile se la form di richiesta presentasse un elenco di
aeroporti dai quali scegliere, piuttosto che chiedere l'immissione
manuale dei codici all'utente. Abbiamo due possibilità:
- presentare come possibili
scelte tutti gli aeroporti esistenti al
mondo
- presentare come scelte solo
gli aeroporti da cui partono i voli
della compagnia
La prima soluzione non è molto sensata, perchè
l'utente
si trova a dover scegliere tra una immensità di aeroporti,
quando
poi effettivamente quelli serviti sono pochissimi. La seconda
soluzione è implementata nella pagina web:
- form-totale1.php:
come form-totale.php
ma i
campi per inserire gli aeroporti di arrivo e
destinazione sono campi a scelta multipla.
Questa soluzione ha il
difetto che ogni volta che aggiungiamo o eliminiamo un aeroporto dalla
base di dati occorre modificare la pagina web.
Nessuna delle due
soluzioni è quindi ottimale, se realizzata in HTML,
ma con PHP possiamo
calcolare automaticamente quali sono gli aeroporti di partenza e di
destinazione possibili. Consideriamo la seguente modifica del file di
prima:
- form-totale2.php:
come
form-totale1.php ma l'elenco degli aeroporti viene generato
interrogando il database.
Questo nuovo script interroga il database MySQL per determinare quali
sono gli
aeroporti disponibili, e costruisce dei
campi di input di tipo SELECT appropriati. Modifiche alla base di dati
si riflettono immediatamente sulle pagine web generate: non occorre
quindi nessuna manutenzione speciale per adattare il sito web alla
nuova situazione.
Esercizio 1
Modificare form-totale2.php
in modo tale che gli aeroporti di partenza
visualizzati siano solo quelli da cui effettivamente parte almeno un
volo, mentre gli aeroporti di arrivo siano solo quelli nei quali arriva
almeno un volo.
Esercizio 2
Modificare form-totale2.php
in modo tale che, una volta scelto
l'aeroporto di partenza, vengano visualizzati solo gli aeroporti di
destinazione verso i quali esiste un volo (con partenza dall'aeroporto
selezionato). Ci sono due possiblità:
- fare due form diverse, la
prima in cui si sceglie solo
l'aeroporto di partenza, e la seconda in cui si sceglie l'aeroporto di
destinazione. Una volta scelto anche quest'ultimo, si passa alla
visualizzazione dei risultati;
- fare una form unica, ma
utilizzare JavaScript per forzare il
ricaricamento della pagina quando si modifica l'aeroporto di partenza.
Variabili predefinite di PHP:
l'array
$_SERVER.
Il PHP mette a disposizione alcune variabili predefinite (chiamate in
gergo variabili super-globali).
Abbiamo
già visto la variabile array $_GET
che contiene i parametri
passati allo script PHP tramite la URL. Un altra variabile
predefinita è l'array $_SERVER.
Si tratta di un array associativo che contiene varie informazioni
relative all'ambiente nel quale lo script viene eseguito. Ad esempio:
- $_SERVER['SERVER_SOFTWARE']:
contiene il nome del server Web su cui lo script è in
esecuzione. Nelle
aule dell'università usiamo il server Apache 2.0. Il
valore
di $_SERVER['SERVER_SOFTWARE']
è qualcosa del tipo "Apache/2.0.xx (Fedora)".
- $_SERVER['HTTP_USER_AGENT']:
nome del browser che l'utente sta utilizzando per la connessione. Per i
browser basati su Mozilla (come Netscape 7.0, Mozilla, Galeon, etc..)
su macchine Linux il valore è qualcosa del tipo "Mozilla/5.0 (X11; U;
Linux i686;
en-US; rv:1.6) Gecko/20040124".
Questa informazione può essere utilizzata per generare file
HTML
diversi a seconda del browser, visto che alcuni aspetti del linguaggio,
in particolare
riguardo a Javascript, non sono del tutto standardizzati.
- $_SERVER['HTTP_HOST']:
contiene il nome della macchina che contiene il server web. Normalmente
è localhost
per i
computer dell'aula informatizzata.
- $_SERVER['PHP_SELF']:
contiene il nome assoluto dello script correntemente in esecuzione. In
pratica $_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']
è l'URL corrente.
Per controllare tutte le chiavi supportate da $_SERVER,
più
varie altre
informazioni sul sistema PHP come i parametri di
configurazione, si può utilizzare la funzione:
- bool phpinfo([int
what]):
manda in output una pagina XHTML che contiene varie informazioni su PHP
quali variabili predefinite, settaggi della configurazione, moduli
opzionali caricati, etc.. Il parametro di input consente di specificare
quali informazioni visualizzare. Tipicamente si omette, nel qual caso
vengono visualizzate tutte le informazioni disponibili. Restituisce
sempre il valore true.
Il modo più semplice di usare phpinfo()
è prepararsi
una semplicissima pagina phpinfo.php
il cui unico contenuto è:
<?php
phpinfo();
?>
Accedere alla pagina phpinfo.php
visualizzerà tutte le
informazioni necessarie.
La variabile
$_SERVER['PHP_SELF']
La variabile predefinita $_SERVER['PHP_SELF']
può essere utilizzata quando, all'interno di uno script,
è necessario inserire un collegamento allo script stesso. Ad
esempio, in form-totale.php
abbiamo la riga:
<form
action="form-totale.php"
method="GET">
che serve a richiamare lo script stesso una volta inseriti gli
aeroporti di partenza e destinazione. Se noi cambiamo il nome dello
script, dobbiamo anche modificare il valore dell'attributo action.
C'è il rischio però di dimenticarsene!
La soluzione è allora usare $_SERVER['PHP_SELF']
come
valore
dell'attributo action, in modo tale che, per quanto si modifichi il
nome del file PHP, il tag FORM
conterrà sempre il valore
corretto. In pratica, la riga di prima va sostituita con:
<form
action="<?php echo
$_SERVER['PHP_SELF']?>" method="GET">
Lo script modificato è form-totale-self.php.
Contare il numero di righe di
un risultato
Abbiamo visto che per inviare una query da PHP a MySQL si usa la
funzione mysql_query.
Il risultato è un valore
di tipo resource
che può essere dato in input alla funzione mysql_fetch_array
per accedere
al risultato della interrogazione. Talvolta si vuole conoscere
immediatamente il numero di righe presenti nel risultato. In tal caso
si può utilizzare questa funzione
- int mysql_num_rows(resource result):
restituisce
il numero di righe della risorsa result.
La funzione mysql_num_rows()
funziona solo quando la query eseguita precedentemente è una
SELECT. Se la query fosse stata, ad esempio, una UPDATE, sarebbe stato
necessario usare una funzione diversa (mysql_affected_rows)
per sapere
il numero di righe modificate.
Esercizio 3
Modificare lo script form-totale.php in modo tale che, dati l'aeroporto
di partenza e l'aeroporto di arrivo, venga visualizzato non solo
l'elenco dei voli disponibili ma anche il numero totale di voli, usando
la funzione mysql_num_rows().
È preferibile utilizzare la variabile $_SERVER['PHP_SELF'],
come
fatto nella sezione precedente, piuttosto che scrivere direttamente il
nome dello script.
Metodi GET e POST
Abbiamo visto come passare dei parametri ad uno script in PHP
inserendoli nella URL. All'interno di una form, si può
specificare che si intende utilizzare questo metodo per il passaggio
dei parametri inserendo, nel tag <FORM>,
l'attributo METHOD=GET.
Esiste un altro metodo per il passaggio dei parametri ad uno script da
una form, il
metodo POST.
Per utilizzare il metodo POST basta effetturare un paio di cambiamenti
rispetto
a quanto fatto finora:
- sostituire l'attributo METHOD=GET
con METHOD=POST
nel tag
FORM;
- sostituire tutte le
occorrenze della variabile $_GET
con
la
variabile $_POST
nello
script che viene richiamato.
Lo script form-totale-post.php
è la versione di form-totale.php modificato per utilizzare
il
metodo POST (viene anche utilizzata la funzione mysql_num_rows
come richiesto
dall'Esercizio 3).
Vediamo in dettaglio alcune
delle differenze tra i metodi GET e POST.
Differenza n. 1:
visibilità dei parametri
Il metodo POST, a differenza del GET, non utilizza la URL per il
passaggio dei parametri. Questi vengono comunque passati al momento
della richiesta della pagina, ma con un meccanismo interno che non
è visibile all'utente. Per questo, il metodo POST
è
più adatto se bisogna inviare come parametri dei valori
sensibili: numeri di carte di credito, password, etc.. Usando il metodo
GET, una persona che passa per caso davanti al computer potrebbe
sbirciare il contenuto della URL e scoprire il numero della vostra
carta di credito!
A dire il vero questo accorgimento è del tutto insufficiente
per
dati così importanti come il numero di carta di credito. E`
anche
assolutamente necessario che tutta la comunicaziona tra browser e
server web avvenga in maniera criptata, usando il protocollo https
invece di http.
Questo è
però al di là degli obiettivi di questo corso.
Differenza n.2: bookmarks
Se si salva nei segnalibri (detti anche preferiti, o bookmarks)
l'indirizzo di una pagina web,
verranno salvati anche i valori di eventuali parametri passati col
metodo GET alla pagina. Parametri passati col metodo POST non vengono
salvati. Per questo, quando la pagina che vogliamo visualizzare
contiene dei dati che può essere interessante riprendere in
un
momento successivo (ad esempio l'elenco dei voli tra un aeroporto di
partenza e uno di destinazione), il metodo GET è da
preferire.
È per questo che tutti gli script visti nella lezione precedente
utilizzano il metodo GET. Se si salva nei bookmark l'indirizzo http://localhost/~studente/form-totale2.php?src=CTA&dst=JFK
sarà possibile accedere direttamente all'elenco dei voli da
Catania a New York senza passare per la FORM di immissione dati.
Differenza n.3: ricarica della
pagina
Se si preme il tasto reload su una pagina a cui sono stati passati dei
parametri con il metodo POST, il browser non ricarica automaticamente
la pagina. Avverte prima l'utente che ci sono stati dei parametri
passati con il POST e chiede se veramente si vuole ricaricare la
pagina (in tal caso i parametri vengono passati di nuovo).
Il motivo di questo comportamento ferraginoso è che
il metodo POST è di solito utilizzato per passare dei
parametri
agli script che modificano una base di dati, mentre il GET viene usato
per gli script che interrogano una base di dati. Fare due
interrogazioni ad un base di dati non è un problema, anche
se lo
si fa per sbaglio, ma fare due modifiche alla base di dati per sbaglio,
quando invece se ne voleva fare solo una, è tutta un'altra
cosa.
Per questo il browser chiede conferma che effettivamente si voglia
ricaricare la pagina (col rischio di effettuare qualche modifica non
prevista).
I file utilizzati in questa lezione: airdb2.sql,
error.php,
e .htaccess.