الكوكيز والجلسات
HTTP ينسى كل طلب؛ فكيف تبقى السلة ممتلئة وتبقى مسجّلًا؟ ⏱ نحو 35 دقيقة.
- تشرح لماذا
HTTPعديم الحالة وكيف تحل الكوكيز ذلك. - تنشئ الكوكيز وتقرؤها وتحذفها، وتعرف حدودها الأمنية.
- تستخدم الجلسات لحفظ بيانات المستخدم على الخادم.
- تميّز متى تستخدم الكوكي ومتى الجلسة، وتعرف إعدادات الأمان.
١HTTP بلا ذاكرة
كل طلب HTTP مستقل تمامًا: الخادم لا يتذكر أنك طلبت صفحة قبل ثانية. نقول إن HTTP بروتوكول عديم الحالة Stateless. فكيف يعرف المتجر ما في سلّتك؟ وكيف يبقى المستخدم مسجّلًا دخوله وهو يتنقل بين الصفحات؟
الحل فكرة بسيطة: الخادم يعطي المتصفح «بطاقة» صغيرة، والمتصفح يعيدها مع كل طلب تالٍ. هذه البطاقة اسمها الكوكي Cookie.
جرّب الملف التالي: عدّاد زيارات بسيط. أرسلنا له ثلاثة طلبات متتالية:
<?php$n = (int) ($_COOKIE['visits'] ?? 0) + 1;setcookie('visits', $n, time() + 30 * 24 * 3600); // صالح 30 يومًاecho "<p>هذه زيارتك رقم $n</p>";
افتح السطر الأول: الاستجابة فيها Set-Cookie. ثم افتح الثاني: الطلب صار فيه الترويسة Cookie: visits=1 ، أي أن المتصفح أعاد البطاقة.
٢كيف تعمل الكوكيز؟
- الخادم يرسل في الاستجابة:
Set-Cookie: visits=1; expires=… - المتصفح يحفظها مرتبطة باسم الموقع.
- مع كل طلب تالٍ لنفس الموقع يرسل:
Cookie: visits=1 - PHP يضعها لك في المصفوفة
$_COOKIE.
| ما تكتبه في PHP | معناه |
|---|---|
setcookie('theme', 'dark', time() + 3600); | أنشئ كوكي تنتهي بعد ساعة (3600 ثانية). |
setcookie('theme', 'dark'); | كوكي جلسة: تُحذف عند إغلاق المتصفح. |
$_COOKIE['theme'] ?? 'light' | اقرأها، مع قيمة بديلة إن لم توجد. |
setcookie('theme', '', time() - 3600); | احذفها: تاريخ انتهاء في الماضي. |
٣الجلسات: البيانات على الخادم
بما أن الكوكي غير موثوقة، نحفظ البيانات المهمة على الخادم، ونعطي المتصفح كوكي واحدة فقط فيها رقم عشوائي طويل يدل على بياناته. هذه هي الجلسة Session:
| الكوكي | الجلسة | |
|---|---|---|
| أين البيانات؟ | في متصفح المستخدم | على الخادم (ملفات في مجلد مؤقت) |
| ماذا يرى المستخدم؟ | البيانات نفسها | رقم الجلسة فقط: PHPSESSID=8f2c… |
| هل يستطيع تغييرها؟ | نعم | لا (إلا إن سرق رقم جلسة غيره) |
| مناسبة لـ | تفضيلات غير حساسة: المظهر واللغة | تسجيل الدخول، والسلة، والصلاحيات |
وفي PHP ثلاث خطوات فقط: session_start() في أعلى كل ملف يستخدم الجلسة، ثم اقرأ واكتب في المصفوفة $_SESSION كأي مصفوفة:
<?phpsession_start();$products = ['coffee' => 'قهوة عربية', 'dates' => 'تمر سكري', 'tea' => 'شاي أخضر']; // إضافة إلى السلةif (isset($_GET['add'], $products[$_GET['add']])) { $id = $_GET['add']; $_SESSION['cart'][$id] = ($_SESSION['cart'][$id] ?? 0) + 1;}$cart = $_SESSION['cart'] ?? [];?><h3>المنتجات</h3><?php foreach ($products as $id => $name): ?> <p><?= $name ?> — <a href="shop.php?add=<?= $id ?>">أضف للسلة</a></p><?php endforeach; ?><h3>سلتك (<?= array_sum($cart) ?>)</h3><ul><?php foreach ($cart as $id => $qty): ?> <li><?= $products[$id] ?> × <?= $qty ?></li><?php endforeach; ?></ul><a href="clear.php">إفراغ السلة</a>
<?phpsession_start();unset($_SESSION['cart']);header('Location: shop.php', true, 303);
أول طلب أنشأ الجلسة (Set-Cookie: PHPSESSID). بعده يرسل المتصفح الرقم نفسه، فيجد PHP سلة هذا المستخدم. و clear.php أفرغت السلة ثم حوّلت إلى shop.php.
٤إنهاء الجلسة
<?phpsession_start(); unset($_SESSION['cart']); // احذف مفتاحًا واحدًا $_SESSION = []; // أفرغ كل بيانات الجلسةsession_destroy(); // واحذف ملفها من الخادم (عند تسجيل الخروج)
وستستخدم هذا كله في الدرس 16 لبناء تسجيل الدخول والخروج.
٥أمان الكوكيز والجلسات
رقم الجلسة يساوي «مفتاح الحساب» مؤقتًا: من سرقه دخل باسم صاحبه. لذلك:
| الإعداد | ماذا يفعل؟ |
|---|---|
HttpOnly | تمنع JavaScript من قراءة الكوكي، فلا يسرقها سكربت XSS. |
Secure | لا تُرسل إلا عبر HTTPS المشفّر. |
SameSite=Lax | لا تُرسل مع طلبات تأتي من مواقع أخرى (حماية من هجوم CSRF). |
<?php// قبل session_start: إعدادات آمنة لكوكي الجلسةsession_set_cookie_params([ 'lifetime' => 0, // تنتهي بإغلاق المتصفح 'httponly' => true, 'secure' => true, // على موقع HTTPS فقط 'samesite' => 'Lax',]);session_start(); // وبعد تسجيل الدخول الناجح: رقم جلسة جديدsession_regenerate_id(true);
توقّع وتحقّق
لماذا نحتاج الكوكيز والجلسات؟
HTTP عديم الحالة.أين تُحفظ بيانات $_SESSION؟
أي معلومة مناسبة لكوكي عادية؟
كيف تحذف كوكي؟
الخلاصة
HTTPعديم الحالة؛ الكوكي «بطاقة» يعيدها المتصفح مع كل طلب.setcookie(اسم، قيمة، وقت الانتهاء)ثم $_COOKIEفي الطلبات التالية.- الكوكي يراها المستخدم ويغيّرها؛ لا تضع فيها شيئًا حساسًا.
session_start()أعلى الملف، ثم $_SESSION؛ البيانات على الخادم والمتصفح يحملPHPSESSIDفقط.HttpOnlyوSecureوSameSiteوsession_regenerate_idلحماية الجلسة.
تحدٍّ برمجي: قائمة المفضلة في الجلسة
متوسطاكتب fav.php لقائمة الدورات المفضلة لكل متدرب، تُحفظ في الجلسة.
?add=اسميضيف الدورة إلى المفضلة (بلا تكرار: إن وُجدت لا تُضاف ثانية).?clear=1يفرغ المفضلة.- في كل طلب اطبع العدد بالشكل
<p>المفضلة: 2</p>ثم قائمة<ul>فيها كل دورة في<li>بترتيب الإضافة. - احفظ القائمة في
$_SESSION['favs']، لا في كوكي.
👀 اعرض الاستجابة المطلوبة
GET /fav.php?add=PHPGET /fav.php?add=SQLGET /fav.php?add=PHPGET /fav.phpGET /fav.php?clear=1
- الكود يعمل بلا أخطاء أو تحذيرات
- الخادم أنشأ جلسة (كوكي PHPSESSID)
- بعد إضافتين: المفضلة: 2
- إضافة PHP مرة ثانية لا تكررها
- طلب بلا معاملات يعرض القائمة كما هي بالترتيب
- clear يفرغ القائمة
- تستخدم $_SESSION
- لا تستخدم setcookie
💡 تلميح 1
session_start(); ثم $_SESSION['favs'] = $_SESSION['favs'] ?? [];💡 تلميح 2
!in_array($_GET['add'], $_SESSION['favs'])حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
<?phpsession_start();$_SESSION['favs'] = $_SESSION['favs'] ?? []; if (isset($_GET['clear'])) { $_SESSION['favs'] = [];}if (isset($_GET['add']) && !in_array($_GET['add'], $_SESSION['favs'])) { $_SESSION['favs'][] = $_GET['add'];} echo "<p>المفضلة: " . count($_SESSION['favs']) . "</p>";echo "<ul>";foreach ($_SESSION['favs'] as $f) { echo "<li>" . htmlspecialchars($f) . "</li>";}echo "</ul>";