ضمن عرض سلام مجدد، ديدم بد نيست يكسري توضيحات درباره اين كلاس ارائه بدم:
اين كلاس فكر ميكنم خيلي به درد ميخوره. بخصوص براي جلوگيري از حملاتي به سايت مثل سرقت Session و... در سرورهاي اشتراكي كه همه به پوشه tmp ميتونن دسترسي داشته باشن. ابتدا كد كلاس رو مشاهده كنيد:
<?PHP
//Copyright محمد مصطفي شهركي @ http://www.barnamenevis.ir
ini_set('session.save_handler','user');
class MySessionHandler
{
private $time_out; //Time out for session
private $salt; //Salt, an uniq string
private $browser_hash; //Browser hash
private $server; //Server name
private $user; //User name
private $pass; //Pass word
private $db; //Database name
public function Open($save_path, $session_name)
{
//Initialize your need here.
//In my case, I need nothing.
return true;
}
public function Close()
{
//Just deinitialize your resources
return true;
}
public function Write($id,$data)
{
$safe_id=mysql_real_escape_string($id);
$safe_data=mysql_real_escape_string($data);
$hash=mysql_real_escape_string($this->browser_hash);
$now=date("Y-m-d H:i:s");
$query="INSERT INTO `sessions` (`id`,`data`,`modified`,`hash`) VALUES ('$safe_id','$safe_data','$now','$hash') ON DUPLICATE KEY UPDATE `data`='$safe_data', `modified`='$now',`hash`='$hash'";
try
{
mysql_query($query);
}
catch(Exception $e)
{
return false;
}
return true;
}
public function Read($id)
{
$query='SELECT * FROM `sessions` WHERE (`id`=\''.mysql_real_escape_string($id).'\')';
try
{
$result=mysql_query($query);
}
catch(Exception $e)
{
return '';
}
//Is there any???
if (mysql_num_rows($result)!=1)
{
return '';
}
$data=mysql_fetch_assoc($result);
//Now its time to validate...
$time=strtotime($data['modified']);
$hash=$data['hash'];
//Check for time out and browser data
if(time()-$time > $this->time_out || strcasecmp($this->browser_hash,$hash)!=0)
{
return '';
}
//Anything is ok, return data
return $data['data'];
}
public function Destroy($id)
{
$safe_id=mysql_real_escape_string($id);
$query="DELETE FROM `sessions` WHERE (`id`='$safe_id')";
try
{
mysql_query($query);
}
catch(Exception $e)
{
return false;
}
$this->GC($this->time_out);
return true;
}
public function GC($maxlifetime)
{
//You can use your timeout instead of this.
$date=time()-$maxlifetime;
$date_str=date("Y-m-d H:i:s",$date);
$query="DELETE FROM `sessions` WHERE (`modified`<'$date')";
try
{
mysql_query($query);
}
catch(Exception $e)
{
return false;
}
return true;
}
private function connect()
{
mysql_connect($this->server,$this->user,$this->pass) or die('Connection Error');
mysql_select_db($this->db) or die('Database does not exit.');
mysql_query('SET NAMES \'utf8\'');
}
public function __construct($server,$user,$pass,$db,$time_out=600, $salt='')
{
date_default_timezone_set('Asia/Tehran');
if($salt=='')
{
$salt=md5('http://www.barnamenevis.ir');
}
$this->server=$server;
$this->user=$user;
$this->pass=$pass;
$this->db=$db;
$this->time_out=$time_out;
$this->salt=$salt;
$this->calcHash();
$this->connect();
session_set_save_handler(array(&$this,'Open'),arra y(&$this,'Close'),array(&$this,'Read'),array(&$thi s,'Write'),array(&$this,'Destroy'),array(&$this,'G C'));
}
private function calcHash()
{
$ip=isset($_SERVER['HTTP_CLIENT_IP'])?$_SERVER['HTTP_CLIENT_IP']:"Unknown";
$ip.=isset($_SERVER['HTTP_X_FORWARDED_FOR'])?$_SERVER['HTTP_X_FORWARDED_FOR']:"Unknown";
$ip.=isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:"Unknown";
$agent=isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:'NoUserAgent';
$browser_data=$this->salt.$_ip.$_agent;
$this->browser_hash=md5($browser_data);
}
}
?>
توي اين كلاس، بخشهاي زير وجود داره:
تنظيم session.save_handler با مقدار user تا ديگه موقع ساخت Session از فايلها استفاده نشه.
متد Open كه براي ايجاد يك Session جديد يا بازكردن Session موجود به كار ميره. همونطور كه ميبينيد، در كلاسي كه نوشتم، اين متد قرار نيست كاري انجام بده!
متد Close كه براي بستن Session كاربرد داره و همونطور كه ميبينيد، در كلاسي كه نوشتم، اين متد هم كاري انجام نميده!
متد Write كه براي نوشتن Session كاربرد داره و بعد از انجام كنترلهاي امنيتي، اطلاعات Session رو در بانك اطلاعاتي ذخيره ميكنه.
متد Read كه براي خواندن Session به كار ميره و بعد از اينكه مطمئن شد Session ID واردشده معتبره و زمان اعتبار Session تمام نشده، اطلاعات Session رو از بانك اطلاعاتي استخراج كرده و بر ميگردونه.
متد Destroy كه براي تخريب Session كاربرد داره و همونطور كه ميبينيد، بعد از حذف Session از بانك اطلاعاتي، متد GC رو صدا ميزنه كه به زباله روب معروفه!
متد GC همونطور كه گفتم، به زباله روب معروفه و قاعدتاً بايد هر چند وقت يكبار بطور خودكار فراخواني بشه ولي تابحال نديدم اين اتفاق بيفته. شايد علتش اين باشه كه PHP براي استفاده بهينه از منابع سرور، فقط وقتي صداش ميزنه كه با كمبود حافظه مواجه بشه. به هر حال، با فراخواني اين تابع، Sessionهايي كه مدت اعتبارشون منقضي شده، از بانك اطلاعاتي حذف ميشن تا حافظه اشغال شده، آزاد بشه. براي اطمينان، توي متد Destroy اين متد رو خودمون فراخواني ميكنيم تا هرموقع يك Session تخريب شد، ساير Sessionهاي منقضي شده هم از بانك اطلاعاتي حذف بشن.
متد Connect كه private هست و فقط داخل كلاس براي اتصال به بانك اطلاعاتي ازش استفاده ميكنيم.
متد سازنده كلاس كه كارش معلومه : مقداردهي اوليه به فيلدهاي كلاس و فراخواني تابع session_set_save_handler و ارسال متدهاي كلاس بعنوان پارامتر براي اون تا به PHP بگيم از اين متدها براي كار با Session استفاده كن.
و در آخر، متد calcHash كه private هست و با تركيب IP كاربر و IP پشت Proxy و IP پشت *** و همچنين Agent كه معرف سيستم عامل و مرورگر مورد استفاده است، يك كد Hash منحصر به فرد براي هر كاربر ايجاد ميكنه كه براي شناسايي كاربر استفاده ميشه. براي مثال، اگه IP فرد عوض بشه يا با مرورگر ديگه همزمان وارد سايت بشه، نميتونه از Session قبلي در اون مرورگر يا با IP جديد استفاده كنه.
حالا ببينيم چطور از اين كلاس استفاده مي كنيم:
اول يك جدول در بانك اطلاعاتي با ساختار زير ايجاد كنيد:
CREATE TABLE IF NOT EXISTS `sessions` (
`id` varchar(100) COLLATE utf8_bin NOT NULL,
`data` text COLLATE utf8_bin NOT NULL,
`modified` datetime NOT NULL,
`hash` varchar(60) COLLATE utf8_bin NOT NULL,
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
<!doctype html public "-//w3c//dtd xhtml 1.0 strict//en"
"http://www.w3.org/tr/xhtml1/dtd/xhtml1-strict.dtd">
<!-- Copyright محمد مصطفي شهركي @ http://www.barnamenevis.ir -->
<HTML xmlns="http://www.w3.org/1999/xhtml">
<HEAD>
<TITLE>Session Set Save Handler DEMO</TITLE>
<META http-equiv="content-type" content="text/html; charset=utf-8"/>
<?PHP
require_once('sssh.class.php');
?>
</HEAD>
<BODY>
<?PHP
$session=new MySessionHandler('localhost','root','','session_db ');
session_start();
echo isset($_SESSION['test'])?$_SESSION['test']:'Test session is not defined';
$_SESSION['test']='http://www.barnamenevis.ir';
echo '<BR/>';
echo isset($_SESSION['value'])?$_SESSION['value']:'value session is not defined';
$_SESSION['value']='http://www.barnamenevis.ir';
?>
</BODY>
</HTML>
خيلي ساده است، نه؟ كافيه يك شئ از كلاس ايجاد كنيم و بقيه كارها دقيقاً مثل قبله. انگار نه انگار كه Session توي DB ذخيره ميشه. مثل قبل با session_start و SESSION_$ و ساير توابع Session كار ميكنيم ولي ديگه فايلي براي ما ساخته نميشه. بنابراين، هرجا خواستين Session رو توي DB ذخيره كنيد، از اين كلاس يك شئ ايجاد كنيد و بعد با Session مثل قبل كار كنيد.
اميدوارم به دردتون بخوره.
موفق باشيد.