Laboratorio di Sistemi
Informativi
PHP e MySQL
Il PHP 5 mette a disposizione del programmatore due librerie diverse
per interfacciarsi a un database MySQL: la librerie mysql
e mysqli
(dove i sta per improved). La
libreria mysqli
è sicuramente la migliore, sia perchè supporta
alcune
funzionalità di MySQL 4.1 e 5.0 che non sono supportate
dall'altra libreria, sia perchè ha una struttura object
oriented
che la rende più simile ad API simili sviluppate per altri
linguaggi (ad esempio al JDBC per il linguaggio Java).
Tuttavia, la mysqli
non è
disponibile ancora su
tutte le distribuzioni di Linux. Questo, e il fatto che in
realtà non usiamo nessuna delle funzioni evolute di MySQL
che ne
richiederebbero l'utilizzo, ci induce a utilizzare la vecchia libreria mysql
.
Accesso a MySQL
Cominciamo ad imparare come accedere ad un database MySQL
tramite
PHP. Tutto si basa su alcune funzioni che il linguaggio ci mette a
disposizione.
- resource
mysql_connect(string
server,string username, [string password]):
si collega ad un
server MySQL con un determinato nome utente e password; se ci si vuole
collegare senza fornire una password, basta omettere il terzo
parametro. Le parentesi quadre attorno a [string password]
stanno
proprio ad indicare che il parametro è opzionale.
Restituisce un identificatore
di connessione
se questa ha successo,
false
altrimenti.
Il risultato di mysql_connect
è un
tipo che non
abbiamo ancora visto, il tipo resource
. Il
tipo resource
contiene valori che identificano una qualche risorsa che è
stata
concessa al programma PHP, nel nostro caso la risorsa è una
connessione al database. Il valore di una variabile resource non ha
nessun significato per un essere umano: la sua unica funzione,
tipicamente, è quella di essere passata come parametro ad
altre
funzioni che agiscono sulla stessa risorsa.
- bool mysql_select_db(string
nomedb,[resource connessione]): seleziona un database
corrente
per le operazioni successive, in maniera simile al comando
USE
del monitor MySQL. Ogni connessione a un server MySQL ha il suo proprio
database corrente, per questo occorre passare un identifictore di
connessione, ottenuto precedentemente con mysql_connect
.
Se questo identificatore non viene fornito, si utilizza per default
l'ultima connessione attivata. Restituisce true
se
l'operazione ha successo, false
altrimenti.
- resource
mysql_query(string
query,[resource connessione]): esegue la query specificata
nel
primo parametro (come comando SQL), sulla connessione specificata dal
secondo parametro (che al solito, è opzionale). Restituisce false se si
verificano errori,
altrimenti
- se la query era una SELECT, SHOW o DESCRIBE restituisce
una
valore di tipo risorsa che può essere utilizzato da altre
funzioni PHP per accedere alle varie righe e colonne del risultato;
- per gli altri tipi di query restituisce
true
se
la query ha successo, false
altrimenti.
- array mysql_fetch_array(resource
risultato): dato un oggetto risultato
ottenuto con
mysql_query
, restituisce un
array che
contiene i dati relativi ad una riga del risultato. La posizione 0
dell'array contiene il valore presente nella prima colonna della riga,
alla posizione 1 c'è il valore presente nella seconda
colonna e
così via. È possibile accede alle varie colonne
anche in
maniera associativa, usando come indice il nome della colonna piuttosto
che la sua posizione. Ogni volta che
mysql_fetch_array viene chiamato, viene restituita una riga diversa del
risultato. Quando le righe sono terminate, restituisce false
.
- bool mysql_close([resource
connessione]):
chiude
una connessione a MySQL. Restituisce
true
se
l'operazione
ha successo, false
altrimenti. Il comando mysql_close
di solito non è necessario, in quanto la connessione
è
automaticamente chiusa alla fine del codice PHP.
Ad esempio, consideriamo il seguente programma che esegue la query SELECT * FROM voli
nel database
airdb
e visualizza il risultato come pagina
HTML.
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Prova
PHP e
MySQL</title>
</head>
<body>
<?php
mysql_connect("localhost","studente");
mysql_select_db("airdb");
$res=mysql_query("select * from voli");
while ($riga=mysql_fetch_array($res))
echo $riga["id"]," ",$riga["idsrc"],"
",$riga["iddst"],"<br>";
mysql_close();
?>
</body>
</html>
Lo script inizia con la connessione al server mysql su localhost come studente.
Successivamente viene
selezionato il database airdb,
inviata la query,
e il risultato viene messo nella variabile $result
.
Da lì, una
alla volta viene estratta una riga dei risultati e inserita nella
variabile $riga
, per poi essere stampata. I
valori delle chiavi per
$riga (ovvero id, idsrc, iddst) sono gli stessi che si ottengono come
intestazione delle colonne quando la query select * from voli
è
inviata da mysqlc. Se si modifica la linea
$res=mysql_query("select
* from
voli");
con
$res=mysql_query("select
id,
idsrc, iddst as destinazione from voli");
occorre anche modificare l'echo finale in
echo $riga["id"]," ",$riga["idsrc"],"
",$riga["destinazione"],"<br>";
altrimenti viene generato un errore, che ci avverte che
stiamo
tentando di accedere alla chiave "iddst" che non esiste.
Controllo degli errori
Cosa succede se si sbaglia a scrivere il nome del database nella
funzione mysql_select_db
o la query SQL in mysql_query
?
Ad esempio, modifichiamo
mysql_select_db("airdb") con mysql_select_db("airodd").
Si noti che non viene generato nessun errore in corrispondenza
di mysql_select_db,
ma viene invece generato il seguente warning in corrispondenza di mysql_fetch_array
:
Warning: mysql_fetch_array(): supplied
argument is not a valid MySQL result resource in /home/studente/public_html/mysqlprova.php
on line 11
Quello che succede è che mysql_select_db
fallisce in maniera silenziosa, restituendo il valore false
(che non utilizziamo). Successicamente mysql_query
fallisce, anch'esso in maniera silenziosa, restituendo ancora il valore
false
(che noi assegnamo alla variabile $res
).
Quando si tenta di eseguire la mysql_fetch_array
il PHP si lamenta dicendo che $res
non
contiene una variabile di tipo risorsa come si aspettava.
Il problema è che questo messaggio non da nessuna
informazione
su dove effettivamente si sia verificato l'errore iniziale. Nasce
pertanto l'esigenza, per il programmatore, di gestire gli errori di
MySQL in proprio. Tra le funzioni della libreria mysql, le
seguenti possono tornare utili a questo scopo:
- int mysql_errno([resource
connessione]): restituisce il codice di errore dell'ultima
operazione eseguita da MySQL. Il valore 0 indica che l'ultima
operazione è stata eseguita con successo.
- string mysql_error([resource
connessione]): restituisce il messaggio di
errore relativo all'ultima operazione eseguita da MySQL. La stringa
vuota '' indica che l'ultima operazione è stata eseguita con
successo.
Ad esempio, si può modificare la pagina PHP di prima nel
modo seguente:
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Prova PHP e MySQL</title>
</head>
<body>
<?php
mysql_connect("localhost","studente");
if (!mysql_select_db("airdbd")) {
?>
Non riesco ad accedere al database<br>
Il numero di errore restituito da PHP
è: <?php echo mysql_errno() ?>
<br>
Il messaggio di errore restituito da PHP
è: <?php echo mysql_error() ?>
<br>
<?php
} else {
$res=mysql_query("select * from voli");
while ($riga=mysql_fetch_array($res))
echo $riga["id"]," ",$riga["idsrc"],"
",$riga["iddst"],"<br>";
mysql_close();
}
?>
</body>
</html>
In questa variante, viene controllato il risultato di mysql_select_db
.
Se c'è un errore, il risultato è false
e viene visualizzato un messaggio di errore, sfuttando anche le
funzioni messe a disposizione da MySQL. Notare che i messaggi di errori non
sono ottenuti con una istruzione
echo ma chiudendo lo script PHP iniziale, passando
temporaneamente
all'HTML, per ritornare successivamente a PHP. Visto che questo pezzo
di HTML è all'interno del blocco then di un if, esso
sarà mandato al
browser solo se la condizione dell'if
è verificata. Se, invece, il comando mysql_select_db
ha successo, l'esecuzione procede normalmente.
Ovviamente, un controllo simile andrebbe effettuato tutte le volte che
si chiama una funzione di MySQL che può terminare con un
errore. Possiamo ottenere quindi qualcosa di questo tipo:
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Prova
PHP/MySQL con
controllo errori</title>
</head>
<body>
<?php
if (!
@mysql_connect("localhost","studente"))
die ('Non riesco a
connettermi al database: '.mysql_error());
if (!
mysql_select_db("airdb"))
die('Non riesco ad
accedere al database airdb: '.mysql_error());
if (!
($res=mysql_query("select *
from voli")))
die('Non riesco ad
eseguire la query: '.mysql_error());
while
($riga=mysql_fetch_array($res))
echo $riga["id"],"
",$riga["idsrc"]," ",$riga["iddst"],"<br>";
if (!mysql_close())
die('Non riesco ad
effettuare la close: '.mysql_error());
?>
</body>
</html>
Si notino due cose:
- l'uso della funzione
die
per
semplificare i vari comandi if.
- l'uso del simbolo
@
davanti a mysql_connect
;
La funzione die()
visualizza il parametro di input e termina l'esecuzione del programma PHP:
void die(string
error
): stampa una stringa,
tipicamente un messaggio di errore, e termina la pagina PHP.
Se si verifica un errore durante la mysql_connect
(ad esempio il server mysql non risponde) il sistema genera
automaticamente un warning
e continua l'esecuzione del codice PHP. Nell'ottica che il programma
gestisca autonomamente le situazioni di errore, questo warning
automatico è indesiderato. Si può evitare la
generazione di un
qualunque messaggio di errore semplicemente facendo precedere una
espressione con la chiocciola (il simbolo @).
Funzioni, file include, MySQL e controllo sugli errori
Per scrivere il meno possibile ma nel contempo controllare
completamente tutte le condizioni di errore, è possibile
definirsi una funzione PHP che si occupa di visualizzare gli errori
generati da MySQL, e includerla in tutte le pagine PHP con require.
Consideriamo ad esempio la
seguente funzione:
function mysql_showerror()
{
die
('<B>Error</B> '.mysql_errno().' :
'.mysql_error());
}
Se mettiamo questa definizione dentro il file
error.php, questo ci consente di riscrivere la nostra pagina PHP in questo modo:
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Prova
PHP/MySQL con
controllo errori e include</title>
</head>
<body>
<?php
require 'error.php';
@mysql_connect("localhost","studente") or mysql_showerror();
mysql_select_db("airdb")
or mysql_showerror();
$res=mysql_query("select
*
from voli") or mysql_showerror();
while
($riga=mysql_fetch_array($res))
echo $riga["id"],"
",$riga["idsrc"]," ",$riga["iddst"],"<br>";
mysql_close() or mysql_showerror();
?>
</body>
</html>
A parte l'uso della funzione mysql_showerror()
e del comando require
per
includere error.php,
un'altra novità di questo script è
l'uso dell'operatore or. La notazione
exp1 or exp2
equivale (per
quello che ci riguarda) a if
(!
exp1) exp2 ma è più facile da
scrivere e da leggere.
In realtà, consiglierei a tutti di utilizzare la seguente versione evoluta di mysql_showerror
:
function mysql_showerror()
{
$bt=debug_backtrace();
die ('<B>MySQ Error</B> '.mysql_errno().' : '.mysql_error().
' in
<b>'.$bt[0]['file'].'</b> on line
<b>'.$bt[0]['file'].'</b>');
}
A differenza della precedente, questa versione visualizza il numero di
riga e il nome del file dove si è verificato l'errore, ed
è quindi molto più utile a scopo di debugging. Utilizza
la funzione debug_backtrace()
, che spiegheremo però solo più avanti nel corso.
Esercizio 1
Salvare l'ultimo esempio di pagina PHP mostrata. Creare un file error.php che
contiene
funzione mysql_showerror()
definita sopra.
Provare se la pagina PHP funziona. Quando tutto è a posto,
provare a modificarla ed inserire degli errori, ed esaminare i
risultati che si ottengono.
Esercizio 2
Scrivere una pagina PHP che, ogni volta che viene caricata, aggiunga una nuova riga nella tabella voli.