تالار گفتمان nCIS.ir

نسخه‌ی کامل: ذخیره سشن در دیتابیس در PHP7 و بالاتر
شما در حال مشاهده نسخه آرشیو هستید. برای مشاهده نسخه کامل کلیک کنید.
قبلاً توی این تاپیک روشی ذخیره‌سازی سشن توی دیتابیس رو در نسخه‌های PHP قبل از 7 یعنی 5 و پایین‌تر توضیح داده بودم اما پیرو توضیحات یکی از دوستان، متوجه شدم که توی PHP7 به بالا یه مقدار روش کار عوض شده و روش قبلی جوابگو نیست و باید بهینه‌سازی و بروزرسانی خاصی انجام بشه. خوب توی این تاپیک قصد دارم این روش رو توضیح بدم.
اول از همه بهتره یه کلاس کوچک برای ارتباط با دیتابیس ایجاد کنیم. من ترجیح میدم با 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;
   }
}
حالا باید کلاس مدیریت سشن خودمون رو بنویسیم. برای این کار باید کلاس ما حتماً رابط 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 هست.
حالا تنها کاری که باقی مونده، استفاده از این کلاس هست. کافیه به تابع 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 درصورتی که وجود نداشته باشه، ساخته میشه و مقادیر سشن توی این جدول ثبت میشن. واضحه که اسامی جدول و دیتابیس و مدت‌زمان اعتبار هر متغیر سشن رو میتونین براساس نیازتون تغییر بدین. ازطرفی من متدهای اضافه که توی تاپیک قبلی بود و برای کارهای دیگه مثل آمار کاربران فعال و... نوشته بودیم رو حذف کردم و درصورت تمایل خودتون میتونین دوباره اونها رو اضافه کنین.