8. Ejercicio IMPOTS con MySQL
Ya hemos escrito tres versiones de este ejercicio. La última, version, utilizaba una clase de cálculo de impuestos. Esta clase tomaba de un archivo de texto los datos necesarios para dicho cálculo. A partir de ahora, los tomará de una base de datos. Para ello, escribimos un primer código que transferirá los datos del archivo de texto a una base de datos.
El archivo de texto impots.txt es el siguiente:
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
La base de datos que hay que crear es la siguiente:
![]() | ![]() |
La base se llama [dbimpots] y tiene una única tabla [impots]. La utiliza el usuario [root] sin contraseña.
8.1. Transferencia de un archivo de texto a una tabla MySQL (txt2mysql)
<?php
// se transfiere el archivo de texto con los datos necesarios para el cálculo de los impuestos
// a una tabla mysql
// los datos
$IMPOTS = "impots.txt";
$BASE = "dbimpots";
$TABLE = "impots";
$USER = "root";
$PWD = "";
$HOTE = "localhost";
// los datos necesarios para el cálculo del impuesto se han colocado en el archivo $IMPOTS
// a razón de una línea por tabla en el formato
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);
// ¿Se ha producido algún error?
if ($erreur) {
print "$erreur\n";
exit;
}//if
// se transfieren estas tablas a una tabla mysql
$erreur = copyToMysql($limites, $coeffR, $coeffN, $HOTE, $USER, $PWD, $BASE, $TABLE);
if ($erreur)
print "$erreur\n";
else
print "Transfert opéré\n";
// fin
exit;
// --------------------------------------------------------------------------
function copyToMysql($limites, $coeffR, $coeffN, $HOTE, $USER, $PWD, $BASE, $TABLE) {
// copia las 3 tablas numéricas $limites, $coeffR, $coeffN
// en la tabla $TABLE de la base de datos mysql $BASE
// la base mysql se encuentra en la máquina $HOTE
// el usuario está identificado por $USER y $PWD
// conexión
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";
// eliminación de la tabla
$requête = "drop table $TABLE";
exécuteRequête($connexion, $requête);
// creación de la tabla
$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)";
// relleno
for ($i = 0; $i < count($limites); $i++) {
// consulta de inserción
$requête = "insert into $TABLE (limites,coeffR,coeffN) values ($limites[$i],$coeffR[$i],$coeffN[$i])";
// ejecución de la consulta
list($erreur, $res) = exécuteRequête($connexion, $requête);
// retorno en caso de error
if ($erreur)
return "$requête : erreur ($erreur)";
}//for
// se ha terminado - nos desconectamos
déconnecte($connexion);
// retorno sin error
return "";
}
// --------------------------------------------------------------------------
function getTables($IMPOTS) {
// $IMPOTS: el nombre del archivo que contiene los datos de las tablas $limites, $coeffR, $coeffN
...
// fin
return array("", $limites, $coeffR, $coeffN);
}
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
// se elimina el marcador de fin de línea de $ligne si existe
...
// fin
return($ligne);
}
// ---------------------------------------------------------------------------------
function connecte($dsn, $login, $pwd) {
// conecta ($login,$pwd) a la base $dsn
// devuelve el id de la conexión junto con un mensaje de error
...
}
//se conecta
// ---------------------------------------------------------------------------------
function déconnecte($connexion) {
// cierra la conexión identificada por $connexion
...
}
// ---------------------------------------------------------------------------------
function exécuteRequête($connexion, $sql) {
// ejecuta la consulta $sql en la conexión $connexion
// devuelve una matriz de 2 elementos ($erreur,$résultat)
...
}
Resultados en pantalla:
8.2. El programa de cálculo de impuestos ( impots_04)
Este version utiliza una clase Impuestos que busca en una base de datos los valores necesarios para el cálculo del impuesto. Introducimos aquí un nuevo concepto, el de consulta preparada. La ejecución de una orden SQL por parte de una SGBD se realiza en dos fases:
- se prepara la consulta: el SGBD preparará un plan de ejecución optimizado para la consulta. Se trata de ejecutarla de la forma más eficaz posible.
- Se ejecuta la consulta.
Si una misma consulta se ejecuta N veces, los dos pasos anteriores se realizan N veces. Sin embargo, es posible preparar la consulta una vez y ejecutarla N veces. Para ello hay que utilizar consultas preparadas. Si $requête es la orden SQL que se va a ejecutar y $connexion el objeto PDO que representa la conexión:
- $statement=$connexion->prepare($requête) prepara una consulta y devuelve la consulta «preparada»
- $statement->execute() ejecuta la consulta preparada.
Si la consulta preparada es una orden select, entonces
- $statement->fetchAll() devuelve todas las filas de la tabla resultante de la selección en forma de una matriz T, donde T[i,j] es el valor de la columna j de la fila i de la tabla
- $statement->fetch() devuelve la fila actual de la tabla en forma de una matriz T, donde T[j] es el valor de la columna j de la fila
La consulta preparada aporta otras ventajas además de una mayor eficiencia. En particular, ofrece mayor seguridad. Por lo tanto, debería utilizarse sistemáticamente.
<?php
// prueba -----------------------------------------------------
// definición de las constantes
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$TABLE = "impots";
$BASE = "dbimpots";
$USER = "root";
$PWD = "";
$HOTE="localhost";
// los datos necesarios para el cálculo del impuesto se han colocado en la tabla mysqL $TABLE
// perteneciente a la base de datos $BASE. La tabla tiene la siguiente estructura
// límites decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
// los parámetros de los contribuyentes (estado civil, número de hijos, salario anual)
// se han colocado en el archivo de texto $DATA a razón de una línea por contribuyente
// los resultados (estado civil, número de hijos, salario anual, impuesto a pagar) se colocan en
// el archivo de texto $RESULTATS, a razón de un resultado por línea
// se crea un objeto Impuestos
$I = new Impôts($HOTE, $USER, $PWD, $BASE, $TABLE);
// ¿ha habido algún error?
$erreur=$I->getErreur();
if ($erreur) {
print "$I->erreur\n";
exit;
}//if
// se crea un objeto de utilidades
$u = new Utilitaires();
// apertura del archivo de datos de los contribuyentes
$data = fopen($DATA, "r");
if (!$data) {
print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
exit;
}
// apertura del archivo de resultados
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
exit;
}
// se procesa la línea actual del archivo de datos de los contribuyentes
while ($ligne = fgets($data, 100)) {
// se elimina el posible marcador de fin de línea
$ligne = $u->cutNewLineChar($ligne);
// se recuperan los 3 campos «casado», «hijos» y «salario» que forman $ligne
list($marié, $enfants, $salaire) = explode(",", $ligne);
// se calcula el impuesto
$impôt = $I->calculer($marié, $enfants, $salaire);
// se introduce el resultado
fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
// dato siguiente
}
// se cierran los archivos
fclose($data);
fclose($résultats);
// fin
exit;
// ---------------------------------------------------------------------------------
// definición de una clase Impuestos
class Impôts {
// atributos: las 3 tablas de datos
private $limites;
private $coeffR;
private $coeffN;
private $erreur;
private $nbLimites;
// getter
public function getErreur(){
return $this->erreur;
}
// constructor
function __construct($HOTE, $USER, $PWD, $BASE, $TABLE) {
// inicializa los atributos $limites, $coeffR, $coeffN
// los datos necesarios para el cálculo del impuesto se han colocado en la tabla mysql $TABLE
// perteneciente a la base $BASE. La tabla tiene la siguiente estructura
// límites decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
// la conexión a la base de datos mysql de la máquina $HOTE se realiza con la identidad ($USER,$PWD)
// inicializa el campo $erreur con un posible error
// vacío si no hay error
//
// conexión a la base de datos 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;
}
// lectura de la tabla $TABLE
$requête = "select limites,coeffR,coeffN from $TABLE";
// ejecuta la consulta $requête en la conexión $connexion
try {
$statement = $connexion->prepare($requête);
$statement->execute();
// procesamiento del resultado de la consulta
while ($colonnes = $statement->fetch()) {
$this->limites[] = $colonnes[0];
$this->coeffR[] = $colonnes[1];
$this->coeffN[] = $colonnes[2];
}
// sin errores
$this->erreur = "";
// número de elementos de la matriz de límites
$this->nbLimites = count($this->limites);
} catch (PDOException $e) {
$this->erreur = $e->getMessage();
}
// desconexión
déconnecte($connexion);
}
// --------------------------------------------------------------------------
function calculer($marié, $enfants, $salaire) {
// $marié: sí, no
// $enfants: número de hijos
// $salaire: salario anual
// ¿El objeto se encuentra en buen estado?
if ($this->erreur)
return -1;
// número de participaciones
...
}
}
// ---------------------------------------------------------------------------------
// una clase de funciones de utilidad
class Utilitaires {
function cutNewLinechar($ligne) {
// se elimina el marcador de fin de línea de $ligne si existe
...
}
}
// ---------------------------------------------------------------------------------
function connecte($dsn, $login, $pwd) {
// conecta ($login,$pwd) a la base $dsn
// devuelve el id de la conexión junto con un mensaje de error
...
}
//se conecta
// ---------------------------------------------------------------------------------
function déconnecte($connexion) {
// cierra la conexión identificada por $connexion
...
}
Resultados: los mismos que con las versiones anteriores.
Comentarios
Las novedades se encuentran en las líneas 98-109:
- línea 99: la orden SQL select, que permitirá recuperar los datos necesarios para el cálculo del impuesto.
- línea 102: preparación de la orden SQL select
- línea 103: ejecución de la orden preparada
- líneas 105-109: procesamiento línea por línea de la tabla de resultados de la selección

