Skip to content

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) {
  // سه آرایه عددی $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 اجرا می‌کند
  //یک آرایهٔ ۲ عنصری را بازمی‌گرداند ($erreur, $résultat)
 ...
}

خروجی صفحه:

Transfert opéré

8.2. برنامه محاسبه مالیات ( impots_04)

این نسخه از کلاس Impôts استفاده می‌کند که مقادیر مورد نیاز برای محاسبه مالیات را از پایگاه داده بازیابی می‌کند. در اینجا مفهومی جدید معرفی می‌کنیم: پرس‌وجوی آماده‌شده. اجرای یک دستور SQL توسط یک دستور SGBD در دو مرحله انجام می‌شود:

  1. پرس‌وجو آماده می‌شود: فرآیند SGBD یک طرح اجرایی بهینه‌شده برای پرس‌وجو آماده می‌کند. هدف این است که آن را با کارایی هرچه بیشتر اجرا کند.
  1. پرس‌وجو اجرا می‌شود.

اگر همان پرس‌وجو 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;
}//اگر
//یک شیء امکانات ایجاد می‌شود
$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);
  //بازیابی سه فیلد «married»، «children» و «salary» که $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 {

  //ویژگی‌ها: ۳ جدول داده
  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 است. جدول دارای ساختار زیر است
    //limits 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 = "";
      //تعداد عناصر در آرایه limits
      $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 را می‌بندد
  ...
}

نتایج: مشابه نسخه‌های قبلی.

توضیحات

عناصر جدید در خطوط ۹۸–۱۰۹ قرار دارند:

  • خط 99: دستور SQL select، که داده‌های مورد نیاز برای محاسبه مالیات را بازیابی می‌کند.
  • خط ۱۰۲: آماده‌سازی فرمان SQL select
  • خط ۱۰۳: اجرای فرمان آماده‌شده
  • خطوط ۱۰۵–۱۰۹: پردازش سطر به سطر جدول نتایج از select