أساسيات PHP

الجلسات والكوكيز

13 دقيقة الدرس 20 من 45

الجلسات والكوكيز

الجلسات والكوكيز ضرورية للحفاظ على الحالة وبيانات المستخدم عبر طلبات صفحات متعددة. تتيح ميزات مثل أنظمة تسجيل الدخول وعربات التسوق وتفضيلات المستخدم والمزيد.

ما هي الجلسات؟

تسمح الجلسات بتخزين بيانات المستخدم على الخادم طوال مدة زيارة المستخدم. يحصل كل مستخدم على معرف جلسة فريد مخزن في كوكي.

الفرق الرئيسي:
  • الجلسات: البيانات مخزنة على الخادم، أكثر أمانًا، تنتهي عند إغلاق المتصفح
  • الكوكيز: البيانات مخزنة في المتصفح، أقل أمانًا، يمكن أن تستمر لفترة أطول

العمل مع الجلسات

بدء الجلسة

<?php // ابدأ الجلسة دائمًا في أعلى الملف، قبل أي إخراج session_start(); // الآن يمكنك استخدام $_SESSION $_SESSION['username'] = 'John'; $_SESSION['user_id'] = 123; $_SESSION['role'] = 'admin'; echo "بدأت الجلسة!"; ?>
مهم: استدعِ session_start() قبل أي إخراج (HTML، echo، إلخ). وإلا ستحصل على خطأ "تم إرسال الرؤوس بالفعل".

قراءة بيانات الجلسة

<?php session_start(); // التحقق من وجود متغير الجلسة if (isset($_SESSION['username'])) { echo "مرحبًا بعودتك، " . $_SESSION['username']; } else { echo "يرجى تسجيل الدخول"; } // الحصول على متغير الجلسة مع قيمة افتراضية $role = $_SESSION['role'] ?? 'guest'; echo "دورك: $role"; ?>

تدمير الجلسات

<?php session_start(); // إزالة متغير جلسة محدد unset($_SESSION['username']); // إزالة جميع متغيرات الجلسة session_unset(); // تدمير الجلسة بالكامل session_destroy(); echo "تم تسجيل خروجك"; ?>

مثال نظام تسجيل دخول كامل

<?php // login.php session_start(); $error = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $username = trim($_POST['username']); $password = $_POST['password']; // في التطبيق الحقيقي، تحقق من قاعدة البيانات // هذا للعرض التوضيحي فقط if ($username === 'admin' && $password === 'password123') { // تعيين متغيرات الجلسة $_SESSION['user_id'] = 1; $_SESSION['username'] = $username; $_SESSION['role'] = 'admin'; $_SESSION['logged_in'] = true; $_SESSION['login_time'] = time(); // إعادة التوجيه إلى لوحة التحكم header('Location: dashboard.php'); exit; } else { $error = "اسم مستخدم أو كلمة مرور غير صحيحة"; } } ?> <!DOCTYPE html> <html> <head> <title>تسجيل الدخول</title> <style> .error { color: red; } .form-group { margin-bottom: 15px; } </style> </head> <body> <h1>تسجيل الدخول</h1> <?php if ($error): ?> <div class="error"><?php echo $error; ?></div> <?php endif; ?> <form method="post"> <div class="form-group"> <label for="username">اسم المستخدم:</label> <input type="text" id="username" name="username" required> </div> <div class="form-group"> <label for="password">كلمة المرور:</label> <input type="password" id="password" name="password" required> </div> <button type="submit">تسجيل الدخول</button> </form> </body> </html>
<?php // dashboard.php session_start(); // التحقق من تسجيل دخول المستخدم if (!isset($_SESSION['logged_in']) || !$_SESSION['logged_in']) { header('Location: login.php'); exit; } $username = $_SESSION['username']; $role = $_SESSION['role']; $login_time = date('Y-m-d H:i:s', $_SESSION['login_time']); ?> <!DOCTYPE html> <html> <head> <title>لوحة التحكم</title> </head> <body> <h1>لوحة التحكم</h1> <p>مرحبًا، <?php echo htmlspecialchars($username); ?>!</p> <p>الدور: <?php echo htmlspecialchars($role); ?></p> <p>تم تسجيل الدخول في: <?php echo $login_time; ?></p> <a href="logout.php">تسجيل الخروج</a> </body> </html>
<?php // logout.php session_start(); // مسح بيانات الجلسة $_SESSION = []; // تدمير كوكي الجلسة if (isset($_COOKIE[session_name()])) { setcookie(session_name(), '', time() - 3600, '/'); } // تدمير الجلسة session_destroy(); // إعادة التوجيه لتسجيل الدخول header('Location: login.php'); exit; ?>

أمان الجلسات

<?php session_start(); // إعادة إنشاء معرف الجلسة لمنع تثبيت الجلسة session_regenerate_id(true); // تعيين مهلة الجلسة (30 دقيقة) $timeout = 1800; // ثواني if (isset($_SESSION['last_activity']) && (time() - $_SESSION['last_activity']) > $timeout) { session_unset(); session_destroy(); header('Location: login.php?timeout=1'); exit; } $_SESSION['last_activity'] = time(); // تخزين IP المستخدم لمنع اختطاف الجلسة if (!isset($_SESSION['user_ip'])) { $_SESSION['user_ip'] = $_SERVER['REMOTE_ADDR']; } else { if ($_SESSION['user_ip'] !== $_SERVER['REMOTE_ADDR']) { session_unset(); session_destroy(); die('تم الكشف عن اختطاف الجلسة'); } } ?>

العمل مع الكوكيز

تعيين الكوكيز

<?php // كوكي أساسي (ينتهي خلال ساعة) setcookie('username', 'John', time() + 3600); // كوكي مع مسار ونطاق setcookie('theme', 'dark', time() + (86400 * 30), '/'); // 30 يومًا // كوكي آمن (HTTPS فقط) setcookie('token', 'abc123', time() + 3600, '/', '', true, true); // المعاملات: الاسم، القيمة، الانتهاء، المسار، النطاق، آمن، httponly // كوكي ينتهي عند إغلاق المتصفح setcookie('temp_data', 'value', 0); echo "تم تعيين الكوكيز!"; ?>
معاملات الكوكي:
  • name: اسم الكوكي
  • value: قيمة الكوكي
  • expire: طابع زمني للانتهاء (0 = كوكي الجلسة)
  • path: المسار حيث الكوكي متاح ('/' = النطاق بأكمله)
  • domain: النطاق حيث الكوكي متاح
  • secure: الإرسال عبر HTTPS فقط
  • httponly: غير قابل للوصول عبر JavaScript (حماية XSS)

قراءة الكوكيز

<?php // التحقق من وجود الكوكي if (isset($_COOKIE['username'])) { echo "مرحبًا بعودتك، " . $_COOKIE['username']; } else { echo "زائر لأول مرة"; } // الحصول على كوكي مع قيمة افتراضية $theme = $_COOKIE['theme'] ?? 'light'; // عرض جميع الكوكيز echo '<pre>'; print_r($_COOKIE); echo '</pre>'; ?>

حذف الكوكيز

<?php // حذف الكوكي بتعيين انتهاء في الماضي setcookie('username', '', time() - 3600); // أو استخدم 1 كانتهاء setcookie('theme', '', 1); echo "تم حذف الكوكيز"; ?>

وظيفة تذكرني

<?php // login.php مع "تذكرني" session_start(); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $username = $_POST['username']; $password = $_POST['password']; $remember = isset($_POST['remember']); // التحقق من بيانات الاعتماد (مبسط) if ($username === 'admin' && $password === 'password123') { // تعيين الجلسة $_SESSION['user_id'] = 1; $_SESSION['username'] = $username; // إذا تم تحديد "تذكرني" if ($remember) { // إنشاء رمز آمن $token = bin2hex(random_bytes(32)); // تخزين الرمز في قاعدة البيانات مع user_id // $db->query("INSERT INTO remember_tokens ..."); // تعيين كوكي مع الرمز (30 يومًا) setcookie('remember_token', $token, time() + (86400 * 30), '/', '', true, true); } header('Location: dashboard.php'); exit; } } ?> <form method="post"> <input type="text" name="username" required> <input type="password" name="password" required> <label> <input type="checkbox" name="remember" value="1"> تذكرني </label> <button type="submit">تسجيل الدخول</button> </form>
<?php // فحص تسجيل الدخول التلقائي (أعلى كل صفحة محمية) session_start(); if (!isset($_SESSION['user_id']) && isset($_COOKIE['remember_token'])) { $token = $_COOKIE['remember_token']; // فحص الرمز في قاعدة البيانات // $user = $db->query("SELECT user_id FROM remember_tokens WHERE token = ?"); // إذا كان صالحًا، سجل دخول المستخدم // $_SESSION['user_id'] = $user['user_id']; } ?>

مثال عربة التسوق

<?php // add_to_cart.php session_start(); // تهيئة العربة إذا لم تكن موجودة if (!isset($_SESSION['cart'])) { $_SESSION['cart'] = []; } // إضافة عنصر إلى العربة if (isset($_POST['product_id'])) { $product_id = intval($_POST['product_id']); $quantity = intval($_POST['quantity']) ?: 1; // إذا كان المنتج موجودًا بالفعل في العربة، زد الكمية if (isset($_SESSION['cart'][$product_id])) { $_SESSION['cart'][$product_id] += $quantity; } else { $_SESSION['cart'][$product_id] = $quantity; } echo "تمت الإضافة إلى العربة!"; } ?>
<?php // view_cart.php session_start(); $cart = $_SESSION['cart'] ?? []; if (empty($cart)) { echo "عربتك فارغة"; } else { echo "<h2>عربتك</h2>"; echo "<table>"; echo "<tr><th>معرف المنتج</th><th>الكمية</th><th>الإجراء</th></tr>"; foreach ($cart as $product_id => $quantity) { echo "<tr>"; echo "<td>$product_id</td>"; echo "<td>$quantity</td>"; echo "<td><a href='remove_from_cart.php?id=$product_id'>إزالة</a></td>"; echo "</tr>"; } echo "</table>"; echo "<p>إجمالي العناصر: " . array_sum($cart) . "</p>"; } ?>
<?php // remove_from_cart.php session_start(); if (isset($_GET['id'])) { $product_id = intval($_GET['id']); unset($_SESSION['cart'][$product_id]); } header('Location: view_cart.php'); exit; ?>

تكوين الجلسة (php.ini)

; إعدادات الجلسة المهمة في php.ini session.cookie_httponly = 1 ; منع وصول JavaScript session.cookie_secure = 1 ; HTTPS فقط session.use_strict_mode = 1 ; رفض معرفات الجلسة غير المهيأة session.cookie_samesite = Strict ; حماية CSRF session.gc_maxlifetime = 1800 ; عمر الجلسة (30 دقيقة) session.cookie_lifetime = 0 ; ينتهي الكوكي عند إغلاق المتصفح

مقارنة الجلسات مقابل الكوكيز

الميزة الجلسات الكوكيز
موقع التخزين الخادم العميل (المتصفح)
الأمان أكثر أمانًا أقل أمانًا (يمكن تعديله)
حد الحجم يعتمد على الخادم (عادة كبير) 4 كيلوبايت لكل كوكي
الانتهاء إغلاق المتصفح أو مهلة يحدده المطور (أيام، شهور، سنوات)
أنواع البيانات أي نوع بيانات PHP نصوص فقط
الأفضل لـ البيانات الحساسة، حالة تسجيل الدخول التفضيلات، التتبع، تذكرني

أفضل الممارسات

أفضل ممارسات الأمان:
  • استخدم دائمًا session_regenerate_id() بعد تسجيل الدخول
  • عيّن علامة httponly على الكوكيز
  • استخدم HTTPS وعيّن علامة secure
  • نفذ مهلة الجلسة
  • لا تخزن أبدًا بيانات حساسة في الكوكيز
  • تحقق من بيانات الجلسة في كل طلب
  • تحقق من اختطاف الجلسة
  • استخدم رموز CSRF للنماذج
  • دمر الجلسات عند تسجيل الخروج
  • عيّن جمع نفايات الجلسة المناسب

تمرين تطبيقي

المهمة: أنشئ نظام مصادقة مستخدم كامل مع:

  1. صفحة تسجيل دخول مع اسم مستخدم/كلمة مرور
  2. صفحة تسجيل
  3. صفحة لوحة تحكم محمية
  4. وظيفة تسجيل الخروج
  5. مربع اختيار "تذكرني" (كوكي 30 يومًا)
  6. مهلة الجلسة بعد 15 دقيقة من عدم النشاط
  7. عرض وقت تسجيل الدخول في لوحة التحكم
  8. صفحة تفضيلات المستخدم (تخزين تفضيل السمة في كوكي)

متطلبات الأمان:

  • إعادة إنشاء معرف الجلسة عند تسجيل الدخول
  • تشفير كلمات المرور (استخدم password_hash())
  • الحماية من اختطاف الجلسة
  • استخدم كوكيز آمنة و httponly
  • إعادة توجيه المستخدمين غير المسجلين إلى صفحة تسجيل الدخول

الملخص

في هذا الدرس، تعلمت:

  • ما هي الجلسات والكوكيز ومتى تستخدم كل منها
  • بدء وإدارة الجلسات باستخدام session_start()
  • تخزين واسترداد بيانات الجلسة
  • تدمير الجلسات بشكل صحيح
  • إنشاء نظام تسجيل دخول/خروج كامل
  • أمان الجلسات (المهلة، إعادة الإنشاء، منع الاختطاف)
  • تعيين وقراءة وحذف الكوكيز
  • تطبيق وظيفة "تذكرني"
  • بناء عربة تسوق باستخدام الجلسات
  • مقارنة الجلسات مقابل الكوكيز
  • أفضل ممارسات الأمان

تهانينا! لقد أكملت الوحدة 4: المتغيرات العمومية الفائقة والنماذج. لديك الآن المهارات لبناء تطبيقات PHP تفاعلية وذات حالة مع النماذج ورفع الملفات ومصادقة المستخدم!