8. Вправа IMPOTS з MySQL
Ми вже написали три версії цього завдання. В останній версії використовувався клас для розрахунку податку. Цей клас отримував дані, необхідні для розрахунку, з текстового файлу. Тепер він буде отримувати їх із бази даних. Для цього ми пишемо перший код, який перенесе дані з текстового файлу в базу даних.
Текстовий файл impots.txt має такий вигляд:
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
База даних, яку потрібно створити, має такий вигляд:
![]() | ![]() |
База має назву [dbimpots] і містить єдину таблицю [impots]. Доступ до неї здійснює користувач [root] без пароля.
8.1. Перенесення текстового файлу в таблицю MySQL (txt2mysql)
<?php
// передає текстовий файл з даними, необхідними для розрахунку податків
// у таблицю MySQL
// дані
$IMPOTS = "impots.txt";
$BASE = "dbimpots";
$TABLE = "impots";
$USER = "root";
$PWD = "";
$HOTE = "localhost";
// дані, необхідні для розрахунку податку, були розміщені у файлі $IMPOTS
// по одному рядку на таблицю у вигляді
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);
// Чи сталася помилка?
if ($erreur) {
print "$erreur\n";
exit;
}//if
// ці масиви переносимо в таблицю MySQL
$erreur = copyToMysql($limites, $coeffR, $coeffN, $HOTE, $USER, $PWD, $BASE, $TABLE);
if ($erreur)
print "$erreur\n";
else
print "Transfert opéré\n";
// кінець
exit;
// --------------------------------------------------------------------------
function copyToMysql($limites, $coeffR, $coeffN, $HOTE, $USER, $PWD, $BASE, $TABLE) {
// копіюємо 3 числові масиви $limites, $coeffR, $coeffN
// у таблицю $TABLE бази даних MySQL $BASE
// база даних MySQL знаходиться на комп'ютері $HOTE
// користувач ідентифікується за допомогою $USER та $PWD
// вхід
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";
// видалення таблиці
$requête = "drop table $TABLE";
exécuteRequête($connexion, $requête);
// створення таблиці
$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)";
// заповнення
for ($i = 0; $i < count($limites); $i++) {
// запит на вставку
$requête = "insert into $TABLE (limites,coeffR,coeffN) values ($limites[$i],$coeffR[$i],$coeffN[$i])";
// виконання запиту
list($erreur, $res) = exécuteRequête($connexion, $requête);
// повернення у разі помилки
if ($erreur)
return "$requête : erreur ($erreur)";
}//цикл
// все закінчено — виходимо з системи
déconnecte($connexion);
// повернення без помилки
return "";
}
// --------------------------------------------------------------------------
function getTables($IMPOTS) {
// $IMPOTS: ім'я файлу, що містить дані з таблиць $limites, $coeffR, $coeffN
...
// кінець
return array("", $limites, $coeffR, $coeffN);
}
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
// видаляється маркер кінця рядка з $ligne, якщо він існує
...
// кінець
return($ligne);
}
// ---------------------------------------------------------------------------------
function connecte($dsn, $login, $pwd) {
// підключає ($login,$pwd) до бази $dsn
// повертає ідентифікатор з’єднання та повідомлення про помилку
...
}
//встановлює з'єднання
// ---------------------------------------------------------------------------------
function déconnecte($connexion) {
// закриває з’єднання, ідентифіковане як $connexion
...
}
// ---------------------------------------------------------------------------------
function exécuteRequête($connexion, $sql) {
// виконує запит $sql через з’єднання $connexion
// повертає масив із 2 елементів ($erreur, $résultat)
...
}
Результати на екрані:
8.2. Програма для розрахунку податку ( impots_04)
Ця версія використовує клас Impôts, який отримує з бази даних значення, необхідні для розрахунку податку. Тут ми вводимо нове поняття — підготовлений запит. Виконання команди SQL за допомогою SGBD відбувається у два етапи:
- запит готується: SGBD готує оптимізований план виконання для запиту. Мета полягає в тому, щоб виконати його якомога ефективніше.
- запит виконується.
Якщо один і той самий запит виконується N разів, обидва попередні етапи виконуються N разів. Однак можна підготувати запит один раз і виконати його N разів. Для цього потрібно використовувати підготовлені запити. Якщо $requête — це команда SQL, яку потрібно виконати, а $connexion — об’єкт PDO, що представляє з’єднання:
- $statement=$connexion->prepare($requête) готує запит і повертає «підготовлений» запит
- $statement->execute() виконує підготовлений запит.
Якщо підготовлений запит є командою select, то
- $statement->fetchAll() повертає всі рядки таблиці, отриманої в результаті виконання select, у вигляді масиву T, де T[i,j] є значенням стовпця j рядка i таблиці
- $statement->fetch() повертає поточний рядок таблиці у вигляді масиву T, де T[j] — це значення стовпця j у рядку
Підготовлений запит має й інші переваги, окрім більшої ефективності. Зокрема, він забезпечує вищий рівень безпеки. Тому його слід використовувати систематично.
<?php
// тест -----------------------------------------------------
// визначення констант
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$TABLE = "impots";
$BASE = "dbimpots";
$USER = "root";
$PWD = "";
$HOTE="localhost";
// дані, необхідні для розрахунку податку, були розміщені в таблиці mysqL $TABLE
//, що належить до бази даних $BASE. Таблиця має таку структуру
// межі decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
// параметри платників податків (сімейний стан, кількість дітей, річний заробіток)
// були розміщені у текстовому файлі $DATA по одному рядку на кожного платника податків
// результати (сімейний стан, кількість дітей, річний дохід, сума податку до сплати) розміщено у
// текстовий файл $RESULTATS, по одному результату на рядок
// створюється об’єкт «Податки»
$I = new Impôts($HOTE, $USER, $PWD, $BASE, $TABLE);
// чи сталася помилка?
$erreur=$I->getErreur();
if ($erreur) {
print "$I->erreur\n";
exit;
}//if
// створюється об’єкт «Утиліти»
$u = new Utilitaires();
// відкриття файлу з даними платників податків
$data = fopen($DATA, "r");
if (!$data) {
print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
exit;
}
// відкриття файлу результатів
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
exit;
}
// обробляється поточний рядок файлу даних платників податків
while ($ligne = fgets($data, 100)) {
// видаляємо можливий маркер кінця рядка
$ligne = $u->cutNewLineChar($ligne);
// витягуються 3 поля «одружений», «діти», «зарплата», що утворюють $ligne
list($marié, $enfants, $salaire) = explode(",", $ligne);
// розраховується податок
$impôt = $I->calculer($marié, $enfants, $salaire);
// записуємо результат
fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
// наступні дані
}
// закриваємо файли
fclose($data);
fclose($résultats);
// кінець
exit;
// ---------------------------------------------------------------------------------
// визначення класу «Податки»
class Impôts {
// атрибути: 3 таблиці даних
private $limites;
private $coeffR;
private $coeffN;
private $erreur;
private $nbLimites;
// геттер
public function getErreur(){
return $this->erreur;
}
// конструктор
function __construct($HOTE, $USER, $PWD, $BASE, $TABLE) {
// ініціалізує атрибути $limites, $coeffR, $coeffN
// дані, необхідні для розрахунку податку, були розміщені в таблиці MySQL $TABLE
//, що належить до бази даних $BASE. Таблиця має таку структуру
// limites decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
// підключення до бази даних MySQL на машині $HOTE здійснюється під ідентифікатором ($USER,$PWD)
// ініціалізує поле $erreur із можливою помилкою
// очищається, якщо помилки немає
//
// підключення до бази даних 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;
}
// читання таблиці $TABLE
$requête = "select limites,coeffR,coeffN from $TABLE";
// виконує запит $requête через з'єднання $connexion
try {
$statement = $connexion->prepare($requête);
$statement->execute();
// обробка результату запиту
while ($colonnes = $statement->fetch()) {
$this->limites[] = $colonnes[0];
$this->coeffR[] = $colonnes[1];
$this->coeffN[] = $colonnes[2];
}
// помилок немає
$this->erreur = "";
// кількість елементів масиву перевищує межі
$this->nbLimites = count($this->limites);
} catch (PDOException $e) {
$this->erreur = $e->getMessage();
}
// відключення
déconnecte($connexion);
}
// --------------------------------------------------------------------------
function calculer($marié, $enfants, $salaire) {
// $marié: так, ні
// $enfants: кількість дітей
// $salaire: річний оклад
// чи об’єкт перебуває у належному стані?
if ($this->erreur)
return -1;
// кількість часток
...
}
}
// ---------------------------------------------------------------------------------
// клас службових функцій
class Utilitaires {
function cutNewLinechar($ligne) {
// видаляється маркер кінця рядка з $ligne, якщо він існує
...
}
}
// ---------------------------------------------------------------------------------
function connecte($dsn, $login, $pwd) {
// підключає ($login, $pwd) до бази $dsn
// повертає ідентифікатор з’єднання та повідомлення про помилку
...
}
//встановлює з'єднання
// ---------------------------------------------------------------------------------
function déconnecte($connexion) {
// закриває з’єднання, ідентифіковане за $connexion
...
}
Результати: такі самі, як і в попередніх версіях.
Коментарі
Нові елементи містяться у рядках 98–109:
- рядок 99: команда SQL select, яка дозволить отримати дані, необхідні для розрахунку податку.
- рядок 102: підготовка запиту SQL select
- рядок 103: виконання підготовленого запиту
- рядки 105–109: построкова обробка таблиці результатів select

