الجلسات HTTP في Laravel

من موسوعة حسوب

مقدّمة

توفر الجلسات طريقة لتخزين المعلومات حول المستخدم على عدّة طلبات نظرًا لأن التطبيقات المُعتمدة على HTTP بدون حالة. يأتي Laravel مع مجموعة متنوعة من الخلفيّات (backends) التي يمكن الوصول إليها عبر واجهة برمجية API تعبيرية موحّدة. كما يتضمّن دعم خلفيات شائعة مثل Memcached وRedis وقواعد البيانات خارج الأطر المألوفة.

الضبط

يُخزّن ملف إعدادات الجلسة في config/session.php. تأكد من مراجعة خياراتك المتاحة في هذا الملف. Laravel مُعد افتراضيًّا لاستخدام برنامج تشغيل (driver) الجلسة file الذي يعمل جيّدًا في العديد من التطبيقات. قد تفكر في تطبيقات الإنتاج في استخدام برامج التشغيل Memcached أو Redis للحصول على أداء جلسة أسرع. يُعرّف خيار إعداد الجلسة driver مكان تخزين بيانات الجلسة لكل طلب. يأتي Laravel مع عدّة برامج تشغيل ممتازة خارج الأطر المألوفة:

  • file - تُخزّن الجلسات في storage/framework/sessions .
  • cookie - تُخزّن الجلسات في ملفات تعريف الارتباط آمنة ومشفّرة.
  • database - تُخزّن الجلسات في قاعدة بيانات علائقية.
  • memcached / redis - تُخزّن الجلسات في إحدى هذه المخازن السريعة القائمة على ذاكرة التخزين المؤقت.
  • array - تُخزّن الجلسات في مصفوفة PHP ولن تستمر.

يُستخدم برنامج تشغيل المصفوفة أثناء الاختبار ويمنع استمرار تخزين البيانات المخزّنة في الجلسة.

متطلبات المُشغّل

قاعدة البيانات

ستحتاج لإنشاء جدول لاحتواء عناصر الجلسة عند استخدام برنامج تشغيل قاعدة بيانات الجلسة. في ما يلي مثال عن تصريح Schema للجدول:

Schema::create('sessions', function ($table) {
    $table->string('id')->unique();
    $table->unsignedInteger('user_id')->nullable();
    $table->string('ip_address', 45)->nullable();
    $table->text('user_agent')->nullable();
    $table->text('payload');
    $table->integer('last_activity');
});

تستطيع استخدام الأمر session:table Artisan لتوليد هذا التهجير (migration):

php artisan session:table

php artisan migrate

Redis

ستحتاج إلى تثبيت الحزمة predis/predis ‏(~ 1.0) عبر  Composer قبل استخدام جلسات Redis مع Laravel. تستطيع إعداد اتصالات Redis في ملف الإعداد database. يمكن استخدام الخيار connection لتحديد أي اتصال Redis تستخدمه الجلسة في ملف الإعداد session.

استخدام الجلسة

استرداد البيانات

توجد طريقتان أساسيّتان للعمل ببيانات الجلسات في Laravel: عبر المساعد session العام وعبر نسخة Request . فلنلقي نظرة أولًا على الوصول للجلسة عبر نسخة Request والتي يمكن التلميح على نوعها على تابع وحدة التحكّم. تذكر أنّ اعتماديّات تابع وحدة التحكّم تُضاف تلقائيًا عبر حاوي خدمات Laravel:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * عرض ملف  المستخدم المحدّد الشخصي .
     *
     * @param  Request  $request
     * @param  int  $id
     * @return Response
     */
    public function show(Request $request, $id)
    {
        $value = $request->session()->get('key');

        //
    }
}

تستطيع عندما تسترد عنصرًا من الجلسة تمرير قيمة افتراضية كالمتغيّر الوسيط الثاني للتابع get. ستُرد هذه القيمة الافتراضية إن لم يوجد المفتاح المحدّد في الجلسة. إن مرّرت Closure كقيمة افتراضية للتابع get ولم يُعثر على المفتاح المطلوب سيُنفّذ Closure وترد نتيجته:

$value = $request->session()->get('key', 'default');

$value = $request->session()->get('key', function () {
    return 'default';
});

مساعد الجلسة العام

تستطيع أيضًا استخدام الدالّة العامّة session لاسترداد البيانات وتخزينها في الجلسة. سيرد المساعد session، عند مناداته بمتغيّر سلسلة نصيّة وسيط واحد، قيمة مفتاح تلك جلسة. عند مناداة المساعد مع مصفوفة من أزواج المفاتيح / القيم ستُخزّن تلك القيم في الجلسة:

Route::get('home', function () {
    // جلب قطعة بيانات من الجلسة...
    $value = session('key');

    //تحديد قيمة افتراضيّة...
    $value = session('key', 'default');

    // تخزين جزء البيانات في الجلسة...
    session(['key' => 'value']);
});

ملاحظة: بالكاد يوجد أي اختلاف عملي بين استخدام الجلسة عبر نسخة طلب HTTP مقابل استخدام المساعد العام session. كلتا الطريقتين قابلتان للاختبار عبر التابع assertSessionHas المتوفر في جميع حالات اختبارك.

استرداد جميع بيانات الجلسة

إن رغبت في استرداد جميع بيانات الجلسة تستطيع استخدام التابع all:

$data = $request->session()->all();

تحديد وجود عنصر في الجلسة

تستطيع استخدام التابع has لتحديد وجود عنصر في الجلسة. يرد التابع has القيمة true إن وجد العنصر ولم يكن فارغًا (null):

if ($request->session()->has('users')) {
    //
}

تستطيع استخدام التابع exists للتأكد من وجود العنصر في الجلسة حتى إن كانت قيمته null. يعيد التابع exists القيمة true إذا كان العنصر موجودًا:

if ($request->session()->exists('users')) {
   //
}

تخزين البيانات

ستستخدم عادةً التابع put أو المساعد session لتخزين البيانات في الجلسة:

// عبر نسخة طلب...
$request->session()->put('key', 'value');

//عبر مساعد عام...
session(['key' => 'value']);

إضافة العناصر إلى مصفوفة الجلسة (Pushing To Array Session Values)

يمكن استخدام التابع push لدفع قيمة جديدة على قيمة جلسة مصفوفة. إن احتوى المفتاح user.teams مثلًا مصفوفة من أسماء الفرق تستطيع دفع قيمة جديدة لداخل المصفوفة كما يلي:

$request->session()->push('user.teams', 'developers');

استرداد وحذف عنصر

سيستردَ التابع pull ويحذف العنصر من الجلسة بسطر برمجي واحد:

$value = $request->session()->pull('key', 'default');

تمويض البيانات (Flash Data)

قد ترغب أحيانًا في تخزين العناصر في الجلسة لكن للطلب التالي فقط. يمكنك ذلك باستخدام التابع flash . ستُتاح البيانات المخزنة في الجلسة باستخدام هذا التابع فقط أثناء الطلب HTTP التالي وتُحذف بعد ذلك. تفيدنا بيانات Flash بصفة عامّة برسائل الحالة قصيرة الأمد:

$request->session()->flash('status', 'Task was successful!');

إن احتجت للاحتفاظ ببياناتك المموّضة (Flash) لعدة طلبات، تستطيع استخدام التابع reflash الذي سيحتفظ بجميع بيانات Flash لطلب إضافي. إذا احتجت فقط للاحتفاظ ببيانات Flash محددة، تستطيع استخدام التابع keep:

$request->session()->reflash();

$request->session()->keep(['username', 'email']);

حذف البيانات

سيحذف التابع forget جزءًا من البيانات من الجلسة. تستطيع استخدام التابع flush إن رغبت في إزالة جميع البيانات من الجلسة:

$request->session()->forget('key');

$request->session()->flush();

تجديد مُعرّف الجلسة (Regenerating The Session ID)

غالبًا ما يُجدّد مُعرّف الجلسة لمنع المستخدمين الخبثاء من استغلال هجوم تثبيت جلسة (session fixation) ضد تطبيقك.

يعيد Laravel إنشاء معرّف الجلسة تلقائيًا أثناء الاستيثاق (authentication) إن كنت تستخدم LoginController؛ ولكن إن احتجت لإعادة إنشاء معرّف الجلسة يدويًا تستطيع استخدام التابع regenerate.

$request->session()->regenerate();

إضافة برامج تشغيل جلسة مخصّصة

تعريف استخدام برنامج تشغيل

يجب أن يُعرّف برنامج تشغيل جلستك المخصّص استخدام SessionHandlerInterface . تحتوي هذه الواجهة على بعض التوابع البسيطة التي نحتاج لتعريف استخدامها. تبدو بذرة تطبيق MongoDB هكذا:

<?php

namespace App\Extensions;

class MongoSessionHandler implements \SessionHandlerInterface
{
    public function open($savePath, $sessionName) {}
    public function close() {}
    public function read($sessionId) {}
    public function write($sessionId, $data) {}
    public function destroy($sessionId) {}
    public function gc($lifetime) {}
}

ملاحظة: لا يأتي Laravel مصحوبًا بمجلّد يحتوي على إضافاتك. أنت حر في وضعها في أي مكان تريده. أنشأنا في هذا المثال مجلّد Extensions لإيواء MongoSessionHandler.

بما أنّ الغرض من هذه التوابع ليس بديهيَّ الفهم، دعنا نغطي بسرعة ما يفعله كل تابع منها:

  • عادةً ما يُستخدم التابع open في أنظمة تخزين الجلسات القائمة على الملفات. لن تحتاج أبدًا تقريبًا لوضع أي شيء في هذا التابع نظرًا لأن Laravel يُشحن مع برنامج تشغيل جلسة file. تستطيع تركها كبذرة فارغة. في الواقع اشتراط تعريف استخدام هذا التابع نابع من ضعف تصميم واجهة PHP (الذي سنناقشه لاحقًا)
  • يمكن عادةً تجاهل التابع close مثل التابع open. فلا حاجة إليه بالنسبة لمعظم برامج التشغيل.
  • يجب أن يرد التابع read نسخة السلسلة نصيّة لبيانات الجلسة المرتبطة بالمتغيّر ‎$sessionId. لا داعي لأي سَلسَلة (serialization) أو ترميز (encoding) عند استرداد أو تخزين بيانات الجلسات في برنامج تشغيلك بما أنّ Laravel سيهتّم بالسلسلة مكانك.
  • يجب أن يكتب التابع write السلسلة النصيّة ‎$data المحدّدة المرتبطة بـالمتغيّر ‎$sessionId بنظام تخزين مستمر (persistent storage) مثل MongoDB  أو Dynamo إلخ. للتذكير مجددًّا لا ينبغي أن تُسلسل أي شيء - بما أن Laravel يهتم بذلك بدلًا منك.
  • يجب أن يحذف التابع destroy البيانات المرتبطة بـالمتغيّر ‎$sessionId من التخزين الدائم.
  • يجب أن يدمّر التابع gc كافة بيانات الجلسة الأقدم من المدّة ‎$lifetime المحدّدة وهي طابع زمني UNIX. بالنسبة للأنظمة التي تُنهي صلاحيتها (self-expiring) مثل Memcached و Redis ، يمكن ترك هذا التابع فارغًا.

تسجيل برنامج التشغيل

تستطيع تسجيل  برنامج تشغيلك في إطار العمل بمجرد تعريف استخدامه. لإضافة برامج تشغيل أخرى لخلفيّة جلسة Laravel، تستطيع استخدام التابع extend على الواجهة الساكنة Session. عليك بمناداة التابع extend من تابع موفّر الخدمات boot. تستطيع فعل بذلك من AppServiceProvider الموجود أو إنشاء موفّر خدمات جديد:

<?php

namespace App\Providers;

use App\Extensions\MongoSessionHandler;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\ServiceProvider;

class SessionServiceProvider extends ServiceProvider
{
    /**
     * إجراء تمهيد الخدمات ما بعد التسجيل.
     *
     * @return void
     */
    public function boot()
    {
        Session::extend('mongo', function ($app) {
            // Return implementation of SessionHandlerInterface...
            return new MongoSessionHandler;
        });
    }

    /**
     * تسجيل الارتباطات في موفّر الخدمات.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

تستطيع استخدام برنامج التشغيل mongo بملف إعدادك config/session.php بمجرد تسجيل برنامج تشغيل الجلسة.

مصادر