Lezione Precedente Elenco Lezioni Lezione Successiva

Laboratorio di Sistemi Informativi

Inserimento dati con struttura 3 fasi

Le soluzioni viste finore per l'inserimento di nuovi oggetti hanno un grosso difetto: se noi inseriamo un nuovo oggetto e poi ricarichiamo la pagina inserimento.php (o sue varianti), viene automaticamente inserito un nuovo oggetto con gli stessi dati. Ovviamente questo non è il comportamento che desideriamo. La soluzione con il metodo POST è un po' meglio, in quanto il browser chiede conferma dell'operazione prima di ricaricare, ma la cosa non è comunque ottimale.

Struttura a 3 fasi

La soluzione migliore è quella di adottare, per le modifiche alla base di dati, una architettura software basata su tre fasi:
  1. all'utente viene presentata la form di richiesta dati;
  2. una volta che l'utente ha sottomesso la form, i dati sono inseriti;
  3. una volta avvenuto l'inserimento, lo script richiama automaticamente una nuova pagina che si occupa di visualizzare il messaggio di conferma all'utente.
In questo modo, quando l'utente clicca sul pulsante di sottomissione della form, quello che gli viene visualizzato alla fine è solo la pagina di conferma, che può quindi essere ricaricata quante volte si vuole senza nessun effetto collaterale. Questa tecnica è implementata in inserimento3-form.php, inserimento3.php e inserimento3-conferma.php.

È interessante esaminare come avviene il passaggio automatico dall'esecuzione di inserimento3.php all'esecuzione di inserimento3-conferma.php. Quando il server web deve mandare al browser una pagina HTML (sia essa statica o generata da uno script PHP), invia in realtà una risposta che consiste in una riga con lo stato dell'operazione (successo o fallimento), una intestazione, e infine il corpo vero e proprio della risposta, ovvero la pagina web richiesta. Ogni riga di intestazione fornisce informazioni aggiuntive sulla pagina inviata o contiene dei comandi per il browser. Tutte le righe di intestazione hanno la forma:

<Tipo-Intestazione>: <valore>
Tra i tipi di intestazione più interessanti c'è sicuramente Location. Specificando come header una stringa del tipo "Location: <nuovoURL>" si dice al browser che in effetti la pagina corrente non contiene alcun dato, e che il browser deve automaticamente provvedere a caricare la pagina specificata da <nuovoURL>. Da PHP è possibile specificare delle linee di intestazione aggiuntive da mandare al browser, in aggiunta a quelle standard, usando la funzione: Così, basta indicare
header("Location: http://localhost/~<username>/inserimento3-conferma.php")
alla fine di inserimento3.php perché il browser venga automaticamente reindirizzato alla pagina di conferma. 

Si ricordi che, in aula informatizzata, occorre sostituire in tutte le URL localhost con goemon, e utilizzare il proprio numero di matricola come username. In particolare, questa modifica va apportata alla pagina inserimento3.php.

Migliorare la pagina di conferma

La pagina di conferma che abbiamo realizzato è un po' troppo spartana. Sarebbe utile visualizzare un riassunto delle informazioni inserite nella base di dati, in modo che l'utente del sistema si senta più rassicurato che le cose siano andate come previsto. Per far ciò dobbiamo modificare inserimento3-conferma.php in modo che accetti un parametro in input, l'id dell'oggetto appena inserito, e provveda a interrogare il database e a visualizare i dati dell'oggetto in questione (quindi si ottiene una cosa simile alla pagina di dettagli dell'oggetto, ma senza il blog associato).

A questo, occorre modificare la pagina inserimento3.php in modo da passare l'id opportuno a inserimento3-conferma.php. Ma come si fa a sapere questo id, visto che viene generato automaticamente da MySQL? Ci viene in aiuto il metodo lastInsertId() della classe PDO:

L'id dell'oggetto inserito viene quindi prelevato con questo metodo e passato nel parametro id della URL. Queste modifiche sono state implementate in inserimento4-form.php, inserimento4.php e inserimento4-conferma.php.

Posizione del comando header

Nella maggior parte delle distribuzioni, perché la funzione header abbia effetto, occorre che nessun output sia stato precedentemente inviato al browser. Ad esempio nella pagina
prova
<?php header('headerprova');?>
il comando header non funziona (e genera un errore) perché viene chiamato dopo che è stato generata come output la stringa prova. Al contrario la pagina seguente funziona:
<?php header('headerprova');?>
prova
Il motivo di tutto ciò è che, se un output è già stato prodotto, allora il server ha iniziato a inviare il corpo della risposta al browser, per cui non è più possibile inviare righe di intestazione.

In alcune distribuzioni di PHP e/o Linux, invece, è abilitata la funzione di bufferizzazione dell'output che elimina in gran parte il problema. In questo caso l'output non viene mandato immediatamente al browser, ma viene immagazzinato internamente da PHP e inviato solo quando l'esecuzione della pagina è terminata. In questo modo, è possibile dare il comando header anche quando è stato già prodotto dell'output. Notare che, anche quando il buffering è abilitato, se l'output inviato è superiore alla dimensione del buffer, il server comincia ad inviarlo al browser, e questo può di nuovo creare un errore sul comando header. Siccome tutto questo comportamento non è standard, è preferibile non farci troppo affidamento. È possibile disabilitare la bufferizzazione aggiungendo al file .htaccess la seguente linea:

php_value output_buffering Off

Analogamente, è possibile abilitare questa funzionalità specificando una riga come quella di sopra, ma rimpiazzando il valore Off con la dimensione del buffer che si vuole utilizzare, espressa in byte. Ad esempio:

php_value output_buffering 8192

Nel seguito lavoreremo sempre con la bufferizzazione dell'output disabilitata. Vi consiglio quindi di inserire l'apposita linea nel file .htaccess o scaricare il file .htaccess di default per il corso.

Variabili super-globali: l'array $_SERVER

Il PHP mette a disposizione alcune variabili predefinite (chiamate in gergo variabili super-globali). Abbiamo già visto le variabili array $_GET e $_POST che contengono i parametri passati allo script PHP. 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.

Ulteriore miglioramento della procedura di inserimento

Si vuole fare in modo che sia possibile spostare a piacimento gli script che formano la nostra applicazione senza dover modificare il codice sorgente. Questo per ora non è possibile perché l'ultima riga di inserimento4.php contiene il comando:

header("Location: http://localhost/~<username>/inserimento4-conferma.php?id=$id");
Se decidessimo di spostare tutta l'applicazione Mancolista dentro la cartella ~<username>/public_html/mancolista, occorrerebbe modificare il comando di sopra con
header("Location: http://localhost/~<username>/mancolista/inserimento4-conferma.php?id=$id");
Stesso problema se la nostra macchina venisse messa in rete con un nome proprio e quindi, invece di chiamarsi localhost, prendesse il nome di pincopallino.unich.it. Per risolvere il secondo problema, si utilizza le variabile predefinita $_SERVER['HTTP_HOST'] che contiene il nome della macchina su cui sta lo script e $_SERVER['PHP_SELF'] che contiene l'indirizzo della pagina in esecuzione, all'interno della macchina. Nel nostro caso $_SERVER['HTTP_HOST'] contiene localhost e $_SERVER['PHP_SELF']  contiene /~<username>/inserimento4.php. Quello che dobbiamo fare è estrarre, da $_SERVER['PHP_SELF'], il percorso completo della pagina con l'eccezione dell'ultima componente (inserimento4.php) perchè a quest'ultima dobbiamo sostituire il nome della pagina di conferma da richiamare (inserimento4-conferma.php). A questo provvede la funzione dirname:
Dunque, il comando da dare è
header("Location: http://".$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF'])
      ."/inserimento4-conferma.php?id=$id");

La nuova versione è scaricabile come inserimento5-form.php, inserimento5.php e inserimento5-conferma.php.

Esercizi e Soluzioni

Esercizio 1

Inglobare inserimento4-form.php, inserimento4.php e inserimento4-conferma.php in un unico file, come già fatto per inserimento-totale.php nella lezione precedente.

Esercizio 2

Utilizzando la funzione header(), scrivere una funzione redirect_browser() che accetta come parametro un percorso relativo e  redirige il browser alla pagina ivi indicata. In pratica, alla fine di inserimento5.php deve essere possibile dare il comando

redirect_browser("inserimento5-conferma.php?id=$id");

invece di

header("Location: http://".$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF'])
      ."/inserimento5-conferma.php?id=$id");

Lezione Precedente Elenco Lezioni Lezione Successiva

Valid HTML 4.01 Transitional Valid CSS!