ในบทเรียนรู้นี้เป็นการแก้ปัญหาโดยให้สมาชิก Login เพียงแค่เครื่องเดียว ที่ Login ใช้งานล่าสุด ตัวที่ Login ค้างไว้ให้ Logout แบบ Auto ซึ่งนั่นเราจะต้องจัดการกับ Session ที่เข้าใช้งานเว็บไซต์ให้ได้นั่นเอง

โดยทั่วไปแล้ว Session จะเกิดที่ Browser ฝั่ง Client และจะถูกทำลายไปเมื่อปิด Browser ฉะนั้นการจัดการกับ Session แบบรวมศูนย์กลาง เอามาเก็บไว้ใน Database ก็น่าจะบริหารจัดการผู้ใช้งานได้

ที่นี้ถ้าคนเข้าเว็บไซต์เยอะๆ ล่ะทำไง โดยการเก็บครั้งนี้เก็บหมด ซึ่งไม่ว่าจะ login หรือไม่ (guest) ทางออกคือกำหนดให้ Session มีวันหมดอายุ

ฉนั้นเราจะปิด function การจำการเข้าระบบไว้ออกซะ (Remember Me)

สร้างตารางเก็บ Session

สร้างตารางเก็บ Session โดยจะเพิ่ม user_id เป็นตัวเก็บการ Login หากผู้ใช้งานเข้าเว็บไซต์ (guest) แล้ว login เข้าระบบ

CREATE TABLE `session` (
  `id` char(40) COLLATE utf8_unicode_ci NOT NULL,
  `expire` int(11) DEFAULT NULL,
  `data` blob,
  `user_id` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

จากนั้น Generate Model เก็บไว้ใน common/models/Session.php

แก้ไขไฟล์ config

ทำการแก้ไข ไฟล์ frontend/config/main.php โดยการเพิ่มส่วน session ให้ไปใช้งาน Db ในส่วน components ของการตั้งค่า

'components' => [
//...
        'session' => [
            'name' => 'APPFRONTEND',
            'class' => 'yii\web\DbSession',
            'sessionTable' => 'session',
            'timeout' => 60 * 60 * 24,// มีอายุ 24 ชั่วโมง
            'writeCallback' => function ($session) {
                Yii::$app->session->gcSession(60 * 60 * 24); //เก็บ garbage collection ทุกๆ 24 ชั่วโมง
                return [
                    'user_id' => Yii::$app->user->id
                ];
            }
        ],
//...
],

ปัญหาคือเมื่อมีผู้ใช้งานที่เป็น guest เยอะๆ จะมีการบันทึกใน database เยอะมาก ซึ่งจะเกิด garbage session เกิดขึ้น ดังนั้นเมื่อเรากำหนดให้ session มีอายุ 24 ชั่วโมง ก็จะทำการลบ session ที่ไม่ได้ใช้ออกใน 24 ชั่วโมงเช่นกัน

สำหรับการ callback นั้นหากมีการ login เข้าระบบให้เครียร์ garbage session ออกและให้ส่ง user_id กลับไปบันทึกที่ attribute user_id เพื่อระบุว่า user_id ไหนใช้ session นี้

ทำการลบ Session เก่าที่เคย login ไว้

แก้ไข frontend/controllers/SiteController.php

ในส่วน actionLogin() อย่าลืม use common\models\Session;

public function actionLogin()
    {
        if (!Yii::$app->user->isGuest) {
            return $this->goHome();
        }

        $model = new LoginForm();
        if ($model->load(Yii::$app->request->post()) && $model->login()) {

            Session::deleteAll(['and', 'user_id = '.Yii::$app->user->getId(), "id != '".Yii::$app->session->id."'"]);
//...

ทดลองเปิด 2 browser (Chrome/Firefox) จากนั้นลอง login ใน Chrome แล้วใช้งานปกติ จากนั้นไป login ใน Firefox แล้วกลับมา Refresh ใน Chrome จะเห็นว่ามีการ Logout แล้ว

มานพ กองอุ่น

มานพ กองอุ่น : Developer

ความคิดเห็น

หากบทเรียนรู้มีความผิดพลาดประการใด หรือมีข้อเสนอแนะกรุณาแจ้ง contact@programmerthailand.com