OBIETTIVI DELLA LEZIONE
In questa lezione:
Ripasso: variabili esterne $_GET e $_POST
Il client HTTP deve richiedere la pagina al server con uno dei due metodi GET e POST. Come abbiamo visto nelle scorse lezioni, utilizzando il metodo GET gli eventuali controlli provenienti da un form vengono includi nell'URL. In alternativa con il metodo POST vengono inclusi nel corpo della richiesta HTTP. Esempio:
... <form action="provaform.php" method="GET"> nome: <input type="text" name="nome"> cognome: <input type="text" name="cognome"> <input type="submit" value="Visualizza"> </form> ...
La richiesta HTTP sarà:
GET /~sassi/LIA2008/provaform.php?nome=Giovanni&cognome=Rossi HTTP/1.1 Host: www.dti.unimi.it
Lato server, il nostro script può accedere ai valori dei controlli inviati dall'utente tramite la variabile $_GET, che viene popolata automaticamente dal modulo PHP (molto comodo!). Nell'esempio $_GET["nome"] conterrà il valore "Giovanni" e $_GET["cognome"] conterrà il valore "Rossi"
Se invece la La richiesta HTTP fosse stata:
... <form action="provaform.php" method="POST"> nome: <input type="text" name="nome"> cognome: <input type="text" name="cognome"> <input type="submit" value="Visualizza"> </form> ...
La richiesta HTTP sarebbe diventata:
POST /~sassi/LIA2008/provaform.php HTTP/1.0 Host: www.dti.unimi.it Content-Type: application/x-www-form-urlencoded Content-Length: 27 nome=Giovanni&cognome=Rossi
Content-Length è il numero di caratteri contenuti nel corpo della richiesta, mentre Content-Type è il tipo di codifica effettuata. Lato server, il nostro script può accedere ai valori dei controlli inviati dall'utente tramite la variabile $_POST, anch'essa popolata automaticamente dal modulo PHP. Nell'esempio $_POST["nome"] conterrà il valore "Giovanni" e $_POST["cognome"] conterrà il valore "Rossi"
<html>
<head>
<title>Gazzetta di Crema</title>
</head>
<body>
<?php
if( !isset($_COOKIE['idUtente']) ||
(($_COOKIE['idUtente']!=='1') && ($_COOKIE['idUtente']!=='2')) )
{
print "<h2>Benvenuto nella Gazzetta di Crema</h2>\n";
print "Per accedere devi registrarti\n";
print "<br />\n";
print "<br />\n";
print "Per cortesia, inserisci i tuoi dati:\n";
print "<form action=\"escookie2.php\" method=\"get\">\n";
print "Nome: \n";
print "<input type=\"text\" name=\"nome\" />\n";
print "<br />\n";
print "Cognome: \n";
print "<input type=\"text\" name=\"cognome\" />\n";
print "<br />\n";
print "<input type=\"submit\" value=\"Invia\">\n";
print "</form>\n";
}
else
{
?>
<h2>Benvenuto nella Gazzetta di Crema</h2>
<p>ID dell'utente connesso: <font color="#FF0000">
<?php print $_COOKIE['idUtente']; ?>
</font>
(utente autorizzato a leggere <?php print $_COOKIE['articoliPagati']; ?>
articoli gratuitamente entro un ora)
<br />
<br />
NOTIZIE
<br />
<br />
BLA, BLA, ...
<?php
// Qui potreste permettere all'utente di visualizzare gli articoli per cui
// è autorizzato, etc..
}
?>
</body>
</html>
L'action del form punta al file www.dti.unimi.it/~sassi/LIA2008/escookie2.php
che provvederà a richiedere il cookie:
<?php
if( !isset($_COOKIE['idUtente']) )
{
if( ($_GET['nome']=='Roberto') AND ($_GET['cognome']=='Sassi') ) {
$ID=1;
$articoli=5;
}
elseif( ($_GET['nome']=='Mario') AND ($_GET['cognome']=='Bianchi') ) {
$ID=2;
$articoli=3;
}
else {
$ID=0;
$articoli=0;
}
// I cookie verranno cancellati dal client dopo 3600 secondi = 1 ora
setcookie("idUtente", $ID, time()+3600);
setcookie("articoliPagati", $articoli, time()+3600);
}
// rimanda il browser alla pagina di partenza
header("Location: http://" . $_SERVER['HTTP_HOST'] .
dirname($_SERVER['PHP_SELF']) . "/escookie1.php");
?>
escookie2.php produce la seguente risposta del server (attenzione:
è sempre il server a richiedere il cookie):
HTTP/1.x 302 Found Date: Fri, 03 Dec 2008 11:26:09 GMT Server: Apache/2.0.54 (Debian GNU/Linux) PHP/4.3.10-16 mod_ssl/2.0.54 [...] X-Powered-By: PHP/4.3.10-16 Set-Cookie: idUtente=1; expires=Fri, 03 Dec 2008 12:26:09 GMT Set-Cookie: articoliPagati=5; expires=Fri, 03 Dec 2008 12:26:09 GMT Location: http://www.dti.unimi.it/~sassi/LIA2008/escookie1.php Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html; charset=iso-8859-1La risposta del server è "302 Found" (non "200 OK") e chiede al client una redirezione temporanea (nel senso che eventuali richieste future a questo indirizzo non devono necessariamente essere redirette) al sito indicato nell'header HTTP da "Location: ..." (lo avevamo impostato tramite il comando PHP header()).
# HTTP Cookie File # http://www.netscape.com/newsref/std/cookie_spec.html # This is a generated file! Do not edit. # To delete cookies, use the Cookie Manager. www.dti.unimi.it FALSE /~sassi/LIA2008/ FALSE 1133526791 articoliPagati 5 www.dti.unimi.it FALSE /~sassi/LIA2008/ FALSE 1133526791 idUtente 1 ... (altri cookies)
Da adesso in poi, il client, ad ogni richiesta a www.dti.unimi.it/~sassi/LIA2008/... aggiugerà il valore dei cookies:
GET /~sassi/LIA2008/escookie1.php HTTP/1.1
Host: www.dti.unimi.it
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.12) [...]
Accept: text/xml,application/xml,application/xhtml+xml,text/html; [...]
Accept-Language: it,it-it;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://www.dti.unimi.it/~sassi/LIA2008/escookie1.php
Cookie: idUtente=1; articoliPagati=5
Abbiamo visto che HTTP è un protocollo senza memoria di stato e, di sua natura, ogni coppia "domanda del client"/"risposta del server" è indipendente dalle altre.
Una SESSIONE HTTP è semplicemente una serie di domande/risposte effettuate da un client ad un server che condividono uno stato (condividono informazioni che persistono tra una connessione e le successive).
Inoltre, abbiamo visto come esistano sostanzialmente tre metodi per creare persistenza tra diverse coppie di richiesta/risposta HTTP (si veda la lezione 15). Dei tre metodi, quello che utilizza i cookie è sostanzialmente il più efficace. Nel precedente esempio 4B e negli esempi delle scorse lezioni, abbiamo infatti utilizzato i cookie per creare uno stato tra le diverse connessioni. Nell'esempio della lezione scorsa, lo stato era una semplice variabile che conteggiava il numero delle volte che si era visitata una certa pagina. Nell'esempio visto oggi, lo stato era il nome dell'utente contenuto in un cookie. Quindi, costituiscono degli esempio di sessione HTTP.
PROBLEMA!: per applicazioni in cui la sicurezza è critica il cookie ha un punto debole: le informazioni che si vogliono conservare tra una pagina e l'altra vengono salvate in un file sul disco del client e sono quindi modificabili dall'utente.
Ad esempio, utilizzando PuttyTel, se inviamo questa richiesta:
GET /~sassi/LIA2008/escookie1.php HTTP/1.1 Host: www.dti.unimi.it Cookie: idUtente=2; articoliPagati=100
il server ci scambia per un utente autenticato e inoltre ci permette di leggere 100 articoli gratuitamente!
Per tentare una soluzione a questo problema vengono utilizzate contemporaneamente tre strategie:
Se ci pensate bene è proprio ciò che succede quando telefoniamo al telefono di un call center: 1) ci viene dato un codice intervento e 2) sul computer del call center vengono registrati i dati! Le tre strategie vengono implementate in PHP dal meccanismo delle "sessions" (SESSIONI PHP). Un esempio (essessione1.php):
<?php
session_start();
if( !isset($_SESSION['numero_visite']) )
{
$_SESSION['numero_visite']=1;
}
else
{
$_SESSION['numero_visite']++;
}
?>
<html>
<head>
<title>Titolo</title>
</head>
<body>
Il numero di volte che ti sei connesso a questa pagina è
<b><?php print $_SESSION['numero_visite']; ?></b>.
</body>
</html>
Tutti gli script che vogliono accedere alla sessione devono iniziare con la funzione session_start(). Come funziona?:
HTTP/1.x 200 OK Date: Mon, 10 May 2004 08:07:29 GMT Server: Apache/1.3.26 (Unix) Debian GNU/Linux PHP/4.1.2 mod_ssl/2.8.9 OpenSSL/0.9.6g mod_perl/1.26 X-Powered-By: PHP/4.1.2 Set-Cookie: PHPSESSID=42b93d2d874a2f169896583a9e4d85db; path=/ [...]Inoltre crea sul server un file dove verranno salvate le variabili da conservare per tutta la durata della sessione. Il nome del file contiene il valore di PHPSESSID. As esempio, viene creato il file sess_42b93d2d874a2f169896583a9e4d85db.
GET /~sassi/LIA2008/essessione1.php HTTP/1.1 Host: www.dti.unimi.it [...] Cookie: PHPSESSID=42b93d2d874a2f169896583a9e4d85db [...]mentre il contenuto del file di sessione sess_42b93d2d874a2f169896583a9e4d85db è
numero_visite|i:5;La variabile $_SESSION['numero_visite'] conterrà il valore 5.
Per fare in modo che il valore di una variabile sia disponibile per tutta la sessione, basta aggiungere un elemento all'array $_SESSION. I dati vengono automaticamente salvati nel file di sessione.
Quando si decide di chiudere una sessione:
// elimina tutte le variabili dalla sessione session_unset(); // chiude la sessione session_destroy();
La funzione session_start() fa quindi cose diverse a seconda che
trovi o meno un file con il nome corrispondente al cookie PHPSESSID ricevuto.
Le sessioni NON sono un modo per autenticare l'utente, ma solo per capire che
le richieste vengono da uno stesso utente (che eventualmente abbiamo autenticato).
In questa breve sezione aumentiamo la conoscenza di base del PHP
Come in C, anche in PHP è possibile costruire delle funzioni, che ritornino o meno dei valori. La sintassi generale è
function nome_della_funzione($parametro1, $parametro2) { // corpo della funzione return $valore_restituito; }Anche per le funzioni, non è necessario specificare né il tipo dei parametri, né il tipo del valore che viene restituito.
<?php
function fattoriale($n)
{
$risultato=1;
for($i=2; $i<=$n; $i++)
$risultato*=$i;
return $risultato;
}
?>
<html>
<head>
<title>Fattoriale di un numero</title>
</head>
<body>
<?php
if( isset($_GET['numero']) )
{
print "Il fattoriale di {$_GET['numero']} è " . fattoriale($_GET['numero']);
}
else
{
?>
<form action="<?php print $_SERVER['PHP_SELF']?>", method="get">
Calcola il fattoriale di
<input type="text" name="numero">
<input type="submit" value="Calcola!">
</form>
<?php
}
?>
</body>
</html>
I parametri sono passati per valore. Se si desidera che un parametro sia
passato per riferimento, nella dichiarazione della funzione bisogna
anteporre l'operatore & al nome della variabile.
<?php
function fattoriale($n, &$risultato)
{
$risultato=1;
for($i=2; $i<=$n; $i++)
$risultato*=$i;
return $risultato;
}
?>
[...]
<?php
if( isset($_GET['numero']) )
{
fattoriale($_GET['numero'], $r);
print "Il fattoriale di {$_GET['numero']} è $r";
}
else
{
[...]
Le funzioni in PHP possono essere ricorsive.
<html> <head> <title>Il mio sito</title> </head> <body> <font color="#FF0000"><h2>IL MIO SITO</h2></font> <hr size="1">ed file footer.inc:
<hr size="1"> Contatta il <a href="mailto:webmaster@ilmiosito.it">WebMaster</a>! </body> </html>ecco lo script che li include (hf.php):
<?php
include("header.inc");
?>
<br />
<h2>Contenuto del sito</h2>
<br />
<?php
include("footer.inc");
?>
Dopo averlo installato, fate partire i vari server:
Copiate i vostri files nella cartella:
(modificando opportunamente il path in base alla vostra installazione).
Per visualizzare la vostra pagina, nell'indirizzo del browser selezionate "localhost" o 127.0.0.1 seguito dalla pagina che volete visualizzare, con indirizzo relativo rispetto alla root del webserver (la cartella dove avete messo i files). Se utilizzate EasyPHP potete anche cliccare con il tasto destro sull'icona PHP che avete vicino all'orologio e selezionare "Local Web".
Esercizio 1
Preparare lo script memorizzanome1.php che
inizia una sessione e, dopo aver chiesto all'utente
il nome, lo memorizza nella variabile di sessione "nome".
Se "nome" è già contenuto in $_SESSION, presenta all'utente
una pagina di saluto contenente il nome dell'utente.
Preparare lo script memorizzanome2.php che
legge il valore della variabile di sessione "nome" e
presenta all'utente una pagina di benvenuto contenente il nome.
Funzionano entrambi? Chiudete il brower. Apritelo di
nuovo e visualizzate memorizzanome2.php.
La sessione è ancora aperta? Perché
©2008 Roberto Sassi