前几天有朋友说他网站上有人刷虚拟物品,导致他损失太大,问我有没有什么简单的办法解决,他提出的要求是:同时只能由一个人登陆这个账号来避免多点同时登陆,同时刷新,于是我想到了将session信息存储到mysql数据库中,通过控制session信息到达单点登陆的目的,下面是关于将将session信息存储到mysql数据库中的一个测试。

Session在PHP中默认的是以文件的形式保存在一个临时文件夹里面的,对于一个小型系统来说,这样做完全可以,可是对于一个大型而又被经常访问的系 统来说,就不是很好的办法了。假设这个网站一天有1 000个人访问。一个月以后Session的临时文件夹就会有30 000个临时文件。想象一下计算机要从30 000里面找一条session_sid是要花费不少时间的。因此为了提高效率,使用用数据库来保存Session不失为解决这个矛盾的好方法。

Session既然在php中默认的是以文件的形式保存在一个临时文件夹里面的。那么可以通过修改php.ini文件的session.save_handler设置来改变Session的保存方式。默认为session.save_handler = files,必须将其修改为session.save_handler = user,即变为用户自定义方式。然后我们可以创建自己的用户级的一组Session函数(打开、读取、关闭、写入等),然后必须使用session_set_save_handler函数注册自己创建的Session的保存函数。

测试所需的脚本:

session_save.php注册自己创建的session的保存函数
set_session_test.php      session设置测试脚本
get_session_test.php      session显示测试脚本
数据库的表结构
列名
类型
说明
sesskey
char(32)
Session关键字
expiry
int(11) unsigned
有效期限
value
text
Session值
session_save.php代码:
$gb_DBname="samples";
$gb_DBuser="root";
$gb_DBpass="123456";
$gb_DBHOSTname="localhost";
$SESS_DBH="";//变量为$SESS_DBH数据库连接对象,将在sess_open函数中初始化。
$SESS_LIFE=get_cfg_var("session.gc_maxlifetime");//调用get_cfg_var函数取得session的最大有效期
//定义sess_open函数,带两个参数保存路径$save_path(文件保存方法时会用到),Session名称$session_name。这两个参数尽管没有在函数内使用,但必须以这种方式定义sess_open函数。所有Session处理函数都必须遵循此处所示的固定的定义方式。
functionsess_open($save_path,$session_name)
{
global$gb_DBHOSTname,$gb_DBname,$gb_DBuser,$gb_DBpass,$SESS_DBH;//global的作用是定义全局变量,但是这个全局变量不是应用于整个网站,而是应用于当前页面
///建立数据库连接,并初始化数据库连接对象$SESS_DBH。mysql扩展库中有两种建立数据库连接的函数,mysql_pconnect用于建立与数据库的持久连接,而函数mysql_connect用于建立非持久连接。出现连接错误时,显示错误信息:
if(!$SESS_DBH=mysql_pconnect($gb_DBHOSTname,$gb_DBuser,$gb_DBpass))
{
echo"
MySql Error:".mysql_error().""; 
 
die();
}
if(!mysql_select_db($gb_DBname,$SESS_DBH))//指定对象数据库,相当于执行“use 数据库名;”的命令。
{
echo"
MySql Error:".mysql_error().""; 
 
die();
}
returntrue;
}
functionsess_close()//定义关闭session方法。
{
returntrue;
}
functionsess_read($key)//读取session函数,参数为session关键字名(随机产生的乱码)
{
global$SESS_DBH,$SESS_LIFE;
//session关键字为条件,从表db_session检索出在有效期限内的session信息。
$qry="select value from db_session where sesskey = '$key' and expiry > ".time();
$qid=mysql_query($qry,$SESS_DBH);//#mysql_query函数执行一条 MySQL 查询。第二个参数为数据库连接,省略时使用上一个打开的连接
//#mysql_fetch_row从结果集中以数字数组的形式取得一行。依次调用 mysql_fetch_row() 将返回结果集中的下一行,如果没有更多行则返回 FALSE。成功时,此行的执行结果是将取出来的值放在变量$value中:
if(list($value)=mysql_fetch_row($qid)){
return$value;
}
returnfalse;
}
functionsess_write($key,$val)//##向数据库中保存Session信息。
{
global$SESS_DBH,$SESS_LIFE;
$expiry=time()+$SESS_LIFE;//###Session的期限是当前时间加上最大有效期后的时间。
$value=$val;
$qry="insert into db_session values('$key',$expiry,'$value')";
$qid=mysql_query($qry,$SESS_DBH);
if(!$qid)//插入失败,意味着数据库中已有Session记录,则对Session进行更新处理。
{
$qry="update db_session set expiry=$expiry,
value='$value' where sesskey='$key' and expiry >".time();
$qid=mysql_query($qry,$SESS_DBH);
}
return$qid;
}
functionsess_destroy($key)//定义删除Session信息的sess_destroy函数,关闭画面时会执行
{
global$SESS_DBH;
$qry="delete from db_session where sesskey = '$key'";
$qid=mysql_query($qry,$SESS_DBH);
return$qid;
}
functionsess_gc($maxlifetime)//定义自动删除过期的Session信息的函数sess_gc。
{
global$SESS_DBH;
$qry="delete from db_session where expiry 
$qid=mysql_query($qry,$SESS_DBH);
returnmysql_affected_rows($SESS_DBH);
}
session_module_name();//不带参数的session_module_name函数用于获取目前Session的模块。
session_set_save_handler("sess_open","sess_close","sess_read","sess_write","sess_destroy","sess_gc");
//注册自定义session函数,包括上面定义的所有函数
?>
set_session_test.php代码
//进行自定义Session处理文件。在所有使用自定义Session处理(本节即数据库保存方式)的页面中都必须包含此文件。
include("session_save.php");
//session_start函数,session处理开始。
session_start();
//下面三行设置session变量
$_SESSION['message']=" How do session store into database?";
$_SESSION['message1']="Just read this note ";
$_SESSION['from']=;
echo"显示SESSION";
?>
get_session_test.php代码
include("session_save.php");
session_start();
echo$_SESSION['message'];//显示session变量
echo"
";echo$_SESSION['message1'];
echo"
";echo$_SESSION['from'];
$_SESSION['addMess']="Hello";
?>

经过测试,session信息完全可以保存到数据库中,通过检查当前用户的session信息是否存在,或者是否过期,来判断该用户是否已经登陆 或者登陆超时,来更新数据库;再说说开题的需求,如果再每个需要验证用户的页面中加入,session信息是否存在的验证就可以实现单点登陆,我修改了朋友程序的代码,顺利的实现的了他的功能,再也没有人能刷虚拟商品了,不过本来他的程序漏洞太大,也没有空给他重编程序,他暂时就这么用了,以后有空还要研究下其他的方法。