از دست رفتن PHP SESSION موضوعی نیست که هر روز با آن سر و کله بزنید، اما ممکن است شما هم مثل من به این مشکل برخورد کرده باشید. اگر این طور است این صفحه ممکن است به شما کمک کند.
اخیراً وقتی که روی یکی از پروژهام کار می کردم به مشکلی برخوردم که خیلی برام جدید و ناشناخته بود. وقتی که فرم submit می شد در دفعه اول و دوم CSRF Token در مقایسه با اطلاعات موجود در PHP Session معتبر بود ولی در دفعه سوم توکن غیر معتبر بود.
پس از رهگیری کد متوجه شدم که اطلاعات PHP Session به یک دلیلی که برایم کاملاً ناشناخته بود پاک می شدند. پس از چیزی حدود 10 روز سردرگمی و جستجوهای مختلف از این سایت و اون سایت بالاخره متوجه شدم که دلیل این خطا چه می باشد. برای همین تصمیم گرفتم که راه حل و تجربیاتی که در این چند روز باهاش مواجه بودم را در اینترنت به اشتراک بگذارم.
موضوعی که خیلی به نظرم مهم است و بایستی منبعد در عیب یابی ها مدنظرم باشد این بود که مشکلی که من باهاش مواجه بودم در سمت سرور بود ولی عیب یابی اون از سمت client باید شروع می شد. چرا که مشکل بخاطر کوکی PHP Session بوجود آمده بود ولی من توجهی به لاگ مرورگر نکرده بودم.
رفع مشکل PHP Session
در تصویر زیر می توانید خطای SameSite cookies که توسط مرورگر Firefox لاگ شده است را مشاهده نمایید.
متن این لاگ متن زیر می باشد:
Cookie “PHPSESSID” does not have a proper “SameSite” attribute value. Soon, cookies without the “SameSite” attribute or with an invalid value will be treated as “Lax”. This means that the cookie will no longer be sent in third-party contexts. If your application depends on this cookie being available in such contexts, please add the “SameSite=None“ attribute to it. To know more about the “SameSite“ attribute, read https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie/SameSite
این خطا مربوط به کوکی PHP Session می باشد، که بدرستی تنظیم نشده است و بدلیل تنظیمات پیش فرض فایل php.ini ایجاد شده است. برای رفع این مشکل کد زیر را قبل از دستور session_start()
وارد نمایید.
session_set_cookie_params(
array(
'lifetime' => 3600,
'path' => '/',
'domain' => $_SERVER['HTTP_HOST'],
'secure' => true,
'httponly' => true,
'samesite' => 'None'
)
);
کد بالا از تابع session_set_cookie_params()
استفاده می کند. این تابع پارامترهای کوکی PHP Session را تنظیم می نماید. در کد بالا طول عمر کوکی یک ساعت از زمان ایجاد (3600 ثانیه) تعیین شده است. توجه داشته باشید که پارامتر secure روی true تنظیم شده است و در صورتی که سایت شما رو اتصال https سرو شود کوکی ارسال خواهد شد. اگر اتصال سایت شما http می باشد این پارامتر را روی false تنظیم نمایید.
اطلاعات اضافی
در صورتی که با وجود کد بالا باز هم مشکل از دست رفتن اتفاقی داده های PHP Session را دارید، پیشنهاد من به شما این است که با استفاده از یک متغیر static دسترسی به داده های PHP Session را مدیریت نمایید. برای این منظور می توانید از کدهای زیر کمک بگیرید.
در کلاس header پروژه خودتان یک ویژگی static با نام $session
ایجاد نمایید. و سپس کدهای زیر را به کلاس header اضافه نمایید.
public function __construct() {
session_set_cookie_params(
array(
'lifetime' => 3600,
'path' => '/',
'domain' => $_SERVER['HTTP_HOST'],
'secure' => true,
'httponly' => true,
'samesite' => 'None'
)
);
session_start(); //start new session
self::$session = $_SESSION; //set session data to out static variable
session_write_close(); //Write session data and end session
}
public static function writeSessionData( string $key, mixed $data ) {
session_start(); //resum previous session
$_SESSION[$key] = $data; //write session data
self::$session = $_SESSION; //update static property
session_write_close(); //Write session data and end session
}
برای اینکه کد بالا به هدف موردنظر برسد در همه فایل های پروژه بایستی تابع session_start()
را حذف نمایید. هر جایی هم که می خواهید داده ای را در PHP Session نگهداری نمایید از متد writeSessionData به شکل زیر استفاده نمایید.
header::writeSessionData( 'user_id', $user_id ); //store user_id in session data