Note finali

Venerdì, 14 Gennaio 2005

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.

Un lungo esempio

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.

Funzioni di servizio

Un file iniziale di funzioni di servizio: miefunzioni.inc

<?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;
    }
}

?>

Identificazione dell'utente

Lo script che identifica l'utente: identifica1.php. Utilizza la tabella utenti creata con il comando SQL:

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("dbprova1", $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
}
?>

Home page

Il file principale: essessione3.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>

Modifica della password

lo script che modifica la password: modifica1.php

<?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("dbprova1", $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>

Chiusura delle sessione

Lo script di chiusura chiudi1.php

<?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>

Java è lento?

Abbiamo visto durante la prima parte del corso che un programma Java viene compilato con il compilatore Java (javac) in modo da produrre il bytecode che viene poi eseguito dalla Virtual Machine.

Nelle prime versioni di Java, il bytecode veniva interpretato dalla JVM. Di conseguenza l'esecuzione era più lenta. Se per certe applicazioni questo non era comunque un problema (la portabilità ripagava la lentezza), lo era per altre (pensate ad applicazioni numeriche, al limite i giochi elettronici).

Per questo motivo, la JVM venne migliorata con una tecnologia detta "just in time" (JIT, pressapoco a partire dalla versione Java 1.1). Quando una certa classe veniva invocata, il bytecode veniva compilato dalla JVM JIT nel codice oggetto della piattaforma in uso. La compilazione selettiva (solo quando una porzione di codice era invocata) riduceva i tempi morti iniziali. La tecnologia JIT ebbe un discreto successo. La JVM JIT Microsoft (jview, oggi ferma alla versione 1.1.4) che la implementava bene era (ed è tuttora) piuttosto veloce.

Anche la semplice compilazione JIT aveva i suoi limiti. Infatti, l'ottimizzazione che la JVM JIT poteva eseguire era molto limitata (il codice che non era ancora stato invocato non veniva preso in cosiderazione). La generazione successiva di JVM incorporò quindi una nuova tecnologia detta "HotSpot" (in forma matura, dalla versione Java 1.3): il codice viene prima interpretato e compilato nel codice oggetto della piattaforma nativa, solo quando considerato "Hot", cioè quando la compilazione ne ridurrebbe decisamente i tempi di esecuzione (tenuto conto dei tempi non indifferenti di compilazione). La JVM HotSpot, interpretando prima il codice, può eseguire delle ottimizzazioni ben più significative. Letteralmente, una JVM JIT compila tutto il codice prima di eseguirlo, ma generalmente anche una JVM HotSpot è chiamata JIT.

Le JVM attuali utilizzano la tecnologia HotSpot. Inoltre, per applicazioni che devono essere molto veloci è possibile richiedere un livello di ottimizzazione HotSpot superiore (al prezzo di un tempo più significativo di attesa quando si lancia l'applicazione) tramite l'opzione -server.

Tanto per avere un'idea della reale velocità di Java, ecco un test effettuato utilizzando un benchmark per il calcolo numerico e scientifico (SciMark 2.0a). Nella tabella è riportata, per ogni JVM, una stima del numero di milioni di operazioni in virgola mobile effettuate al secondo (MegaFlops). Più il numero è alto e più la JVM è veloce. Per un confronto, sono riportati anche i risultati ottenuti compilando un codice equivalente in C con due diversi compilatori (Microsoft VC7.1 e GCC 3.3.1). I test sono stati eseguiti su di un portatile Pentium M 735 1.7MHz (Windows XP).

(Mflops)
Score FFT SOR Monte Carlo Sparse matmult LU
Sun Microsystems Inc.
JVM 1.5.0 -server
335.03 190.17 637.01 70.90 260.68 516.39
IBM Corporation
JVM 1.4.2
309.24 213.44 493.33 77.69 283.34 478.39
IBM Corporation
JVM 1.4.1
307.63 213.44 484.77 80.01 283.22 476.72
Microsoft Corp.
JVM 1.1.4
254.34 108.85 462.54 36.52 203.28 460.48
Sun Microsystems Inc.
JVM 1.4.2
235.03 97.20 496.00 33.17 227.24 321.56
Sun Microsystems Inc.
JVM 1.5.0
233.13 104.67 495.87 40.49 210.46 314.16
Sun Microsystems Inc.
JVM 1.3.1_02
219.37 107.25 478.63 35.65 164.04 311.29
Sun Microsystems Inc.
JVM 1.4.1_02
196.26 87.81 469.30 40.73 173.10 210.37
 
GNU GCC 3.3.1 (MinGW) 404.91 291.29 639.12 98.18 427.78 568.18
Microsoft VC 7.1 (.NET 2003) 364.28 267.93 610.76 63.22 446.73 432.75


Le opzioni utilizzate con i due compilatori C sono state:

GNU GCC 3.3.1 (MinGW) gcc -O2 -malign-double -funroll-loops -march=pentium4
-ffast-math -mfpmath=sse -msse2
Microsoft VC 7.1 (.NET 2003) cl -Za -W3 -nologo -Ox /G7 /arch:SSE2


La JVM più veloce (1.5.0 HotSpot, versione server) è risultata essere solo l'8% più lenta della versione C compilata con Microsoft VC 7.1 (che è un buon compilatore). Il test è molto limitato, ma mostra come le nuove JVM abbiano fatto molti progressi in termini di velocità di elaborazione. Java non è più così lento...

Lab

Debug di un file Java

Spesso un programma contiene errori e, come abbiamo sperimentato durante le esercitazioni, non è detto sia facile individuarlo. Una tecnica utilizzata per localizzare errori si chiama debug (togliere i bug, cioè gli errori). Fare il debug di un file consiste nell'eseguire passo per passo le istruzioni del nostro codice ed ogni istante poter rilevare cosa contengono le variabili che compongono il nostro codice.

Proviamo insieme a debuggare un file.

Esercizio 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.

©2004 Roberto Sassi