8. Esercizio IMPOTS con MySQL
Abbiamo già scritto tre versioni di questo esercizio. L'ultima versione utilizzava una classe per il calcolo delle imposte. Questa classe prelevava da un file di testo i dati necessari per il calcolo. D'ora in poi li preleverà da un database. A tal fine, scriviamo un primo codice che trasferirà i dati dal file di testo a un database.
Il file di testo impots.txt è il seguente:
12620:13190:15640:24740:31810:39970:48360:55790:92970:127860:151250:172040:195000:0
0:0.05:0.1:0.15:0.2:0.25:0.3:0.35:0.4:0.45:0.5:0.55:0.6:0.65
0:631:1290.5:272.5:3309.5:4900:6898.5:9316.5:12106:16754.5:23147.5:30710:39312:49062
Il database da creare è il seguente:
![]() | ![]() |
Il database si chiama [dbimpots] e contiene un'unica tabella, [impots]. Viene gestito dall'utente [root] senza password.
8.1. Trasferimento di un file di testo in una tabella MySQL (txt2mysql)
<?php
// trasferisce il file di testo contenente i dati necessari al calcolo delle imposte
// in una tabella MySQL
// i dati
$IMPOTS = "impots.txt";
$BASE = "dbimpots";
$TABLE = "impots";
$USER = "root";
$PWD = "";
$HOTE = "localhost";
// i dati necessari per il calcolo dell'imposta sono stati inseriti nel file $IMPOTS
// con una riga per ogni tabella nel formato
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);
// Si è verificato un errore?
if ($erreur) {
print "$erreur\n";
exit;
}//if
// si trasferiscono queste tabelle in un database MySQL
$erreur = copyToMysql($limites, $coeffR, $coeffN, $HOTE, $USER, $PWD, $BASE, $TABLE);
if ($erreur)
print "$erreur\n";
else
print "Transfert opéré\n";
// fine
exit;
// --------------------------------------------------------------------------
function copyToMysql($limites, $coeffR, $coeffN, $HOTE, $USER, $PWD, $BASE, $TABLE) {
// copia le 3 tabelle numeriche $limites, $coeffR, $coeffN
// nella tabella $TABLE del database MySQL $BASE
// il database MySQL si trova sul computer $HOTE
// l'utente è identificato da $USER e $PWD
// connessione
list($erreur, $connexion) = connecte("mysql:host=$HOTE;dbname=$BASE", $USER, $PWD);
if ($erreur)
return "Erreur lors de la connexion à MySql sous l'identité ($HOTE,$USER,$PWD) : $erreur\n";
// eliminazione della tabella
$requête = "drop table $TABLE";
exécuteRequête($connexion, $requête);
// creazione della tabella
$requête = "create table $TABLE (limites decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2))";
list($erreur, $res) = exécuteRequête($connexion, $requête);
if ($erreur)
return "$requête : erreur ($erreur)";
// compilazione
for ($i = 0; $i < count($limites); $i++) {
// query di inserimento
$requête = "insert into $TABLE (limites,coeffR,coeffN) values ($limites[$i],$coeffR[$i],$coeffN[$i])";
// esecuzione della query
list($erreur, $res) = exécuteRequête($connexion, $requête);
// ritorno in caso di errore
if ($erreur)
return "$requête : erreur ($erreur)";
}//ciclo
// finito - ci disconnettiamo
déconnecte($connexion);
// ritorno senza errori
return "";
}
// --------------------------------------------------------------------------
function getTables($IMPOTS) {
// $IMPOTS: il nome del file contenente i dati delle tabelle $limites, $coeffR, $coeffN
...
// fine
return array("", $limites, $coeffR, $coeffN);
}
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
// si elimina il carattere di fine riga da $ligne, se presente
...
// fine
return($ligne);
}
// ---------------------------------------------------------------------------------
function connecte($dsn, $login, $pwd) {
// connette ($login,$pwd) al database $dsn
// restituisce l'ID della connessione e un messaggio di errore
...
}
//si connette
// ---------------------------------------------------------------------------------
function déconnecte($connexion) {
// chiude la connessione identificata da $connexion
...
}
// ---------------------------------------------------------------------------------
function exécuteRequête($connexion, $sql) {
// esegue la query $sql sulla connessione $connexion
// restituisce un array di 2 elementi ($erreur,$résultat)
...
}
Risultati sullo schermo:
8.2. Il programma di calcolo delle imposte ( impots_04)
Questa versione utilizza una classe Impôts che recupera da un database i valori necessari per il calcolo dell'imposta. Introduciamo qui un nuovo concetto, quello di query preparata. L’esecuzione di un comando SQL tramite un SGBD avviene in due fasi:
- la query viene preparata: il SGBD preparerà un piano di esecuzione ottimizzato per la query. L'obiettivo è eseguirla nel modo più efficiente possibile.
- la query viene eseguita.
Se una stessa query viene eseguita N volte, le due fasi precedenti vengono ripetute N volte. È tuttavia possibile preparare la query una sola volta ed eseguirla N volte. A tal fine è necessario utilizzare le query preparate. Se $requête è il comando SQL da eseguire e $connexion è l’oggetto PDO che rappresenta la connessione:
- $statement=$connexion->prepare($requête) prepara una query e restituisce la query "preparata"
- $statement->execute() esegue la query preparata.
Se la query preparata è un comando select, allora
- $statement->fetchAll() restituisce tutte le righe della tabella risultante da select sotto forma di un array T, dove T[i,j] è il valore della colonna j della riga i della tabella
- $statement->fetch() restituisce la riga corrente della tabella sotto forma di un array T, dove T[j] è il valore della colonna j della riga
La query preparata offre altri vantaggi oltre a una maggiore efficienza. In particolare, garantisce una maggiore sicurezza. Pertanto, dovrebbe essere utilizzata sistematicamente.
<?php
// test -----------------------------------------------------
// definizione delle costanti
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$TABLE = "impots";
$BASE = "dbimpots";
$USER = "root";
$PWD = "";
$HOTE="localhost";
// i dati necessari per il calcolo dell'imposta sono stati inseriti nella tabella mysqL $TABLE
// appartenente al database $BASE. La tabella presenta la seguente struttura
// limiti decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
// i parametri dei contribuenti (stato civile, numero di figli, stipendio annuo)
// sono stati inseriti nel file di testo $DATA con una riga per ogni contribuente
// i risultati (stato civile, numero di figli, stipendio annuo, imposta da pagare) sono stati inseriti nel
// nel file di testo $RESULTATS, con un risultato per riga
// viene creato un oggetto «Imposte»
$I = new Impôts($HOTE, $USER, $PWD, $BASE, $TABLE);
// si è verificato un errore?
$erreur=$I->getErreur();
if ($erreur) {
print "$I->erreur\n";
exit;
}//if
// si crea un oggetto "utilità"
$u = new Utilitaires();
// apertura del file dei dati dei contribuenti
$data = fopen($DATA, "r");
if (!$data) {
print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
exit;
}
// apertura del file dei risultati
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
exit;
}
// si elabora la riga corrente del file dei dati dei contribuenti
while ($ligne = fgets($data, 100)) {
// si rimuove l'eventuale carattere di fine riga
$ligne = $u->cutNewLineChar($ligne);
// si recuperano i 3 campi «coniuge», «figli» e «stipendio» che formano $ligne
list($marié, $enfants, $salaire) = explode(",", $ligne);
// si calcola l’imposta
$impôt = $I->calculer($marié, $enfants, $salaire);
// si inserisce il risultato
fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
// dato successivo
}
// si chiudono i file
fclose($data);
fclose($résultats);
// fine
exit;
// ---------------------------------------------------------------------------------
// definizione di una classe «Imposte»
class Impôts {
// attributi: le 3 tabelle di dati
private $limites;
private $coeffR;
private $coeffN;
private $erreur;
private $nbLimites;
// getter
public function getErreur(){
return $this->erreur;
}
// costruttore
function __construct($HOTE, $USER, $PWD, $BASE, $TABLE) {
// inizializza gli attributi $limites, $coeffR, $coeffN
// i dati necessari per il calcolo dell'imposta sono stati inseriti nella tabella MySQL $TABLE
// appartenente al database $BASE. La tabella presenta la seguente struttura
// limiti decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
// la connessione al database MySQL del computer $HOTE avviene con le credenziali ($USER,$PWD)
// inizializza il campo $erreur con un eventuale errore
// vuoto se non ci sono errori
//
// connessione al database MySQL
$DSN = "mysql:host=$HOTE;dbname=$BASE";
list($erreur, $connexion) = connecte($DSN, $USER, $PWD);
if ($erreur) {
$this->erreur = "Erreur lors de la connexion à MySql sous l'identité ($HOTE,$USER,$PWD) : $erreur\n";
return;
}
// lettura della tabella $TABLE
$requête = "select limites,coeffR,coeffN from $TABLE";
// esegue la query $requête sulla connessione $connexion
try {
$statement = $connexion->prepare($requête);
$statement->execute();
// elaborazione del risultato della query
while ($colonnes = $statement->fetch()) {
$this->limites[] = $colonnes[0];
$this->coeffR[] = $colonnes[1];
$this->coeffN[] = $colonnes[2];
}
// nessun errore
$this->erreur = "";
// numero di elementi dell'array di limiti
$this->nbLimites = count($this->limites);
} catch (PDOException $e) {
$this->erreur = $e->getMessage();
}
// disconnessione
déconnecte($connexion);
}
// --------------------------------------------------------------------------
function calculer($marié, $enfants, $salaire) {
// $marié: sì, no
// $enfants: numero di figli
// $salaire: stipendio annuo
// L'oggetto è in buone condizioni?
if ($this->erreur)
return -1;
// numero di quote
...
}
}
// ---------------------------------------------------------------------------------
// una classe di funzioni di utilità
class Utilitaires {
function cutNewLinechar($ligne) {
// si rimuove il carattere di fine riga da $ligne, se presente
...
}
}
// ---------------------------------------------------------------------------------
function connecte($dsn, $login, $pwd) {
// collega ($login,$pwd) al database $dsn
// restituisce l'ID della connessione e un messaggio di errore
...
}
//si connette
// ---------------------------------------------------------------------------------
function déconnecte($connexion) {
// chiude la connessione identificata da $connexion
...
}
Risultati: gli stessi delle versioni precedenti.
Commenti
Le novità si trovano nelle righe 98-109:
- riga 99: il comando SQL select che consentirà di recuperare i dati necessari al calcolo dell'imposta.
- riga 102: preparazione del comando SQL select
- riga 103: esecuzione del comando preparato
- righe 105-109: elaborazione riga per riga della tabella dei risultati di select

