前几天有朋友说他网站上有人刷虚拟物品,导致他损失太大,问我有没有什么简单的办法解决,他提出的要求是:同时只能由一个人登陆这个账号来避免多点同时登陆,同时刷新,于是我想到了将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代码:
- <?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处理函数都必须遵循此处所示的固定的定义方式。
- function sess_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 "<li>MySql Error:".mysql_error()."<li>";
- die();
- }
- if(!mysql_select_db($gb_DBname,$SESS_DBH)) //指定对象数据库,相当于执行“use 数据库名;”的命令。
- {
- echo "<li>MySql Error:".mysql_error()."<li>";
- die();
- }
- return true;
- }
- function sess_close() //定义关闭session方法。
- {
- return true;
- }
- function sess_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;
- }
- return false;
- }
- function sess_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;
- }
- function sess_destroy($key) //定义删除Session信息的sess_destroy函数,关闭画面时会执行
- {
- global $SESS_DBH;
- $qry="delete from db_session where sesskey = '$key'";
- $qid=mysql_query($qry,$SESS_DBH);
- return $qid;
- }
- function sess_gc($maxlifetime) //定义自动删除过期的Session信息的函数sess_gc。
- {
- global $SESS_DBH;
- $qry="delete from db_session where expiry < ".time();
- $qid=mysql_query($qry,$SESS_DBH);
- return mysql_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代码
- <?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']= "LAMPBO.org";
- echo "显示SESSION</a>";
- ?>
get_session_test.php代码
- <?php
- include ("session_save.php");
- session_start();
- echo $_SESSION['message']; //显示session变量
- echo "<br>";
- echo $_SESSION['message1'];
- echo "<br>";
- echo $_SESSION['from'];
- $_SESSION['addMess']="Hello";
- ?>
经过测试,session信息完全可以保存到数据库中,通过检查当前用户的session信息是否存在,或者是否过期,来判断该用户是否已经登陆 或者登陆超时,来更新数据库;再说说开题的需求,如果再每个需要验证用户的页面中加入,session信息是否存在的验证就可以实现单点登陆,我修改了朋友程序的代码,顺利的实现的了他的功能,再也没有人能刷虚拟商品了,不过本来他的程序漏洞太大,也没有空给他重编程序,他暂时就这么用了,以后有空还要研究下其他的方法。