رتبه موضوع:
  • 0 رای - 0 میانگین
  • 1
  • 2
  • 3
  • 4
  • 5
ذخیره سشن در دیتابیس در PHP7 و بالاتر
#1
قبلاً توی این تاپیک روشی ذخیره‌سازی سشن توی دیتابیس رو در نسخه‌های PHP قبل از 7 یعنی 5 و پایین‌تر توضیح داده بودم اما پیرو توضیحات یکی از دوستان، متوجه شدم که توی PHP7 به بالا یه مقدار روش کار عوض شده و روش قبلی جوابگو نیست و باید بهینه‌سازی و بروزرسانی خاصی انجام بشه. خوب توی این تاپیک قصد دارم این روش رو توضیح بدم.
پاسخ
تشکر شده توسط:
#2
اول از همه بهتره یه کلاس کوچک برای ارتباط با دیتابیس ایجاد کنیم. من ترجیح میدم با PDO این کار رو انجام بدم:
class DB
{
   /** @var PDO $con */
   private static $con = null;
   const DB = 'session_db';
   const HOST = 'localhost';
   const PASS = '';
   const USER = 'root';

   public function __construct()
   {
       throw new Exception('Cannot create an object from this class.');
   }

   public static function connect()
   {
       $dsn = 'mysql:dbname=' . self::DB . ';host=' . self::HOST . ';charset=utf8';
       try {
           self::$con = new PDO($dsn, self::USER, self::PASS);
       } catch (Exception $e) {
           die('Connection failed: ' . $e->getMessage());
       }
       self::execute('SET NAMES 'utf8'');
   }

   public static function execute($query)
   {
       if (!self::$con) {
           self::Connect();
       }
       return self::$con->exec($query);
   }

   public static function arrayQuery($query, $params = null)
   {
       if (!self::$con) {
           self::connect();
       }
       $data = [];
       $statement = self::$con->prepare($query);
       if ($statement->execute($params)) {
           foreach ($statement->fetchAll(PDO::FETCH_OBJ) as $row) {
               $data[] = $row;
           }
       }
       return $data;
   }

   public static function query($query, $params = null)
   {
       if (!self::$con) {
           self::connect();
       }
       $statement = self::$con->prepare($query);
       if ($statement->execute($params)) {
           return $statement->rowCount();
       }
       return -1;
   }
}
پاسخ
تشکر شده توسط:
#3
حالا باید کلاس مدیریت سشن خودمون رو بنویسیم. برای این کار باید کلاس ما حتماً رابط SessionHandlerInterface رو پیاده‌سازی کنه. کد این کلاس رو میگذارم:
class DbSessionHandler implements SessionHandlerInterface
{
   public $sessionTable = 'session_table';
   public $autoCreateSessionTable = true;
   public $expireTime = 1200; // in Seconds

   private function createTable()
   {
       DB::query('START TRANSACTION;');
       DB::query("
           CREATE TABLE `{$this->sessionTable}` (
             `id` char(32) NOT NULL,
             `data` longblob NOT NULL,
             `expire` int(11) NOT NULL
           ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
      ");
       DB::query("ALTER TABLE `{$this->sessionTable}` ADD PRIMARY KEY (`id`);");
       DB::query('COMMIT;');
   }

   private function deleteExpired()
   {
       return DB::query("DELETE FROM `{$this->sessionTable}` WHERE (`expire`<:expire)", [':expire' => time()]);
   }


   public function close()
   {
       return true;
   }

   public function destroy($session_id)
   {
       DB::query("DELETE FROM `{$this->sessionTable}` WHERE (`id`=:id)", [':id' => $session_id]);
       return true;

   }

   public function gc($maxlifetime)
   {
       $this->deleteExpired();
       return true;
   }

   public function open($save_path, $name)
   {
       if ($this->autoCreateSessionTable) {
           if ($this->deleteExpired() < 0) {
               $this->createTable();
           }
       }
       return true;
   }

   public function read($session_id)
   {
       $data = DB::arrayQuery("SELECT `data` FROM `{$this->sessionTable}` WHERE (`id`=:id AND `expire`>=:expire)", [':id' => $session_id, ':expire' => time()]);
       return (count($data) > 0 ? base64_decode($data[0]->data) : '');
   }

   public function write($session_id, $session_data)
   {
       return DB::query("REPLACE INTO `{$this->sessionTable}` VALUES (:id, :data, :expire)", [':id' => $session_id, ':data' => base64_encode($session_data), ':expire' => time() + $this->expireTime]) > 0;
   }
}

همونطور که میبینین، این کد خیلی شبیه کدی هست که قبلاً نوشتیم و نکته‌ی کلیدی قسمت implements SessionHandlerInterface هست و پیاده‌سازی متدهای close و destroy و gc و open و read و write هست.
پاسخ
تشکر شده توسط:
#4
حالا تنها کاری که باقی مونده، استفاده از این کلاس هست. کافیه به تابع session_set_save_handler خود PHP، یه شئ از این کلاسی که ساختین رو پاس بدین و بعد مثل حالت‌های عادی session_start() رو صدا بزنین:
require_once 'DB.php';
require_once 'DbSessionHandler.php';
session_set_save_handler(new DbSessionHandler());
session_start();
$_SESSION['name'] = 'ncis.ir';

با یه نگاه به دیتابیس متوجه میشین که جدول session_table درصورتی که وجود نداشته باشه، ساخته میشه و مقادیر سشن توی این جدول ثبت میشن. واضحه که اسامی جدول و دیتابیس و مدت‌زمان اعتبار هر متغیر سشن رو میتونین براساس نیازتون تغییر بدین. ازطرفی من متدهای اضافه که توی تاپیک قبلی بود و برای کارهای دیگه مثل آمار کاربران فعال و... نوشته بودیم رو حذف کردم و درصورت تمایل خودتون میتونین دوباره اونها رو اضافه کنین.
پاسخ
تشکر شده توسط:




کاربران در حال بازدید این موضوع: 1 مهمان