OBIETTIVI DELLA LEZIONE
In questa lezione:
Contestualizzazione:
Il processo di creazione dinamica di una pagina HTML può essere schematizzato nei seguenti passi fondamentali:
(1) | Invio dei dati dal client al server | form HTML + richiesta HTTP (GET/POST) | lez15e16 |
(2) | Sul server una CGI riceve i dati | Server + Programma PHP | lez17e18 |
(3) | La CGI interroga il DB MySQL | query MySQL | Oggi |
(4) | Con i risultati ottenuti crea la pagina da rimandare all'utente | Programma PHP + Server | lez17e18 |
In questa sezione ci concentriamo sul punto (3).
Il processo è schematizzato in questa figura.
MySQL è un server di database relazionale,
in parte conforme allo standard SQL92. In termini
molto rozzi, un database relazionale è un insieme di tabelle
e di relazioni tra alcuni campi di tabelle diverse.
Per quanto riguarda il nostro corso chiameremo con il
nome di "record" ciascuna riga di una tabella e
con quello di "campo" ciascuna colonna.
MySQL può essere interrogato attraverso un dialetto
del linguaggio standard SQL.
Vediamo attraverso alcuni esempi una possibile sessione:
CREATE DATABASE db_annunci;
\u db_annunci
CREATE TABLE annunci ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, data DATE NOT NULL, testo TEXT NOT NULL, matricola VARCHAR( 6 ) NOT NULL, PRIMARY KEY ( id ) );
INSERT INTO annunci (data, testo, matricola) VALUES ('2004-05-02', 'Vendo VESPA 125 da sistemare. Luigi 333123456', '123456');
DELETE FROM annunci WHERE id=5;
UPDATE annunci SET testo='Vendo VESPA 200 da sistemare. Luigi 333 1234567', matricola='123457' WHERE id=5;
SELECT * FROM annunci;
SELECT * FROM annunci WHERE testo LIKE '%vendo%' AND testo LIKE '%vespa%';
DROP TABLE annunci;
DROP DATABASE db_annunci;
I comandi SQL (SELECT ad esempio) e i nomi delle colonne (i campi) non sono case-sensitive. Sono invece case-sensitive in MySQL i nomi dei database e delle tabelle.
ATTENZIONE: i comandi SQL riportati sopra terminano con il punto e virgola (;). Quando li effettuaremo da PHP, anche se per il resto la sintassi sarà IDENTICA, il punto e virgola finale NON DEVE ESSERE INSERITO.
PhpMyAdmin è un pacchetto di script PHP che ci permetterà di interagire molto più semplicemente con il server MySQL [Benissimo!].
Ad esempio, vediamo in queste immagini la creazione del database "db_annunci" e della tabella "annunci", come fatto in SQL nella sezione precedente.
Anche se PhpMyAdmin permette di fare molto di più di quanto visto, in generale servirà più che altro per creare la struttura del database. I dati verranno inseriti dagli script PHP.
L'accesso al database MySQL da PHP si compone SEMPRE dei seguenti passi:
$ptr_mysqls=mysql_connect("localhost","rsassi","rsassi") or die("Impossibile connettersi al server MySQL.\n");
mysql_select_db("db_annunci", $ptr_mysqls) or die("Impossibile aprire il database.\n");
$query="SELECT * FROM annunci"; $ptr_risultato_query=mysql_query($query, $ptr_mysqls);
$numero_records=mysql_affected_rows($puntatore_connessione_aperta);
$numero_campi=mysql_num_fields($ptr_risultato_query);
// $i è un numero da 1 a $numero_campi $nome_campo=mysql_field_name($ptr_risultato_query, $i-1);Attenzione: i campi sono numerati a partire da 0!
$record=mysql_fetch_array($ptr_risultato_query, MYSQL_ASSOC);$record è un array associativo che contiene tanti elementi quanti sono i campi contenuti nella risposta ($numero_campi). Le chiave di ciascun elemento è il nome del campo corrispondente.
// $i è un numero da 1 a $numero_records mysql_data_seek($ptr_risultato_query, $i-1) or die("Impossibile posizionarsi sul record $i\n"); $record=mysql_fetch_array($ptr_risultato_query, MYSQL_ASSOC);Attenzione: i record sono numerati a partire da 0!
mysql_free_result($ptr_risultato_query);
mysql_close($ptr_mysqls);
esempiosql1.php conta i records contenuti nella tabella annunci del database db_annunci, visto sopra.
<html>
<head>
<title>Bacheca annunci</title>
</head>
<body>
<?php
$ptr_mysqls=mysql_connect("localhost","root","")
or die("Impossibile connettersi al server MySQL.\n");
mysql_select_db("db_annunci", $ptr_mysqls)
or die("Impossibile aprire il database.\n");
$query_visualizzazione="SELECT * FROM annunci";
$ptr_risultato_query=mysql_query($query_visualizzazione, $ptr_mysqls);
$numero_records=mysql_affected_rows($ptr_mysqls);
print "Il database contiene $numero_records annunci.\n";
mysql_free_result($ptr_risultato_query);
mysql_close($ptr_mysqls);
?>
</body>
</html>
esempiosql2.php visualizza tutti i records della tabella annunci
<html>
<head>
<title>Bacheca annunci</title>
</head>
<body>
<?php
$ptr_mysqls=mysql_connect("localhost","root","")
or die("Impossibile connettersi al server MySQL.\n");
mysql_select_db("db_annunci", $ptr_mysqls)
or die("Impossibile aprire il database.\n");
$query_visualizzazione="SELECT * FROM annunci";
$ptr_risultato_query=mysql_query($query_visualizzazione, $ptr_mysqls);
print "<table cellpadding=\"3\" border=\"1\">\n";
while( $record=mysql_fetch_array($ptr_risultato_query, MYSQL_ASSOC) )
{
print "<tr>\n";
foreach($record as $valore_campo)
{
print "<td>\n";
print $valore_campo . "\n";
print "</td>\n";
}
print "</tr>\n";
}
print "</table>\n";
mysql_free_result($ptr_risultato_query);
mysql_close($ptr_mysqls);
?>
</body>
</html>
Sito dove gli studenti possono inserire le loro inserzioni. L'esempio è più complesso e costituito da tre files. annunci0.php è la pagina principale, inserisci0.php permette di inserire un nuovo annuncio e cancella0.php cancella un annuncio dal database. Il database è sempre db_annunci e la tabella annunci ha la struttura vista sopra.
<html>
<head>
<title>Bacheca annunci</title>
</head>
<body>
<h2>Bacheca Annunci</h2>
<h3>(riservata agli studenti del polo di Crema)</h3><br />
<?php
$ptr_mysqls=mysql_connect("localhost","root","")
or die("Impossibile connettersi al server MySQL.\n");
mysql_select_db("db_annunci", $ptr_mysqls)
or die("Impossibile aprire il database.\n");
$query_visualizzazione="SELECT * FROM annunci";
if( isset($_GET["parola"]) and ($_GET["parola"]!=="") )
$query_visualizzazione .= " WHERE testo LIKE '%{$_GET['parola']}%'";
$ptr_risultato_query=mysql_query($query_visualizzazione, $ptr_mysqls);
$numero_records=mysql_affected_rows($ptr_mysqls);
if($numero_records !== 0)
{
print "<table cellpadding=\"3\" border=\"1\" width=\"550\">\n";
print "<tr>\n";
$numero_campi=mysql_num_fields($ptr_risultato_query);
for($i_campo=0; $i_campo<$numero_campi; $i_campo++)
{
print "<th>\n";
print mysql_field_name($ptr_risultato_query, $i_campo) . "\n";
print "</th>\n";
}
print "</tr>\n";
while( $record=mysql_fetch_array($ptr_risultato_query, MYSQL_ASSOC) )
{
print "<tr>\n";
foreach($record as $nome_campo => $valore_campo)
{
if($nome_campo == "testo")
print "<td>\n";
else
print "<td nowrap>\n";
print $valore_campo . "\n";
print "</td>\n";
}
print "</tr>\n";
}
print "</table>\n";
}
else
{
print "<font color=\"#FF0000\">";
print "Il database è vuoto o nessuna inserzione contiene la parola inserita.";
print "</font><br />\n";
}
mysql_free_result($ptr_risultato_query);
mysql_close($ptr_mysqls);
?>
<br/><br/>
<a href="inserisci0.php">Inserisci un nuovo annuncio</a>
<br />
<form action="cancella0.php" method="get">
Cancella l'annuncio numero:
<input type="text" name="id_annuncio" size="3">
<input type="submit" value="Cancella">
</form>
<form action="<?php print $_SERVER["PHP_SELF"]; ?>" method="get">
Annunci che contengono questa parola:
<input type="text" name="parola" size="20">
<input type="submit" value="Cerca">
</form>
</body>
</html>
<?php
if( !isset($_POST['testo']) or !isset($_POST['matricola']) )
{
?>
<html>
<head>
<title>Bacheca annunci</title>
</head>
<body>
<h2>Bacheca Annunci<h2>
<h3>(riservata agli studenti del polo di Crema)</h3><br />
<h2>Inserisci un annuncio</h2><br />
<form action="<?php print $_SERVER['PHP_SELF']; ?>" method="POST">
<textarea cols=40 rows=7 name="testo">
</textarea>
<table>
<tr>
<td>Matricola:</td>
<td><input type="text" name="matricola" size="6"></td>
</tr>
</table>
<input type="submit" value="Inserisci!">
</form>
</body>
</html>
<?php
}
else
{
$data=date("Y-m-d");
$ptr_mysqls=mysql_connect("localhost","root","")
or die("Impossibile connettersi al server MySQL.\n");
mysql_select_db("db_annunci", $ptr_mysqls)
or die("Impossibile aprire il database.\n");
$query_inserimento="INSERT INTO annunci (data, testo, matricola) ".
"VALUES('$data', '{$_POST['testo']}', '{$_POST['matricola']}')";
$ptr_risultato_query=mysql_query($query_inserimento, $ptr_mysqls);
if($ptr_risultato_query == FALSE)
{
print "<html>\n";
print "<head>\n";
print "<title>Bacheca annunci</title>\n";
print "</head>\n";
print "<body>\n";
print "<h2>Impossibile inserire l'annuncio.</h2>\n";
print "</body>\n";
print "</html>\n";
}
else
{
header("Location: http://" . $_SERVER['HTTP_HOST'] .
dirname($_SERVER['PHP_SELF']) . "/annunci0.php");
}
mysql_close($ptr_mysqls);
}
?>
<?php
if( !isset($_GET['id_annuncio']) )
{
header("Location: {$_SERVER['HTTP_REFERER']}");
}
else
{
$ptr_mysqls=mysql_connect("localhost","root","")
or die("Impossibile connettersi al server MySQL.\n");
mysql_select_db("db_annunci", $ptr_mysqls)
or die("Impossibile aprire il database.\n");
$query_eliminazione="DELETE FROM annunci WHERE id={$_GET['id_annuncio']}";
$risultato_query=mysql_query($query_eliminazione, $ptr_mysqls);
$numero_record_eliminati=mysql_affected_rows($ptr_mysqls);
if( ($risultato_query == FALSE) or ($numero_record_eliminati==0) )
{
print "<html>\n";
print "<head>\n";
print "<title>Bacheca annunci</title>\n";
print "</head>\n";
print "<body>\n";
print "<h2>Impossibile cancellare l'annuncio.</h2>\n";
print "</body>\n";
print "</html>\n";
}
else
{
header("Location: {$_SERVER['HTTP_REFERER']}");
}
mysql_close($ptr_mysqls);
}
?>
Quando si fa l'upload di una immagine sul server (cioè il client invia al server una intera immagine che quest'ultimo salva sul suo file system) il modulo PHP la rende disponibile al nostro script nella variabile super globale $_FILES. Esattamente come troveremmo nell'array $_POST le variabili inviate con il metodo post.
Se il nostro controllo si chiama "miofile", $_FILES["miofile"] contiene:
Da notare:
Ecco un esempio: upload1.php (funziona solo all'interno del polo di Crema)
<html>
<head>
<title>Upload di una immagine</title>
</head>
<body>
<?php
$remote_ip_chunk = explode(".", $_SERVER['REMOTE_ADDR']);
$server_ip_chunk = explode(".", $_SERVER['SERVER_ADDR']);
$remote_ip=$remote_ip_chunk[0] . $remote_ip_chunk[1];
$server_ip=$server_ip_chunk[0] . $server_ip_chunk[1];
if( $remote_ip !== $server_ip )
{
print "Questo script funziona solo all'interno del Polo di Crema!\n";
print "</body>\n</html>\n";
exit;
}
?>
<?php
if( !isset($_FILES['immagine']) )
{
?>
<h3>Seleziona l'immagine da caricare sul server:</h3>
<form action="<?php print $_SERVER['PHP_SELF']; ?>" method="post"
enctype="multipart/form-data">
<input type="hidden" name="MAX_FILE_SIZE" value="30000" />
<input type="file" name="immagine">
<input type="submit" value="Invia l'immagine">
</form>
<?php
}
else
{
if($_FILES['immagine']['error']!==UPLOAD_ERR_OK)
{
print "<h3>L'immagine non è stata caricata. Riprova.</h3>\n";
}
else
{
# il file va spostato da qualche parte perchè ora è in
# una cartella temporanea
$file_destinazione="./img/" . $_FILES['immagine']['name'];
if( move_uploaded_file($_FILES['immagine']['tmp_name'], $file_destinazione) )
{
print "<h3>L'immagine è stata caricata. Eccola:</h3>\n";
print "<img src=\"$file_destinazione\" />\n";
print "<br /><br />\n";
print "Dimensioni di <b>{$_FILES['immagine']['name']}</b>: " .
"{$_FILES['immagine']['size']} bytes.\n";
}
else
{
print "<h3>L'immagine non è stata caricata. Riprova.</h3>\n";
}
}
}
?>
</body>
</html>
$numero_pc=rand()/getrandmax();
<?php
# In UNIX e PHP il tempo si misura in SECONDI dal 1 gennaio 1970
# In PHP ci sono funzione sia per creare tempi UNIX che
# per convertirli in stringhe
# Dato un istante temporale (una data ad esempio) si crea
# la data UNIX con la funzione mktime().
# La sintassi è: mktime(ore, minuti, secondi, mese, giorno, anno)
# Ad esempio per il 6 Novembre 2003
$tempo_riferimento_UNIX=mktime(0,0,0,11,6,2003);
# Avendo una stringa che rappresenta una data è meglio
# utilizzare la funzione strtotime(stringa).
# Ad esempio per la stessa data nel formato standard MySQL
$tempo_riferimento_UNIX=strtotime("2003/11/6");
# Per leggere dal sistema operativo il valore attuale si usa
$tempo_attuale_UNIX=time();
# Quanti giorni e settimane sono trascorsi tra questi due valori?
# I tempi UNIX sono molto comodi per il calcolo
$giorni=floor(($tempo_attuale_UNIX-$tempo_riferimento_UNIX)/(60*60*24));
$settimane=floor(($tempo_attuale_UNIX-$tempo_riferimento_UNIX)/(60*60*24*7));
# Al contrario, dato un tempo UNIX, possiamo convertirlo
# in una stringa con il comando date(formato,tempo_unix)
# Ad esempio: "d/m/Y" corrisponde a "giorno/mese/anno"
# : "Y-m-d" corrisponde alla data standard MySQL "anno-mese-giorno"
print "Dalla data del " . date("d/m/Y",$tempo_riferimento_UNIX) .
" sono trascorsi $giorni giorni ($settimane settimane).";
?>
Durante la scorsa lezione abbiamo imparato cosa è una sessione HTTP e come si gestisce in PHP. Dal punto di vista del programmatore è molto semplice, basta aggiungere la funzione session_start() all'inizio di ciascuno dei files che dovranno fare parte della sessione. Il programma PHP disporrà delle variabili di sessione (persistenti per la durata della sessione) nella variabile superglobale $_SESSION.
Critico per la sicurezza di una sessione è il fatto che l'ID di sessione viaggia in un cookie e può essere carpito durante il viaggio tra server al client. Vediamo 3 regole per rendere una sessione decentemente sicura:
function verifica_SSL()
{
if( $_SERVER['HTTPS'] !== 'on' )
{
# La connessione non è su socket SSL; invita il browser del client a
# ricaricare la stessa pagina tramite HTTPS
header("Location: https://{$_SERVER['SERVER_NAME']}{$_SERVER['PHP_SELF']}");
exit;
}
# Imposta opzione "cookie_secure": il cookie di sessione verrà
# restituito dal client solo su SSL
ini_set("session.cookie_secure", TRUE);
}
Esercizio 1: Prendiamo confidenza con MySQL e PhpMyAdmin
Create un database che abbia come nome il vostro
account (esempio: rsassi).
Create all'interno del database la tabella "annunci" in modo che abbia la
struttura degli esempi visti a lezione. Inoltre,
tramite PhpMyAdmin aggiungete qualche inserzione
(suggerimento: selezionate la tabella e andate alla scheda "Inserisci").
Modificate i file degli esempi 1
e 2 in modo che funzionino
dal vostro account: (1) cambiate username e password
nella funzione mysql_connect() in modo che
coincidano con i vostri dati; (2) cambiate il nome del
database nella funzione mysql_select_db(),
che nel vostro caso si chiama
"phpweb[numero del gruppo a cui appartenete]".
Copiate i files sul webserver. Funzionano?
Esercizio 2
Tramite PhpMyAdmin, create una tabella "spese" che
contenga 3 campi: (1) data: la data della spesa;
(2) motivo: che cosa avete comperato; (3) importo:
quanto avete speso.
Create lo script inseriscispesa.php che permetta
all'utente di inserire, tramite un form una spesa effettuata
nel database.
Preparare lo script vedispese.php che produca una
tabella di tutte le spese effettuate.
©2004 Roberto Sassi