Lezione Precedente
Lezione Successiva

Laboratorio di Sistemi Informativi

Inserimento dati con PHP

Supponiamo ora di voler creare una pagina per l'inserimento di nuovi voli nella base di dati. La struttura generale sarà simile alla pagina per l'interrogazione fatta finora: dovrà comparire una form in cui si richiede all'utente di immettere i dati che si vogliono inserire e poi, cliccando su un pulsante, il controllo passerà allo script che esegue l'operazione di aggiornamento della base di dati.

Per effettuare un inserimento o una modifica su un database si usano gli stessi comandi visti finora. Semplicemente la query che si specifica con il comando mysql_query sarà una INSERT (o DELETE, o UPDATE) invece di una SELECT


ATTENZIONE! Ricordatevi che il risultato di mysql_query,  nel caso di una query di modifica, non è un oggetto risorsa, come per le SELECT, ma un booleano: true nel caso di sucesso, false nel caso di insuccesso.


Possono essere utili anche la seguenti nuove funzioni:
Come esempio di base di un sistema per l'inserimento di nuovi voli, consideriamo le due pagine inserimento.html e inserimento.php. Rispetto agli ultimi script analizzati, siamo tornati ad una soluzione con due file separati, uno per la FORM, l'altro per eseguire l'operazione di inserimento vero e proprio.

Da notare nello script inserimento.php è il trattamento della data. Si è voluto fare in modo che, quando l'utente non inserisce nulla nel campo data della form, venga automaticamente inserito nella base di dati la data e l'ora corrente. Per far ciò si controlla se $_GET['data'] è la stringa vuota, nel qual caso si fa in modo che, come valore per il campo ora nel successivo comando INSERT, venga messa la chiama alla funzione intrinseca NOW() di MySQL. A parte questa particolarità, sia la pagine HTML che quella in PHP sono banali.

Questa coppia di pagine ha un grosso difetto, a cui si è già accennato in precedenza quando abbiamo analizzato i metodi GET e POST. Se noi inseriamo un nuovo volo e poi ricarichiamo la pagina inserimento.php, viene automaticamente reinserito un nuovo volo con gli stessi dati!! Ovviamente questo non è il comportamento che desideriamo. Si può risolvere in parte il problema trasformando lo script in modo da usare il metodo POST per il passaggio dei parametri: in questo modo, quando l'utente cerca di ricaricare la pagina, viene avvertito che l'operazione potrebbe causare degli effetti collaterali.

Esercizio 1

Modificare inserimento.html e inserimento.php in modo da utilizzare il metodo POST invece del metodo GET

Inserimento dati: struttura 3 fasi

La soluzione vista nella lezione precedente, che si ottiene utilizzando il metodo POST anziché il metodo GET, non è comunque ottimale. L'utente, infatti, non può mettere la pagina di conferma in un bookmark: se si salva inserimento.php in un bookmark e si tenta successivamente di ritornare a quella pagina, lo script PHP viene rieseguito e questo causa l'inserimento di un nuovo volo. La soluzione migliore è quella di adottare, per le modifiche alla base di dati, una struttura 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 un 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. Questa pagina può essere tranquillamente inserita nei bookmark perché l'unica cosa che fa è visualizzare un messaggio che indica il successo dell'operazione, senza effettuare ulteriori modifiche nella base di dati. Questa tecnica è implementata in inserimento2.html, inserimento2.php e inserimento2-conferma.php. Notare, tra l'altro, che la pagina di conferma è stata arricchita di informazioni sul volo effettivamente inserito.

È interessante esaminare come avviene il passaggio automatico dall'esecuzione di inserimento2.php all'esecuzione di inserimento2-conferma.php. Una spiegazione precisa richiederebbe lo studio del protocollo HTTP, per cui diamo una spiegazione di massima di quanto succede.

Il punto fondamentale è che quando un browser richiede al server una pagina web, il server risponde inviando, prima della pagina stessa, una serie di informazioni che costituiscono il cosidetto header (intestazione). Esempi di informazioni che possono essere presenti nell'header sono il tipo di server Web o il formato usato per la codifica della pagina web (ASCII, Unicode, etc..).

Da PHP è possibile specificare degli header aggiuntivi da mandare al browser oltre a quelli standard. Questo è possibile tramite la funzione Tra gli header 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>. Così, basta indicare

header("Location: http://localhost/~studente/inserimento2-conferma.php")

alla fine di inserimento2.php perché il browser venga automaticamente reindirizzato alla pagina di conferma.  In effetti il comando presente in inserimento2.php è più complesso per due motivi:
  1. si vuole passare a inserimento2-conferma.php l'identificatore del nuovo volo inserito, in modo che venga poi visualizzata un pagina di conferma con tutti i dati del nuovo volo. 
  2. si vuole fare in modo che sia possibile spostare a piacimento gli script che formano la nostra applicazione senza dover modificare il sorgente. Se noi inserissimo direttamente l'URL

    http://localhost/~studente/inserimento2-conferma.php


    nel codice sorgente e poi decidessimo di spostare tutte l'applicazione relativa al database airdb dentro la cartella ~studente/public_html/airdb, occorrerebbe modificare l'URL presente nel codice con

    http://localhost/~studente/airdb/inserimento2-conferma.php.

    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 primo problema, si utilizza la funzione mysql_insert_id() e si passa il parametro id nella URL.

Per risolvere il secondo problema, si utilizza la 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 /~studente/inserimento2.php. Quello che dobbiamo fare è estrarre, da $_SERVER['PHP_SELF'], il percorso completo della pagina con l'eccezione dell'ultima componente (inserimento2.php) perchè a quest'ultima dobbiamo sostituire il nome della pagina di conferma da richiamare (inserimento2-conferma.php). A questo provvede la funzione dirname:
Dunque, il comando da dare è

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


dove la variabile $id deve contenere l'identificatore del nuovo volo inserito, ottenuto dalla funzione mysql_insert_id().

Posizione del comando header

Nella maggior parte delle distribuzioni, perché la funzione header abbia effetto, occorre che nessun altro output sia stato 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
Nella Fedora 4, invece, è stata abilitata la funzione di bufferizzazione dell'output che nasconde questo problema. Vuol dire che 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. Siccome questo comportamento non è standard in altri ambienti, è preferibile non abituarsi. È possibile disabilitare la bufferizzazione aggiungendo al file .htaccess la seguente linea:

php_value output_buffering 0

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 deve essere possibile dare il comando

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

invece di

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

Esercizio 3

Inglobare inserimento2.html, inserimento2.php e inserimento2-conferma.php in un unico file, come già fatto per form-totale.php.

Esercizio 4

L'interfaccia utente utilizzata finora è molto spartana. In un sistema vero occorrerebbe fornire una form per l'immissione dati più amichevole, simile a quella usata per la richiesta dei voli dati gli aeroporti di partenza e arrivo, in cui per ogni campo vi è un insieme ben definito di valori possibili tra cui scegliere. Come esercizio, fare le modifiche appropriate.


Nota. Fornire una interfaccia utente più ricca ha anche un altro effetto collaterale: quello di rispettare i vincoli di integrità tra i dati. Con gli script visti sopra, è possibile inserire un volo che abbia aeroporti di partenza o di arrivo sconosciuti o con un idaereo inesistente. Questi vincoli di integrità possono anche essere forzati a livello di DBMS (anche se non abbiamo visto come) ma è spesso più efficiente forzarli a livello dell'applicazione impedendo che l'utente possa inserire dati sbagliati.

Lezione Precedente
Lezione Successiva

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