Lezione Precedente
Lezione Successiva

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:
  1. l'utente seleziona i parametri di ricerca
  2. 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&param2=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>&param2=<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&param2=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:

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à:
  1. presentare come possibili scelte tutti gli aeroporti esistenti al mondo
  2. 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:
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:
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à:

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:
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:
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
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:
  1. sostituire l'attributo METHOD=GET con METHOD=POST nel tag FORM;
  2. 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).

Lezione Precedente
Lezione Successiva

I file utilizzati in questa lezione: airdb2.sql, error.php, e .htaccess