שתי מחלקות קטנות עוטפות את מה שמקובל לעשות בכל בקשה: COOKIES קובעת וקוראת עוגיות עם ברירות מחדל קבועות של הליבה, ו-SESSION מאפשרת לשמור ערכים בסשן של PHP בלי להחזיק את קובץ הסשן נעול. בעמוד הזה: ההתנהגות המדויקת של כל מתודה, העוגיות שהליבה עצמה קובעת, הגדרות שאפשר לשנות, ומה לא לעשות.
system/ בעמוד הזה הוא תיקיית הליבה הפרוסה (api/core בריפו), ו-{admin} הוא CONFIG::$admin_url. המחלקות נמצאות ב-system/collections/COOKIES.php וב-system/collections/SESSION.php; טבלת מתודות מקוצרת יש גם ברפרנס עוגיות, סשן ולוגין.
COOKIES#
set#
COOKIES::set($name, $value, $hours = 0, $base_domain = true)
קובעת עוגייה בשם CRM_<name> ומעדכנת גם את $_COOKIE באותה בקשה, כך שקריאה מיידית מחזירה את הערך החדש. החזרה: תוצאת setcookie (false כשכבר נשלחו כותרות).
| דגל | ערך |
|---|---|
expires | $hours <= 0: עוגיית סשן (נעלמת בסגירת הדפדפן). אחרת time() + $hours * 3600 |
path | / |
domain | .<base_domain>: העוגייה תקפה גם בתת-דומיינים |
secure | true: נשלחת רק ב-HTTPS |
httponly | false: JavaScript יכול לקרוא אותה |
samesite | הערך של COOKIES::$samesite (ברירת מחדל None) |
COOKIES::set("lang_pref", "he", 24 * 365); // שנה
COOKIES::set("visited", "1"); // עוגיית סשן
set לא מגדירה HttpOnly, ולכן סקריפט שרץ בדף (XSS, או ספרייה חיצונית) קורא את הערך. עוגיות שמזהות משתמש או מחזיקות טוקן אימות קובעים עם set_secure. בנוסף secure = true תמיד: באתר שמוגש ב-HTTP בלבד העוגייה לא תישמר.set_secure#
COOKIES::set_secure($name, $value, $hours = 0, $base_domain = true)
כמו set אבל עם httponly = true ו-samesite = "Lax" קבוע (לא תלוי ב-COOKIES::$samesite). זו העוגייה הנכונה לטוקן סשן. הליבה משתמשת בה עבור admin_session ו-admin_csrf.
base_domain: דומיין הבסיס והפלטפורמה#
הפרמטר $base_domain = true קובע את הדומיין לפי CONFIG::$base_domain. עם false הליבה בוחרת את הדומיין מנתוני הפלטפורמה (CONFIG::$platform_data): אם הדומיין הנוכחי נמצא ברשימת הדומיינים המותרים של הפלטפורמה העוגייה נקבעת עליו, אחרת על דומיין הפלטפורמה. באתר רגיל (לא פלטפורמה מרובת דומיינים) משאירים true; ערך false שייך לעוגיות הניהול של פלטפורמה.
get, is_set, kill#
| מתודה | התנהגות |
|---|---|
get($name) | הערך של $_COOKIE["CRM_<name>"], או false כשהעוגייה לא קיימת |
is_set($name) | bool |
kill($name, $base_domain = true) | שולחת עוגייה ריקה שפגה (time()-1) על אותו path ו-domain, ומסירה מ-$_COOKIE. עם $base_domain = false בוחרת דומיין לפי כללי הפלטפורמה |
set_hours($name, $hours, $base_domain = true) | מאריכה עוגייה קיימת: קוראת את הערך ושולחת אותה שוב עם set. אם העוגייה לא קיימת לא עושה כלום |
set_secure_hours($name, $hours, $base_domain = true) | אותו דבר עם set_secure |
כל מתודה מוסיפה את הקידומת CRM_ בעצמה. אל תעבירו "CRM_lang_pref", אלא "lang_pref". בדפדפן ובכותרות העוגייה נקראת CRM_lang_pref.
SameSite#
ברירת המחדל None מאפשרת שליחת העוגייה גם בבקשות מאתרים אחרים (ו-iframe). לעוגיות כניסה ולאתרים שאינם מוטמעים במקום אחר עדיף Lax. COOKIES::$samesite הוא public static, ולכן קובעים אותו פעם אחת:
// application/includes/init.php
COOKIES::$samesite = "Lax";
השינוי חל על set בלבד. set_secure תמיד Lax.
עוגיות שהליבה קובעת#
| עוגייה | מי | מאפיינים |
|---|---|---|
CRM_admin_session | כניסת מנהל | set_secure, 168 שעות (7 ימים), הערך הוא טוקן אקראי של 64 תווים hex השמור ב-CRM_adminPanel_sessions |
CRM_admin_logged | דגל ל-JavaScript של הפאנל | set, ערך 1, כ-10 שנים |
CRM_admin_csrf | אסימון CSRF של הפאנל | set_secure, שעה |
CRM_admin_lang | שפת הפאנל | set, עוגיית סשן |
CRM_login_<table> | LOGIN (משתמשי אתר) | set, ברירת מחדל כ-7 שנים |
CRM_user_<table> | COOKIES::user_log (ישן) | set, 72 שעות כברירת מחדל |
פרטי הכניסה של מנהלים בהתחברות וסשנים. הדפדפן שולח את כל העוגיות של הדומיין בכל בקשה, כולל לקבצים סטטיים, ולכן כדאי לשמור עוגיות קטנות ומעטות.
כניסה ישנה: COOKIES::user_*#
מנגנון ישן לכניסת משתמשי אתר, בלי טבלת טוקנים. מתאים רק לתחזוקת קוד קיים; לאתר חדש השתמשו ב-LOGIN (משתמשי האתר).
| מתודה | התנהגות |
|---|---|
user_log($table, $id, $sessTime = 72) | דורשת שורה בטבלה $table. שומרת בעוגייה CRM_user_<table> את MISC::encode(["uid", "ip", "tbl"]). מחזירה את תוצאת COOKIES::set, או false כשהמשתמש לא קיים |
user_log_details($table, $user, $pass, $sessTime = 72) | מחפשת שורה עם username (אחרי MISC::special_chars) ו-password = md5($pass), ואז user_log |
user_is_logged($table) | מפענחת את העוגייה, בודקת uid > 0, שהטבלה זהה, שהשורה קיימת, ובנעילת IP (ראו להלן) |
user_get_id($table) | int, או false כשלא מחובר |
user_logout($table) | מוחקת את העוגייה בלבד |
נעילת ה-IP פעילה כש-COOKIES::$login_use_ip הוא true (ברירת המחדל במחלקה הזו, בניגוד ל-LOGIN): העוגייה תקפה רק מהכתובת שהונפקה לה. ב-false הנעילה כבויה.
user_log_details משווה md5 של הסיסמה, והעוגייה לא רשומה בשום טבלה, ולכן אי אפשר לבטל אותה בשרת (יציאה רק מוחקת אותה במכשיר). כמו ב-LOGIN, הטוקן מוצפן באמצעות MISC::encode ולכן כל התלות היא בסודיות המפתחות (הצפנה).SESSION#
עטיפה דקה לסשן של PHP, בעלת ממשק של מפתח וערך. כל קריאה פותחת את הסשן (session_start() אם אינו פעיל), עושה את הפעולה וסוגרת אותו מיד (session_write_close()), כך שקובץ הסשן לא נשאר נעול והבקשות המקבילות של אותו משתמש לא חוסמות זו את זו.
| מתודה | התנהגות |
|---|---|
SESSION::set($key, $val) | שומרת. אובייקט וכל ערך שאינו מחרוזת או מספר עוברים serialize. מחזירה true |
SESSION::get($key) | מחזירה את הערך, או "" כשהמפתח לא קיים. מחרוזת מסוג serialized עוברת unserialize אוטומטית |
SESSION::is_set($key) | true כש-get($key) != "" (ערך ריק, 0 כמחרוזת או false נחשבים "לא קיים") |
SESSION::remove($key) | מסירה מפתח |
SESSION::destroy() | מבצעת unset($_SESSION). לא קוראת ל-session_destroy(), ולכן הקובץ והעוגייה PHPSESSID נשארים |
SESSION::init() / SESSION::close() | פתיחה וסגירה ידניות |
SESSION::set("cart", ["items" => [12, 18], "coupon" => "SPRING"]);
$cart = SESSION::get("cart"); // המערך, אחרי unserialize
SESSION::remove("cart");
get מפענחת כל ערך שנראה כמו serialized, בלי הגבלת מחלקות. שמרו בסשן רק ערכים שהקוד שלכם יצר, ולעולם לא קלט משתמש "כמו שהוא" שיכול להיראות כמו serialized.הגדרות הסשן שהליבה לא קובעת#
הליבה לא קובעת session_set_cookie_params, שם סשן או נתיב שמירה, ולא קוראת ל-session_regenerate_id בכניסה. עוגיית הסשן מקבלת את ברירות המחדל של השרת. הגדירו ב-php.ini או ב-.user.ini:
session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.use_strict_mode = 1
session.use_only_cookies = 1
ולפני שמירת זהות בסשן (כניסה), החליפו את מזהה הסשן כדי למנוע session fixation:
// בקוד כניסה משלכם, כשמשתמשים ב-SESSION לזהות
SESSION::init();
session_regenerate_id(true);
SESSION::close();
הליבה עצמה משתמשת ב-SESSION לנתונים זמניים (למשל מצב טופס, אוטוקומפליט, בדיקת IP), לא לכניסת מנהלים: מנהלים נכנסים לפי CRM_admin_session ולא לפי סשן PHP.
מתי עוגייה, מתי סשן#
- סשן: נתונים זמניים של גולש (עגלה, שלב בטופס). נשמרים בשרת, הגולש מחזיק רק מזהה.
- עוגייה: העדפות קטנות שאין בהן סוד (שפה, הסכמה לעוגיות).
- טוקן בטבלה: כניסה של משתמש (
LOGIN).
דף שמוגש ממטמון עמוד מלא (PAGE::$cache_this_page) לא מריץ את הקוד שלכם פר-גולש, ולכן אל תקראו שם עוגיות או סשן (מטמון עמוד).