OBIETTIVI DELLA LEZIONE
Rivedere quanto appreso nelle scorse lezioni alla luce di una applicazione WEB leggermente più complessa; inoltre approfondire alcuni dettagli utili per sviluppare gli elaborati.
Attraverso questo lungo esempio ( essessione3.php), ripassiamo le cose imparate nelle scorse lezioni e vediamo come, mettendo insieme le cose imparate, sia possibile costruire un applicazione che, seppure didattica, sia in grado di grarantire un grado di sicurezza minimale.
Il database contiene un solo utente sassi e la password è semplicemente sassi.
<?php
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);
}
function verifica_utente()
{
# Controlla che l'IP dell'utente non sia cambiato da quando
# è stato identificato
if( isset($_SESSION['utente']) and
($_SESSION['IP_utente']!==$_SERVER['REMOTE_ADDR']) )
$_SESSION['utente']=FALSE;
# Identifica l'utente se e' necessario
if( !isset($_SESSION['utente']) or ($_SESSION['utente']===FALSE) )
{
header("Location: http://" . $_SERVER['HTTP_HOST'] .
dirname($_SERVER['PHP_SELF']) . "/identifica1.php");
exit;
}
}
?>
CREATE TABLE `tab_utenti` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , `utente` VARCHAR( 50 ) NOT NULL , `password` VARCHAR( 32 ) NOT NULL , PRIMARY KEY ( `id` ) );
<?php
require('miefunzioni.inc');
verifica_SSL();
session_start();
# Identificazione Utente
if( !isset($_POST['utente']) or !isset($_POST['password']) )
{
?>
<html>
<head>
<title>Banca PincoPallino</title>
</head>
<body>
<h3>Benvenuto alla Banca PincoPallino</h3>
Per cortesia inserire il nome dell'utente e la password
<form action="<?php print $_SERVER['PHP_SELF']; ?>" method="POST">
<table>
<tr>
<td>Nome Utente:</td>
<td><input type="text" name="utente"></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Identificati"></td>
</tr>
</table>
</form>
</body>
</html>
<?php
}
else
{
$ptr_mysqls=mysql_connect("localhost","root","")
or die("Impossibile connettersi al server MySQL.\n");
mysql_select_db("phpweb998", $ptr_mysqls)
or die("Impossibile aprire il database.\n");
$md5password=md5($_POST['password']);
$query_visualizzazione="SELECT * FROM tab_utenti" .
" WHERE utente='{$_POST['utente']}' AND password='$md5password'";
$ptr_risultato_query=mysql_query($query_visualizzazione, $ptr_mysqls);
$numero_records=mysql_affected_rows($ptr_mysqls);
mysql_close($ptr_mysqls);
if($numero_records == 1)
{
# Utente identificato
$_SESSION['utente']=$_POST['utente'];
$_SESSION['IP_utente']=$_SERVER['REMOTE_ADDR'];
header("Location: http://" . $_SERVER['HTTP_HOST'] .
dirname($_SERVER['PHP_SELF']) . "/essessione3.php");
exit;
}
?>
<html>
<head>
<title>Banca PincoPallino</title>
</head>
<body>
<h3>Attenzione, Nome Utente o Password non corretti.</h3>
</body>
</html>
<?php
}
?>
<?php
require('miefunzioni.inc');
verifica_SSL();
# Se si arriva a questa riga la connessione sta avvenendo su canale criptato;
# Inizializza o ripristina la sessione
session_start();
verifica_utente();
# Se si arriva a questa riga L'utente e' identificato e non ha cambiato
# IP di connessione
?>
<html>
<head>
<title>Banca PincoPallino</title>
</head>
<body>
<h3>Banca PincoPallino</h3>
Salve <?php print $_SESSION['utente']; ?>,
benvenuto al sito della Banca PincoPallino.<br />
Effettua le tue operazioni con la tranquillità della sicurezza!<br />
<br />
<br />
[... operazioni varie ...]
<br />
<br />
<br />
Cambia la tua password:
<form action="modifica1.php" method="post">
<input type="password" name="nuovapassword1">
<input type="password" name="nuovapassword2">
<input type="submit" value="Conferma">
</form>
<br />
<a href="chiudi1.php">Chiudi la sessione</a>.
</body>
</html>
<?php
require('miefunzioni.inc');
verifica_SSL();
session_start();
verifica_utente();
# Cambia la password
$numero_records=0;
if( isset($_POST['nuovapassword1']) and isset($_POST['nuovapassword2']) and
($_POST['nuovapassword1']===$_POST['nuovapassword2']) )
{
$ptr_mysqls=mysql_connect("localhost","root","")
or die("Impossibile connettersi al server MySQL.\n");
mysql_select_db("phpweb998", $ptr_mysqls)
or die("Impossibile aprire il database.\n");
# NON memorizziamo la password ma la sua trasformata md5
$md5password=md5($_POST['nuovapassword1']);
$query_modifica="UPDATE tab_utenti SET password='$md5password'" .
" WHERE utente='{$_SESSION['utente']}'";
$ptr_risultato_query=mysql_query($query_modifica, $ptr_mysqls);
$numero_records=mysql_affected_rows($ptr_mysqls);
mysql_close($ptr_mysqls);
}
?>
<html>
<head>
<title>Richiesta Utente</title>
</head>
<body>
<h3><?php
if($numero_records === 1)
print "Operazione conclusa correttamente.";
else
print "Attenzione, impossibile completare l'operazione richiesta.";
?></h3>
</body>
</html>
<?php
require('miefunzioni.inc');
verifica_SSL();
session_start();
verifica_utente();
# Disalloca tutte le variabili della sessione.
session_unset();
# Distrugge la sessione.
session_destroy();
?>
<html>
<head>
<title>Banca PincoPallino</title>
</head>
<body>
<h3>Arrivederci, grazie di aver utilizzato i nostri servizi online.</h3>
</body>
</html>
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).";
?>
ATTENZIONE: alla pagina Note DevC++ sono state aggiunte alcune informazioni sull'ambiente di sviluppo DevC++, utili per risolvere alcuni dei problemi avuti durante le esercitazioni.
Esercizio 1, FACOLTATIVO
Dato il database dell'esercizio 2 della scorsa lezione, preparare lo script sommaspese.php che chieda all'utente due date e calcoli in uscita la somma del campo "importo" per le spese effettuate nell'intervallo specificato.
Esercizio 2, FACOLTATIVO
Scrivere un programma C che chieda all'utente di immettere una stringa formata solo dai caratteri '#', 'o' e ' ' (lunghezza massima 40). Dopo aver verificato che i caratteri forniti siano corretti (non ci siano altri caratteri), contare quale è la sequenza consecutiva di caratteri identici più lunga per ciascun tipo di carattere (es '####' 4 caratteri '#' consecutivi, ...)
Esercizio 3, FACOLTATIVO
Partendo dal codice scritto per l'esercizio precedente, modificare il file scacchiera.c in modo da visualizzare, ad ogni ciclo, il numero massimo di caratteri consecutivi identici sulla stessa riga.
©2004 Roberto Sassi