سلام. من با هماهنگی جناب مهندس شهرکی این کلاس رو به روش pdo تغییر ساختار دادم. امیدوارم لذت ببرید
ذخیره سازی سشن ها در دیتابیس به روش PDO
آقای شهرکی من یک مشکل عجیبی با این کلاس پیدا کردم، و اون اینکه وقتی که لاگین شدیم و مثلا ریدایرکت شدیم از login.php به index.php ، حالا اگر توی این صفحه index.php دکمه ctrl+F5 رو پشت سرهم تند تند بزنی، یک دفعه لاگ اوت میشی و به صفحه login.php ریدارکت میشی اتوماتیک، که دوباره باید لاگین کنی!!! دیتابیس رو هم این موقع اگر نگاه کنی، میبنی چند تا رکورد با هش های برابر توی دیتابیس موجوده، در حالی که ما یک کاربر بیشتر نبودیم که توی سایت لاگین بودیم!
من اومدم توی کلاس تغییراتی رو ایجاد کردم و قبل و بعد از صدا زدن متود اصلی کلاس در متود constructor دیتابیس رو قفل و بعدش آزاد کردم، مشکل رکوردهای تکراری حل شد ولی بازم با ctrl+f5 زدن و رفرش کردن هر صفحه ای که سشن توش استفاده میشه به login.php ریدارکت میشیم!
به نظرتون مشکل از کجاست؟ اینم اضافه کنم که من از session_regenerate_id هم بعد از ساخت سشن و توی هر صفحه ای که از سشن استفاده داره، استفاده میکنم.
راستش فکر میکنم (مطمئن نیستم) چون با دیتابیس کار میکنه، یکم نسبت به فایل کندتره و درنتیجه با درخواستهای پشت سر هم، یه جا ممکنه قبل از اینکه به یه درخواست جواب داده بشه و اطلاعات از دیتابیس خونده بشه، درخواست بعدی بیاد و درخواست قبلی لغو بشه و مشکلاتی مثل Max Connection Limit Reached ایجاد کنه. بهرحال توی سایت واقعی فکر نمیکنم کسی بیاد تند تند Ctrl+F5 بزنه و تازه اگه بزنه هم رسیدن درخواست به سرور یکم کندتر از localhost هست و سرور فرصت داره درخواست قبلی رو کامل کنه.
واسه امنیته، اگر کلاس رو نگاه کنید میبیید مثلا ip و خیلی چیزای دیگه رو از کاربر میگیرید و توی دیتابیس ذخیره میکنید با اینکار مسائلی زیادی مثل session fixation و ... حل میشه.
اگر آقای شهرکی اجازه بدن، این کلاس رو خودم دارم روش کار میکنم و یک سری ایرادی که وجود داشت رو میخوام حل بکنم و یک بهبودی بدم، بعدش صبر کنید همینجا قرار میدمش واستون.
یکی دیگه از مزایاش، دسترسی به اطلاعات بیشتری از اطلاعات کاربران هست. مثلاً الان دقیقاً با کمک کوئری میتونید بفهمید کیا آنلاین هستن (مثلاً آخرین آمار فعالیتشون رو توی دیتابیس دارین و کسانی که کمتر از 20 دقیقه از آخرین فعالیتشون گذشته رو آنلاین نشون بدین) و...
الان که بیشتر فکر میکنم میبینم شما بخاطر استفاده از session_regenerate_id به این مشکل برخوردین. موضوع از این قراره که شما یه درخواست میدین و سرور میخواد سشن رو تغییر بده و توی دیتابیس، id عوض میشه ولی قبل از اینکه جواب به کلاینت برسه و اونم توی کوکی، PHPSESSID رو عوض کنه، یه درخواست دیگه میفرستین که چون همون id قبلی با کوکی ارسال شده، یه درخواست جدید درنظر میگیره و رکورد جدید میسازه یا لاگین نشده حساب میکنه چون سمت سرور id سشن عوض شده ولی مهلت ندادین جواب از سرور بیاد و id جدید توی کوکی کلاینت ذخیره بشه. بهرحال توی سرور واقعی بعید میدونم چنین سناریویی پیش بیاد.
درمورد تغییر کلاس هم مشکلی نیست. کلاس Open Source هست. یادمه قبلاً هم یکی دیگه از دوستان اون رو با PDO بازنویسی کرده بود.
راه حلی به ذهنتون نمیرسه واسه حل این مسئله؟ خودم که دیدم با مثلا lock کردن دیتابیس هیچ کاری نمیتونم بکنم، چون به هر جهت یک جایی باید قفل رو بردارم که باز طرف میتونه ctrl+F5 بزنه! ولی یک راه دیگه ای که به ذهنم میرسه، استفاده از sleep قبل از صدا زدن کلاس هستش! که خیلی راه بدیه
پیشنهاد میکنید کلا session_regenerate_id رو بردارم؟ چون من به توصیه دوستان توی این تاپیک از این تابع استفاده کردم.
خوب برای آنلاین بودن هم میشه یک فیلد activity گذاشت.
خوب سربار اضافی میشه دیگهواسه امنیته، اگر کلاس رو نگاه کنید میبیید مثلا ip و خیلی چیزای دیگه رو از کاربر میگیرید و توی دیتابیس ذخیره میکنید با اینکار مسائلی زیادی مثل session fixation و ... حل میشه.
دوست عزیز session fixation یعنی سرقت سشن که حمله کننده به راحتی نمیتواند نفوذ کند. درضمن من خیلی بار گفتم که اگر کسی session id را بتونه از روی حدث در بیاره احتمال خیلی کم شاید هم صفر داشته باشد.
برای جلوگیری از این روش ها خیل راحت میشه با چند کار ساده این کار را انجام داد.
اصلا ذخیره سشن در پایگاه داده از نظر من اشکال امنیتی و بهینه سازی داره
اصلا هدف از سشن چیه ؟ هدف اش این است که پروتکل http فراموش کار را بهش یادآوری بدهد و خود سازنده های PHP این همه توابع ننوشتن که ما بیاییم در دیتابیس ذخیره کنیم.
شما فکر کنید ما فقط لازم داریم یک session id یا حداقل یک user id و یک سری پارامتر های کمی را در سشن ذخیره کنیم کفایت می کند.
حالا برای مثال بالا خودتون قضاوت کنید :
فرض ما بر این است که dbms روی سرور دیگری است و ما بیاییم برای خواندن فقط چند کیلوبایت داده عملیات زیر را انجام دهیم :
1. ابتدا به dbms وصل شویم
2. درخواست را بفرستیم
3.درخواست بررسی بشود
4. جستجو انجام بشود
5. واکشی بشود
6. برای ما از بستر نت ارسال بشود
و ...
حالا جزئیات را نمیدونم ولی اگر بخواهیم جزئیات را هم ذکر کنیم که دیگه کلی مرحله میشه
شاید برای یک الی چند نفر سریع انجام بشود ولی برای n کاربر نه !
و همچنین درخواست های همزمان هم که الان دوستمان باهاش با مشکل مواجه شده که باید برای اینکار جدول و اون رکورد را قفل کنیم.
در کل میتونه خیلی مسائلی دیگه که من و شما نمیدونیم پیش بیاید.
از این طرف این همه در پایگاه داده بهینه سازی هایی انجام دادن و آنقدر رویش کار کردن که بتونه کوئری شما را در بهترین پیچیدگی زمانی ارائه بدهند پس ما نباید خراب اش کنیم و سربار اضافی برایش درست کنیم.
از این رو خواندن یک فایل session اونم با خود توابع c که PHP استفاده می کند سرعت بی نظیری دارد چرا که ما نمی خواهیم عملیات جستجو ایی را انجام دهیم و نیازی به الگوریتمی برای جستجو و ... نیست !
قرار نیست کسی session id رو حدس بزنه، بلکه اگر پروژه ای که ما میسازیم رو کاربری که ازش استفاده میکنه اونو توی یک هاستینگ اشتراکی استفاده کنه و اون هاستینگ امنیتش کامل نباشه، هکر بدون اینکه session id ها رو بخواد حدس بزنه میتونه به فایل سشن php که برای همه اعضای هاستینگ مشترکه دست پیدا کنه و اینجوری همه سشن رو برداره!! بعدشم شما که میگید این سربار اضافه هستش یک مسئله ای هستش که هر کسی واسه پروژه خودش باید تصمیم بگیره، من که نگفتم حتما از این به بعد سشن ها رو توی دیتابیس ذخیره کنید دیگه! من چون خودم دارم یک پروژه ای رو روش کار میکنم که واسم مهمه و این پروژه یک ادمین به جز خود بنده نداره، که فقط واسم امنیتش مهمه نه اینکه من یک دونه کاربر به سیستم فشار بیارم! خب توی این شرایط من روی امنیت تاکید بیشتری دارم، ولی ممکنه توی یک پروژه دیگه ای از سشن به صورت معمولی استفاده کنم توی یک پروژه ای هم کوکی!
چه بسا روی هاست هایی که shared هستند ذخیره روی فایل فلت امن تر هم باشه چون معمولا بالای http root میشینه
دوست عزیز، این قابلیت، اگه مفید نبود خود PHP اجازه تغییر مکانیزم کاری سشن رو به برنامه نویس نمیداد. حملات سشن فقط محدود به Fixation نیست. اگه سرور درست کانفیگ نشده باشه، توی هاست اشتراکی اجازه دسترسی به فایلهای سشن سایر کاربران هم داده میشه. بعلاوه برای فیلد activity هم یکسری مشکلات هست. مثلاً کاربر بدون خارج شدن، لاگ اوت کنه. یا مسئله حذف رکوردهای Expireشده در روشهای دیگه که میان فعالیتها رو توی یک جدول جدا ذخیره میکنن که در اینجا خود PHP با کمک GC میاد اینها رو مدیریت میکنه.
برای مدیریت سشن هم باید چندین پارامتر مثل IP و Agent و... رو با هم ترکیب کنید و باهاش هش سشن رو بسازین تا هرکدوم از این موارد تغییر کرد، سشن قبلی معتبر نباشه. مثلاً اگه کاربر توی فایرفاکس لاگین کرد، توی کروم لاگین نباشه و...
بعلاوه این موضوع (ذخیره سشن در دیتابیس) ابداً چیز بدی نیست و بعنوان یک Option و قابلیت میشه بهش نگاه کرد. حالا اگه توی یک پروژه لازم بود، استفاده میکنید و اگه نیازی نداشتین، همونجا توی فایل بگذارین. این قابلیت اگه خوب نبود، فریمورکهای مطرح امروزی مثل Yii هم داخل خودشون تعبیه نمیکردنش.
مسئله نگهداری دیتابیس روی سرور دیگه رو هم نمیدونم چرا مطرح کردین چون عملاً توی 99٪ سایتهای ایرانی، Remote DB نداریم.
اینقدر یک مسئله ساده رو بزرگ و بغرنج نکنید!
اگه Permissionها روی اون هاست به خوبی تنظیم نشده باشه و open_basedir خاموش باشه، اجازه دسترسی به فایلها رو به همه کاربران اون هاست میده (چند مورد از هاستهای ایرانی و خارجی رو دیدم که این مشکل رو داشتن) درحالی که دیتابیس، حداقل یک مرحله امنیت بیشتر (نام کاربری و رمز و نام دیتابیس) داره. فکر نکنید همینکه یک فایل رو بالاتر از public_html قرار دادین یا htaccess. گذاشتین، دیگه امنیت تأمینه. خیلی وقتها حمله از داخل خود هاست انجام میشه (توسط یک نفر دیگه که روی همون هاست اکانت داره).
بعلاوه ذخیره سشن در دیتابیس به شما اجازه یکسری کنترلهای امنیتی بیشتر هم میده. مثلاً بطور خودکار موقعی که اطلاعات میخواد توی سشن ذخیره بشه، با الگوریتم AES و با کلید اختصاصی که خودتون توی برنامه تعریف کردین، رمزگذاری کنید و موقع خوندن باز بطور خودکار با همین الگوریتم و با کلید اختصاصی خودتون، رمزگشایی کنید. اینطوری اگه کسی به دیتابیس هم دسترسی پیدا کنه، اطلاعات موجود بدون داشتن اون کلید اختصاصی، به دردش نمیخوره.
داریم گفت و گو می کنیم دیگه(اگر ناراحت نمیشین :) ) و این مسئله ایی که شما دارین می گویید ساده ام نیست.
در کل که من باز هم نفهمیدم دلیل برتری اش را. معادل همه اینکار ها را میشه در session file هم انجام داد.
همه اش ام نباید در این میدان دید قرار داشته باشد شاید استفاده های دیگری هم بشود.اگه مفید نبود خود PHP اجازه تغییر مکانیزم کاری سشن رو به برنامه نویس نمیداد.
بحث امنیت سرور را دیگر در نظر نگیرید. ما فرض را بر این می گذاریم که امنیت چه سمت سرور و چه سمت کلاینت بالا است.اگه سرور درست کانفیگ نشده باشه، توی هاس...
بدون خارج شدن لاگ اوت کنه ؟ چطوری ؟ فکر کنم منظورتون این است که browser را ببندد اگر این هست مشکل اش چیه ؟ چطوری است ؟ منظورتان را متوجه نشده ام.بعلاوه برای فیلد activity هم یکسری مشکلات هست. مثلاً کاربر بدون خارج شدن، لاگ اوت کنه
این دلیل نمیشه.این قابلیت اگه خوب نبود، فریمورکهای مطرح امروزی مثل Yii هم داخل خودشون تعبیه نمیکردنش.
99 درصد ندارن ! نمیدونستم.مسئله نگهداری دیتابیس روی سرور دیگه رو هم نمیدونم چرا مطرح کردین چون عملاً توی 99٪ سایتهای ایرانی، Remote DB نداریم.
چند راهنمایی در مورد کلاس سشن (خودم توسعه دهنده اش شدم :)) )
1. یک متدی بگذارین که بشه خود کانکشن را گرفت من معمولا تو تمام پروزه ها از یک کانکشن استفاده می کنم.
2. بهتره در ساخت هش نام سرور + http_host را هم اضافه کنید اینطوری باعث جلوگیری از حمله بر روی ساب دامنه یا دامنه های مختلف میشه.(نمیدونم من روی PHP تست کردم جواب گرفتم یعنی شناسه سشن دامنه a.example.com را برای کوکی b.example.com تغییر دادم عمل کرد)
آخرین ویرایش به وسیله abolfazl-z : پنج شنبه 17 اردیبهشت 1394 در 23:53 عصر
فکر نمیکنم بتونید انکار کنید که با در دست گرفتن کنترل سشن، اختیارات بیشتری در تنظیم اون و اینکه چه چیزهایی رو توی بحث سشن و تولید هش دخالت بدین خواهید داشت (حتی میتونید برای مثال، توی یک فایل لوگ کلیه اعمال کاربر رو ذخیره کنید و این موضوع - Logging - رو به خود سشن بسپارین و توی کدتون درگیرش نشین).
قطعاً استفاده های دیگری هم داره ولی یکی از رایجترین کاربردهاش، همین موضوع هست. شما توی اینترنت دنبال Session Security in PHP بگردین میبینید که یکی از رایج ترین راهکارها که مورد اتفاق نظر برنامه نویسان بزرگی هم هست، همین ذخیره سشن در دیتابیس هست.همه اش ام نباید در این میدان دید قرار داشته باشد شاید استفاده های دیگری هم بشود.
شما سایت مشتری رو با فرضیات بالا میارین؟بحث امنیت سرور را دیگر در نظر نگیرید. ما فرض را بر این می گذاریم که امنیت چه سمت سرور و چه سمت کلاینت بالا است.
بله منظورم همون بستن مرورگر بود که اشتباهاً نوشتم لاگ اوت. منظورم اینه که برای فیلد activity اگه کاربر مرورگر رو ببنده، اون فیلد دست نخورده باقی میمونه ولی درمورد سشن، بهرحال بعد از تایم مشخصی که قابل تنظیمه، GC میاد سشنهای Expireشده رو حذف میکنه. ضمناً اگه برای هرکاری بخوایم فیلد به دیتابیس اضافه کنیم، از یکسری امتیازات PHP (مثل بروزرسانی خودکار Timestamp سشن) و... خودمون رو محروم کردیم. قرار نیست برای هر کاری که ابزار آماده اش هست، خودمون دیتابیس رو سنگین کنیم و منطق برنامه رو دستکاری کنیم.بدون خارج شدن لاگ اوت کنه ؟ چطوری ؟ فکر کنم منظورتون این است که browser را ببندد اگر این هست مشکل اش چیه ؟ چطوری است ؟ منظورتان را متوجه نشده ام.
پس چی دلیل میشه؟ پس دلیل اینکه این قابلیت رو توی فریمورک گذاشتن چی بوده؟ غیر از اینه که قابلیت مفید و سودمندی دونستنش؟ غیر از اینه که برای امنیت سشن، یکی از راهکارهای محبوب و کارآمد بوده؟این دلیل نمیشه.
نمیگم هاستها این قابلیت رو ندارن. میگم 99 درصد پروژه های ایرانی، Remote DB توی سناریوی کاریشون نیست و دیتابیس و فایلها یکجا قرار گرفتن.99 درصد ندارن ! نمیدونستم.
این کلاس رو توی پکیج PHP بازنویسی کردم و یکم امکاناتش اضافه شد:چند راهنمایی در مورد کلاس سشن (خودم توسعه دهنده اش شدم :)) )
1. یک متدی بگذارین که بشه خود کانکشن را گرفت من معمولا تو تمام پروزه ها از یک کانکشن استفاده می کنم.
2. بهتره در ساخت هش نام سرور + http_host را هم اضافه کنید اینطوری باعث جلوگیری از حمله بر روی ساب دامنه یا دامنه های مختلف میشه.(نمیدونم من روی PHP تست کردم جواب گرفتم یعنی شناسه سشن دامنه a.example.com را برای کوکی b.example.com تغییر دادم عمل کرد)
class DBSessionHandler {
public $sessionTable = 'DBSession';
public $autoCreateSessionTable = true;
public $expire = 1200; // 20 minutes
public $autoStart = true;
/**
* Create the session table
*/
private function _createTable() {
DB::Query("
CREATE TABLE `{$this->sessionTable}` (
`id` char(32) COLLATE utf8_bin NOT NULL,
`expire` int(11) DEFAULT NULL,
`data` longblob,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
");
}
/**
* Deletes expired session
*/
private function _deleteExpired() {
$expire = time();
DB::Query("DELETE FROM '{$this->sessionTable}` WHERE (`expire`<'{$expire}')");
}
/**
* Constructor
*/
public function __construct($autoStart = true) {
ini_set('session.save_handler', 'user');
$this->autoStart = $autoStart;
if($this->autoStart) {
$this->start();
}
register_shutdown_function(array($this, 'sessionClose'));
}
/**
* Update the current session ID with a newly generated one.
* @param boolean $deleteOldSession Whether to delete the old associated session values or not
*/
public function regenerateId($deleteOldSession = false) {
$oldId = session_id();
if(empty($oldId)) {
return;
}
session_regenerate_id();
$newId = session_id();
if(!$deleteOldSession) {
DB::Query("UPDATE `{$this->sessionTable}` SET `id`='{$newId}' WHERE (`id`='{$oldId}')");
}
else {
$expire = time() + $this->expire;
DB::Query("INSERT INTO `{$this->sessionTable}` VALUES ('{$newId}','{$expire}','')");
}
}
/**
* Actually start the session
*/
public function start() {
@session_set_save_handler(
array($this, 'sessionOpen'),
array($this, 'sessionClose'),
array($this, 'sessionRead'),
array($this, 'sessionWrite'),
array($this, 'sessionDestroy'),
array($this, 'sessionGC')
);
@session_start();
if(session_id() == '') {
throw new Exception('Failed to start session.');
}
}
/**
* Ends the current session and store session data
* Do not call this method directly.
*/
public function sessionClose() {
$this->_deleteExpired();
if(session_id() !== '') {
@session_write_close();
}
}
/**
* Session destroy handler
* Do not call this method directly.
* param string $id session ID
* @return boolean whether session is destroyed successfully
*/
public function sessionDestroy($id) {
DB::Query("DELETE FROM `{$this->sessionTable}` WHERE (`id`='{$id}')");
return (DB::AffectedRows() > 0);
}
/**
* Session GC (garbage collector) handler
* Do not call this method directly.
* @param integer $maxLifetime The number of seconds after which data will be seen as 'garbage' and cleaned up.
* @return boolean whether session is GCed successfully.
*/
public function sessionGC($id) {
$this->_deleteExpired();
return true;
}
/**
* Session open handler
* Do not call this method directly.
* @param string @savePath session save path
* @param @sessionName session name
* @return boolean Whether session is opened successfully
*/
public function sessionOpen($savePath, $sessionName) {
if($this->autoCreateSessionTable) {
$this->_deleteExpired();
if(DB::AffectedRows() < 0) {
$this->_createTable();
}
}
return true;
}
/**
* Session read handler
* Do not call this method directly.
* @param string $id session ID
* @return string the session data
*/
public function sessionRead($id) {
$expire = time();
$data = DB::ArrayQuery("SELECT `data` FROM `{$this->sessionTable}` WHERE (`id`='{$id}' AND `expire`>='{$expire}')");
return (count($data) > 0 ? base64_decode($data[0]['data']) : null);
}
/**
* Session write hanlder
* Do not call this method directly.
* @param string $id Session ID
* @param string $data session data
* @return boolean Whether session write is successful
*/
public function sessionWrite($id, $data) {
$data = base64_encode($data);
$expire = time() + $this->expire;
DB::Query("INSERT INTO `{$this->sessionTable}` VALUES ('{$id}','{$data}','{$expire}') ON DUPLICATE KEY UPDATE `data`='{$data}',`expire`='{$expire}'");
}
/**
* Count online users
*/
public function onlineCount() {
$expire = time();
$data = DB::ArrayQuery("SELECT COUNT(*) AS `total` FROM `{$this->sessionTable}` WHERE (`expire`>='{$expire}')");
return $data[0]['total'];
}
/**
* Return online users
*/
public function onlineUsers() {
$expire = time();
$data = DB::ArrayQuery("SELECT `data` FROM `{$this->sessionTable}` WHERE (`expire`>='{$expire}')");
$users = array();
foreach($data as $item) {
$item = base64_decode($item['data']);
if(preg_match('#username.*?"(.*?)"#i', $item, $match)) {
$users[] = $match[1];
}
}
return $users;
}
}
کلاس DB هم اینه کدش:
class DB {
/**
* @property Resource The connection field
*/
protected static $con = null;
private static $host = 'localhost';
private static $user = 'root';
private static $pass = '';
private static $db = 'test';
public function __construct() {
throw new Exception('Cannot create an object from this class.');
}
/**
* Database connector
* Initializes the object and connects to MySQL
*/
public static function Connect() {
self::$con = new mysqli(self::$host, self::$user, self::$pass, self::$db);
if (self::$con->connect_errno) {
die('Connect failed');
}
self::Query('SET NAMES \'utf8\'');
self::$con->set_charset('utf8');
}
/**
* How many rows affected?
* @return The number of affected rows by the last excuted query
*/
public static function AffectedRows() {
if(!self::$con) {
self::Connect();
}
return self::$con->affected_rows;
}
/**
* Executes a select query and return the result as standard PHP array
* @param string $query The select query to execute
* @return array The result array
*/
public static function ArrayQuery($query) {
if(!self::$con) {
self::Connect();
}
$result = array();
$rows = self::Query($query);
if($rows && ($rows->num_rows > 0)) {
while($row = $rows->fetch_assoc()) {
$result[] = $row;
}
}
return $result;
}
/**
* Escape a value to use safely in queries
* @param string $value The value to escape
* @return string|boolean The escaped value if connection exists, false otherwise
*/
public static function Escape($value) {
if(!self::$con) {
self::Connect();
}
if($value !== null) {
return self::Quote(self::$con->real_escape_string($value));
}
return 'NULL';
}
/**
* Execute a query and return the result as a MySQL resource
* @param string $query The query to execute
* @return resource|boolean The result resource if connection exists, false otherwise
*/
public static function Query($query) {
if(!self::$con) {
self::Connect();
}
return self::$con->query($query);
}
/**
* Get the last automatic generated id in insert queries
*/
public static function InsertId() {
if(!self::$con) {
self::Connect();
}
return self::$con->insert_id;
}
/**
* Quote the values
* @param string @value The value to quote
* @return string The quoted value
*/
public static function Quote($value) {
if($value !== null) {
return '\'' . trim($value, '\'') . '\'';
}
return $value;
}
}
اینم مثال از نحوه استفاده:
<?php
function AutoLoad($class) {
require_once 'class.' . $class . '.php';
}
spl_autoload_register('AutoLoad');
$dbsh = new DBSessionHandler();
?>
<!doctype html>
<html>
<head>
<title>Database Session Handler</title>
<meta charset="utf-8" />
</head>
<body>
<?php
echo '<p>There are ' . $dbsh->onlineCount() . ' user(s) online.</p>' . PHP_EOL;
echo 'Online users: <br />' . PHP_EOL;
foreach($dbsh->onlineUsers() as $user) {
echo $user . '<br />' . PHP_EOL;
}
?>
</body>
</html>
البته بدیهیه که میشه به شکل دلخواه متدهای کلاس رو تغییر داد و مواردی که مدنظرتون هست رو میتونید بهش اضافه کنید.
قطعا.فکر نمیکنم بتونید انکار کنید که با در دست گرفتن کنترل سشن، اختیارات بیشتری در تنظیم اون و اینکه چه چیزهایی رو توی بحث سشن و تولید هش دخالت بدین خواهید داشت (حتی میتونید برای مثال، توی یک فایل لوگ کلیه اعمال کاربر رو ذخیره کنید و این موضوع - Logging - رو به خود سشن بسپارین و توی کدتون درگیرش نشین).
مگر امنیت سرور و سیستم مشتری با برنامه نویس است ؟(دقت کنید باگ برنامه نویسی را نمیگم)شما سایت مشتری رو با فرضیات بالا میارین؟
بازم مفهومتان را متوجه نشدم.بهرحال بعد از تایم مشخصی که قابل تنظیمه، GC میاد سشنهای Expireشده رو حذف میکنه. ضمناً اگه برای هرکاری بخوایم فیلد به دیتابیس اضافه کنیم، از یکسری امتیازات PHP (مثل بروزرسانی خودکار Timestamp سشن) و... خودمون رو محروم کردیم. قرار نیست برای هر کاری که ابزار آماده اش هست، خودمون دیتابیس رو سنگین کنیم و منطق برنامه رو دستکاری کنیم.
خوب الان که شما دارین یک دیتابیس اضافه می کنید.ضمناً اگه برای هرکاری بخوایم فیلد به دیتابیس اضافه کنیم از یکسری امتیازات PHP (مثل بروزرسانی خودکار Timestamp سشن) و... خودمون رو محروم کردیم
به عنوان مثال با بروزرسانی کردن یک فیلد activity چه منطقی را دستکاری کردیم ؟ یعنی منظورتون کاهش بهینه سازی یا کد نویسی اضافی ؟قرار نیست برای هر کاری که ابزار آماده اش هست، خودمون دیتابیس رو سنگین کنیم و منطق برنامه رو دستکاری کنیم.
نگاه کنید می خواهیم دو ویژگی را از لحاظ security ، performance و advantage بررسی کنیم. (از نظر من امنیت در درجه اول قرار میگیره ولی بین مزایا و بهنیه سازی را نمیدونم ولی فکر کنم بهینه سازی)پس چی دلیل میشه؟ پس دلیل اینکه این قابلیت رو توی فریمورک گذاشتن چی بوده؟ غیر از اینه که قابلیت مفید و سودمندی دونستنش؟ غیر از اینه که برای امنیت سشن، یکی از راهکارهای محبوب و کارآمد بوده؟
حالا من سوال ام از همان اول همین بود و به جوابم هم نرسیدم.
حالا مهندس شما از دید خودتون و همچنین اطلاعت کلی که وجود دارد در مورد هر یک دلایلی بیان کنید نسبت به هم بدون حاشیه (اون بحثی که در بالا داشتیم را کنار بگذارید)
توی ایران زندگی میکنیم. دقت کنید که هنوز به اون مرحله نرسیدیم که کار تیمی داشته باشیم و خیلی جاها، مسئولیت تأمین امنیت هاست هم از دید مشتری با شماست. وقتی میشه جلوی یکسری خطاهای بقیه رو ازطریق برنامه خودمون بگیریم، بهتره امید به بقیه نداشته باشیم و خودمون دست به کار بشیم. گاهی اوقات هم خوندن سشنهای سایتها و... توسط کسانی که رابطه دوستانه با مدیر هاست دارن یا تطمیع مالی میکنن انجام میشه. خیلی از اسکریپتهایی که نال شدن، از همین روشها آسیب خوردن.
ببینید، مدیریت سشن PHP خودش Timestamp سشن رو اصلاح میکنه و نیاز نیست شما انجام بدین ولی اگه یه فیلد اضافه کنید، خودتون باید توی هر درخواست، آپدیت دیتابیس رو هم انجام بدین.بازم مفهومتان را متوجه نشدم.
دیتابسی که نه، احتمالاً منظورتون جدوله. بله جدول اضافه میشه ولی این جدول بطور خودکار پاکسازی میشه و بار اضافه ای روی جدول کاربران که توی سیستم، معمولاً خیلی زیاد باهاش سروکار داریم، گذاشته نمیشه.خوب الان که شما دارین یک دیتابیس اضافه می کنید.
منظورم اینه که توی برنامه باید مدام کدهایی رو ببینیم که داره اون فیلد رو اصلاح میکنه درحالی که اون فیلد جزو منطق برنامه نیست و فقط برای بحث کاربران آنلاین و... که میشد با مدیریت صحیح سشن، بهش برسیم داره بروزرسانی میشه. این یعنی توی هر بخش از برنامه و هر قابلیت جدیدی که اضافه میکنیم، باید حواسمون به بروزرسانی این فیلد هم باشه.به عنوان مثال با بروزرسانی کردن یک فیلد activity چه منطقی را دستکاری کردیم ؟ یعنی منظورتون کاهش بهینه سازی یا کد نویسی اضافی ؟
امنیت و کارآیی هر دو به یک اندازه اهمیت دارن. سایت امنی که دیر بالا میاد به درد مشتری نمیخوره. سایت سریعی که امنیت نداره هم به همون اندازه بلا استفاده است. درمورد مزایای یک سیستم هم به نوعی میشه گفت باید امنیت و کارآیی رو با هم درنظر گرفت. امتیازها و ویژگیهای خوبی که توی یک سیستم وجود داره بدون امنیت و راندمان مناسب، بدرد نمیخوره. شما حاضرین یک موبایل که کلی امکانات داره ولی به راحتی میشه اطلاعات شما رو از داخلش با بلوتوث بیرون کشید و برای هر درخواست، 5 دقیقه شما رو معطل میکنه بخرین، فقط به این خاطر که قابلیتهای زیادی داره؟ همه اینها در کنار هم بدرد میخورن و هرکدوم نباشه، یه جای کار میلنگه.نگاه کنید می خواهیم دو ویژگی را از لحاظ security ، performance و advantage بررسی کنیم. (از نظر من امنیت در درجه اول قرار میگیره ولی بین مزایا و بهنیه سازی را نمیدونم ولی فکر کنم بهینه سازی)
حالا من سوال ام از همان اول همین بود و به جوابم هم نرسیدم.
حالا مهندس شما از دید خودتون و همچنین اطلاعت کلی که وجود دارد در مورد هر یک دلایلی بیان کنید نسبت به هم بدون حاشیه (اون بحثی که در بالا داشتیم را کنار بگذارید)
آخرین ویرایش به وسیله MMSHFE : شنبه 19 اردیبهشت 1394 در 08:35 صبح دلیل: اشتباه تایپی
اون وقت اگر من سشن های متفاوتی داشته باشم چی ؟ببینید، مدیریت سشن PHP خودش Timestamp سشن رو اصلاح میکنه و نیاز نیست شما انجام بدین ولی اگه یه فیلد اضافه کنید، خودتون باید توی هر درخواست، آپدیت دیتابیس رو هم انجام بدین.
خوب البته سیستمی که من باهاش کار می کنم یک سیستم کاملا شخصی است و از صفر نوشته شده و شما فقط یکبار اونم بصورت خیلی زیبا آپدیت را انجام میدهید.(تا آخر تابستان اگر بشه میزارم تو گیتهاب)منظورم اینه که توی برنامه باید مدام کدهایی رو ببینیم که داره اون فیلد رو اصلاح میکنه درحالی که اون فیلد جزو منطق برنامه نیست و فقط برای بحث کاربران آنلاین و... که میشد با مدیریت صحیح سشن، بهش برسیم داره بروزرسانی میشه. این یعنی توی هر بخش از برنامه و هر قابلیت جدیدی که اضافه میکنیم، باید حواسمون به بروزرسانی این فیلد هم باشه.
من این رو نمیتونم قبول کنم که این یک سربار یا روش غیرمعقولی است !
باز رفتین حاشیه یا اینکه فکر کنم من منظورم را بد بیان کردم. منظور من در مورد session in dbms با session in file بود.امنیت و کارآیی هر دو به یک اندازه اهمیت دارن. سایت امنی که دیر بالا میاد به درد مشتری نمیخوره. سایت سریعی که امنیت نداره هم به همون اندازه بلا استفاده است. درمورد مزایای یک سیستم هم به نوعی میشه گفت باید امنیت و کارآیی رو با هم درنظر گرفتم. امتیازها و ویژگیهای خوبی که توی یک سیستم وجود داره بدون امنیت و راندمان مناسب، بدرد نمیخوره. شما حاضرین یک موبایل که کلی امکانات داره ولی به راحتی میشه اطلاعات شما رو از داخلش با بلوتوث بیرون کشید و برای هر درخواست، 5 دقیقه شما رو معطل میکنه بخرین، فقط به این خاطر که قابلیتهای زیادی داره؟ همه اینها در کنار هم بدرد میخورن و هرکدوم نباشه، یه جای کار میلنگه.
منظورتون رو متوجه نمیشم. شما اگه هزاران سشن هم داشته باشین، PHP خودش اونها رو مدیریت میکنه.
اگه این رو قبول داشته باشین که این کارها رو خود PHP میتونه به روش بهینه تر و اصولی تری مدیریت کنه، اونوقت میتونید بپذیرید که این روش بهرحال یک سربار داره روی کدها میگذاره چون PHP درهرصورت مدیریت سشن خودش رو داره و فقط ما اومدیم گفتیم برای امنیت بیشتر و دراختیار داشتن امکانات بیشتر، بجای فایلها و مسیر پیشفرضش، توی دیتابیس و جدولی که ما میگیم ذخیره کنه.خوب البته سیستمی که من باهاش کار می کنم یک سیستم کاملا شخصی است و از صفر نوشته شده و شما فقط یکبار اونم بصورت خیلی زیبا آپدیت را انجام میدهید.(تا آخر تابستان اگر بشه میزارم تو گیتهاب)
من این رو نمیتونم قبول کنم که این یک سربار یا روش غیرمعقولی است !
مشخصه که سرعت Session in File بیشتره ولی امنیت و امکانات و انعطاف پذیری Session in DB و بطور کلی User Session Handling بیشتره.باز رفتین حاشیه یا اینکه فکر کنم من منظورم را بد بیان کردم. منظور من در مورد session in dbms با session in file بود.
من بحثی ندارم، این قابلیت رو مطرح کردم. حالا هر کسی اون رو سودمند میدونه میتونه استفاده کنه. هرکی هم معتقده مفید نیست یا به کارش نمیاد، دلیلی نداره استفاده کنه. بهره گیری از امکانات مختلف، یک Option هست. همونطور که توی فریمورکها، این قابلیت وجود داره ولی اجباری یا حتی پیشفرض نیست. نمیدونم چرا دنبال برنده توی بحث هستین.
منظورم این هست که چند نوع کاربر مختلف آنلاین داشته باشم. اون وقت برای بدست آوردن تعداد آنلاین ها چیکار می کنیم ؟منظورتون رو متوجه نمیشم. شما اگه هزاران سشن هم داشته باشین، PHP خودش اونها رو مدیریت میکنه.
مثلا سیستم ما قابلیتی داره که با یک session دو نوع کاربر را آنلاین می کند یعنی مثلا یکی کاربر فروشگاه یکی دیگه کاربر انجمن. (برای مثال عرض کردم)
حالا ما می خواهیم تعداد آنلاین بودن کاربران فروشگاه و کاربران انجمن را جدا جدا حساب کنیم. چطوری باید انجام بدهیم ؟ آیا میشود ؟
مهندس من اصلا قصد جسارت ندارم ولی می خواهم برای سوال هایم جواب های علمی باشد و خیلی دوست دارم با افراد با تجربه ایی چون شما بحث و گفتگو چه کوچیک چه بزرگ داشته باشم.من بحثی ندارم، این قابلیت رو مطرح کردم. حالا هر کسی اون رو سودمند میدونه میتونه استفاده کنه. هرکی هم معتقده مفید نیست یا به کارش نمیاد، دلیلی نداره استفاده کنه. بهره گیری از امکانات مختلف، یک Option هست. همونطور که توی فریمورکها، این قابلیت وجود داره ولی اجباری یا حتی پیشفرض نیست. نمیدونم چرا دنبال برنده توی بحث هستین.
من روی سیستمی که دارم می سازم(با اون سیستمی اصلی نوشته میشه) یکم حساسم و باید پایه اش خوب ساخته بشه و دارم بحث می کنم که ببینم نظر بالا و پایین چطوریه و چه دیدی دارن شاید بدرد پروژه ام خورد و به بار علمی افزوده شد.
کاملا باهاتون موافقم اما انعطاف پذیری را میتوانم قبول کنم ولی امنیت را نه.مشخصه که سرعت Session in File بیشتره ولی امنیت و امکانات و انعطاف پذیری Session in DB و بطور کلی User Session Handling بیشتره.
خوب اگر قرار باشه به فایل دسترسی داشته باشند یعنی فاجعه. دیگه سشن و دیتابیس و ... امنیتشان به صفر می رسد. به عنوان مثال در سی ام اس های وردپرس راحت میتونن فایل wp-config را بخونند و اطلاعات دیتابیس را بدست بیاورند. درواقع همه کاری میتونند انجام بدهند دیگه.اگه Permissionها روی اون هاست به خوبی تنظیم نشده باشه و open_basedir خاموش باشه، اجازه دسترسی به فایلها رو به همه کاربران اون هاست میده (چند مورد از هاستهای ایرانی و خارجی رو دیدم که این مشکل رو داشتن) درحالی که دیتابیس، حداقل یک مرحله امنیت بیشتر (نام کاربری و رمز و نام دیتابیس) داره. فکر نکنید همینکه یک فایل رو بالاتر از public_html قرار دادین یا htaccess. گذاشتین، دیگه امنیت تأمینه. خیلی وقتها حمله از داخل خود هاست انجام میشه (توسط یک نفر دیگه که روی همون هاست اکانت داره).
چرا فکر میکنید کاری هست که با سشن عادی میتونید انجام بدین و با این سشن نمیشه؟ اینجا فقط اومدیم محل ذخیره سازی رو عوض کردیم. هر کاری توی پروژه خودتون با سشن خود PHP انجام دادین، اینجا هم میتونید حتی با انعطاف بیشتر انجام بدین. برای مثال، توی سشن کاربران، شناسه خاصی رو ذخیره کنید یا برای متغیرهای سشن اونها، پیشوند جداگانه تعریف کنید و...
این خیلی خوبه.مهندس من اصلا قصد جسارت ندارم ولی می خواهم برای سوال هایم جواب های علمی باشد و خیلی دوست دارم با افراد با تجربه ایی چون شما بحث و گفتگو چه کوچیک چه بزرگ داشته باشم.
من روی سیستمی که دارم می سازم(با اون سیستمی اصلی نوشته میشه) یکم حساسم و باید پایه اش خوب ساخته بشه و دارم بحث می کنم که ببینم نظر بالا و پایین چطوریه و چه دیدی دارن شاید بدرد پروژه ام خورد و به بار علمی افزوده شد.
نه دوست عزیز، بحث امنیت فایلها فقط مربوط به کانفیگ کاربران و گروهبندی اونها و مجوزهای دسترسی میشه ولی توی دیتابیس، یکم اوضاع فرق میکنه. معمولاً توی هاستها دسترسی به پوشه tmp که محل پیشفرض ذخیره سشنهاست، برای تمام کاربران فراهم هست و اگه سرور خوب تنظیم نشده باشه، کاربران به تمام فایلهای این پوشه دسترسی دارن ولی این معناش این نیست که به پوشه public_html شما هم دسترسی دارن و میتونن تنظیمات دیتابیس و... رو بخونن.کاملا باهاتون موافقم اما انعطاف پذیری را میتوانم قبول کنم ولی امنیت را نه.
خوب اگر قرار باشه به فایل دسترسی داشته باشند یعنی فاجعه. دیگه سشن و دیتابیس و ... امنیتشان به صفر می رسد. به عنوان مثال در سی ام اس های وردپرس راحت میتونن فایل wp-config را بخونند و اطلاعات دیتابیس را بدست بیاورند. درواقع همه کاری میتونند انجام بدهند دیگه.