前言
上一篇讲述了Cookie管理,我们知道Cookie是服务器留在用户计算机中的小文件。每当相同的计算机通过浏览器请求页面时,它同时会发送 cookie。并且数
据信息是以明文文本的形式保存在客户端计算机中,因此最好不要保存一些含有敏感的、未加密的数据,否则会影响网络的安全性。
对比Cookie,Session会话文件中保存的数据在PHP脚本中是以变量的形式创建的,创建的会话变量在生命周期中可以被跨页的请求所引用。另外,Session会话是存储在服务器端的,相对安全,并且不像Cookie那样有存储长度的限制。
Session使用前的准备
在进行Session使用前,我们需要知道什么是Session、原理以及它的功能。
什么是Session
Session译为“会话”,其本义是指有始有终的一系列动作/消息,如打电话时从拿起电话拨号到挂断电话这一系列过程可以称为一个Session。
在计算机专业术语中,Session是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统所经过的时间。因此,Session实际上是一个特定的时间概念。
工作原理
当启动一个Session会话时,会生成一个随机且唯一的session_id,也就是Session的文件名,此时session_id存储在服务器的内存中,当关闭页面时此id会自动注销,重新登录此页面,会再次生成一个随机且唯一的id。
Session的功能
Session在Web技术中非常重要。由于网页是一种无状态的连接程序,因此无法得知用户的浏览状态。通过Session则可记录用户相关信息,以供用户再次以此身份对Web服务器提交要求时作确认。例如,在电子商务网站中,通过Session记录用户登录的信息,以及用户所购买的商品,如果没有Session,那么用户每进入一个页面都需要登录一次用户名和密码。
另外,Session会话适用于存储信息量比较少的情况。如果用户需要存储的信息量相对较少,并且对存储内容不需要长期存储,那么使用Session把信息存储到服务器端比较合适。
Session的使用
创建一个Session需要以下几个步骤:
- 启动会话
- 注册会话
- 使用会话
- 删除会话
1、启动会话的方式有两种,一种是使用session_start()函数,另一种方式是使用session_register()函数为会话创建一个变量来隐含地启动会话。
session_start()函数在页面开始位置调用,然后会话变量被登录到数据$_SESSION。
通过session_register()函数用来为会话创建一个变量来隐含地启动会话,但要求设置php.ini文件的选项,即将register_globals指令设置为on,然后重新启动Apache服务器即可;使用session_register()函数时不需要调用session_start()函数,PHP会在创建变量之后隐含地调用session_start()函数。
2、会话变量被创建后,全部保存在数组SESSION中。通过数组SESSION中。通过数组_SESSION创建一个会话变量很容易,只要直接给该数组添加一个元素即可。
1 2 3 4 5 6 7 8 9 10 11 | <?php /** * Created by IntelliJ IDEA. * Date: 2016/8/20 * Time: 14:41 */ session_start(); $_SESSION["admin"]=null; ?> |
上述程序中第一行代码是用于启动Session,第二行代码是声明一个名为admin的变量,并赋空值。
3、使用会话时,我们需要判断会话变量是否有一个会话ID存在,如果不存在,就需要创建一个,并且使其能够通过全局数组$_SESSION进行访问;如果已经存在,则将这个已经创建的会话变量载入以供用户使用。
1 2 3 4 5 | <?php if(!empty($_SESSION['session_name'])){ $myvalue=$_SESSION['session_name']; } ?> |
就像上述程序,先判断用于存储用户名的Session会话变量是否为空,不为空时,将会话变量赋给一个变量$myvalue。
4、删除会话的方法主要有删除单个会话、删除多个会话和结束当前会话3种,下面分别介绍这三种。
(1)删除单个会话即删除单个会话变量,同数组的操作一样,直接注销$_SESSION数组的某个元素即可。
1 2 3 | <?php unset($_SESSION['user']); ?> |
使用unset()函数时,要注意
$_SESSION
数组中元素不能省略,即不可以一次注销整个数组,这样会禁止整个会话的功能,如unset($_SESSION
)函数会将全局变量$_SESSION
销毁,而且没有办法将其恢复,用户也不能再注册$_SESSION
变量。如果要删除多个或全部会话,可采用下面的两种方法。
(2)删除多个会话即一次注销所有的会话变量,可以通过将一个空的数组赋值给$_SESSION来实现。
1 2 3 | <?php $_SESSION=array(); ?> |
(3)如果整个会话已经结束,首先应该注销所有的会话变量,然后使用session_destroy()函数清除结束当前的会话,并清空会话中的所有资源,彻底销毁Session。
1 2 3 | <?php session_destroy(); ?> |
给Session设置时间
Session失效时间设置主要有两种方式:
1、客户端没有禁止Cookie
(1)使用session_set_cookie_params()设置Session的失效时间,此函数时Session结合Cookie设置失效时间。以下示例让Session在1分钟后失效:
1 2 3 4 5 6 | <?php $time=1*60; session_set_cookie_params($time); session_start(); $_SESSION[username]='mr'; ?> |
session_set_cookie_params()必须在session_start之前调用。
不推荐使用此函数,此函数在一些浏览器上会出现问题,所有一般手动设置失效时间。
(2)使用setcookie()函数对Session设置失效时间,如让Session在1分钟后失效:
1 2 3 4 5 6 | <?php session_start(); $time=1*60; setcookie(session_name(),session_id(),time()+$time,"/"); $_SESSION['user']="mr"; ?> |
在上面程序的setcookie()函数中,session_name是Session的名称,session_id是判断客户端用户的标示,因为session_id是随机产生的唯一名称,所以Session是相对安全的。失效时间和Cookie的失效时间一样,最后一个参数为可选参数,是放置Cookie的路径。
2、客户端禁止Cookie
当客户端禁用Cookie时,Session页面间传递会失效,可以将客户端禁止Cookie想象成一家大型连锁超市,如果在其中一家超市内办理了会员卡,但是超市之间并没有联网,那么会员卡就只能在办理的那家超市使用。解决这个问题有4种方法:
(1)在登录之前提醒用户必须打开Cookie,这是很多论坛的做法。
(2)设置php.ini文件中的session.use_trans_sid = 1,或者编译时打开-enable-trans-sid选项,让PHP自动跨页面传递session_id。
(3)通过GET方法,隐藏表单传递session_id。
(4)使用文件或者数据库存储session_id,在页面间传递中手动调用。
以上2种方法不做详细讲解,因为用户不能修改服务器的php.ini文件。第3种方法我们就不可以使用Cookie设置失效时间,但是登陆情况没有变化。
我们基于第3种方法使用GET方法传输,先看实际效果图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <?php header("Content-Type:text/html;charset=utf-8"); session_start(); ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd";> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>登录页面</title> <link href="css/style.css" rel="stylesheet" type="text/css" /> </head> <body> <table width="328" border="0" align="center" cellpadding="0" cellspacing="0"> <tr> <td height="100"></td> </tr> <tr> <td height="214" valign="top" background="images/index_01.jpg"> <form id="form1" name="form1" method="post" action="common.php?<?=session_name(); ?>=<?=session_id(); ?>"> <table width="100%" height="171" border="0" cellpadding="0" cellspacing="0"> <tr> <td width="200" height="60"></td> <td> </td> </tr> <tr> <td align="right" class="white12">用户名:</td> <td> <input name="username" type="text" size="15" /> </td> </tr> <tr> <td align="right" class="white12">密 码:</td> <td><input name="password" type="password" size="15" /></td> </tr> <tr> <td> </td> <td valign="bottom"><input type="submit" name="Submit" value="登 录" /> <input type="reset" name="Submit2" value="取 消" /></td> </tr> </table> </form> </td> </tr> </table> </body> </html> |
上面是我们的登陆主界面的代码。在最上面执行了session_start();
这时会话变量被登录到数据$_SESSION。
1 |
看到点击登陆是地址栏会显示session的ID,并在当前目录下的tmp文件夹下生产一个以sess_开头加上sessionID的文件,查看文件内容可以发现存储着以下值:
admin|s:6:”mrsoft”;
这时点击登陆执行以下代码:
1 | <form id="form1" name="form1" method="post" action="common.php?<?=session_name(); ?>=<?=session_id(); ?>"> |
点击登陆按钮后执行common.php脚本,继续查看common.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <?php header("Content-Type:text/html;charset=utf-8"); error_reporting(0); $path = './tmp/'; $sess_name = session_name(); $sess_id = $_GET[$sess_name]; session_id($sess_id); session_save_path($path); session_start(); if ((trim($_POST['username'])) != 'tm' or (trim($_POST['password']) != '111')) { echo "<script>alert('用户名与密码错误!');location.href='index.php'</script>"; } $_SESSION['admin'] = 'mrsoft'; ?> <link href="css/style.css" rel="stylesheet" type="text/css" /> <table width="328" border="0" align="center" cellpadding="0" cellspacing="0"> <tr> <td height="100"></td> </tr> <tr> <td height="214" valign="top" background="images/index_01.jpg"><table width="100%" border="0" cellspacing="0" cellpadding="0"> <tr> <td width="100"></td> <td height="70"></td> </tr> <tr> <td align="center" valign="middle"> </td> <td height="80" align="center" valign="middle"><p class="white12"> 恭喜您登录成功<a href="connect.php?<?=session_name(); ?>=<?=session_id() ?>"> 请点击转入内容页面</a></p> </td> </tr> </table></td> </tr> </table> |
代码比较简单,先是获取session的名称,然后根据session名称获取session的ID,然后通过session_id()函数存取目前 session的ID,并保存在当前路径下的tmp文件夹下。最后通过$_SESSION[‘admin’] = ‘mrsoft’;将mrsoft值保存在服务器中以便你其他模块操作的使用 。
假设我们将tmp文件夹下的生成的文件删除,点击登陆按钮执行以下代码:
1 | <form id="form1" name="form1" method="post" action="connect.php?<?=session_name(); ?>=<?=session_id(); ?>"> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?php header("Content-Type:text/html;charset=utf-8"); error_reporting(0); $sess_name = session_name(); $sess_id = $_GET[$sess_name]; session_id($sess_id); session_save_path('./tmp/'); session_start(); if ($_SESSION['admin'] == "") { echo "<script>alert('对不起,你没有权限');location.href='index.php'</script>"; } ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>后台管理页面</title> <link href="css/style.css" rel="stylesheet" type="text/css" /> </head> <body> <table width="779" height="712" border="0" align="center" cellpadding="0" cellspacing="0" background="images/index_02.jpg"> <tr> <td></td> </tr> </table> </body> </html> |
从上面程序可以看出来登陆时会去检查session的ID生成的文件中是否有admin,为空时,说明没有权限,当然之前tmp文件下的文件如果不删除的话,可以直接登陆进入,无需用户名和密码。
Session高级应用
session的临时文件
在服务器中,如果将所有用户的Session都保存到临时目录中,会降低服务器的安全性和效率,打开服务器存储的站点会非常慢。使用PHP函数session_save_path()存储Session临时文件,可缓解因临时文件的存储导致服务器效率降低和站点打开缓慢的问题。
1 2 3 4 5 6 7 | <?php $path = './tmp/'; // 设置session存储路径 session_save_path($path); session_start(); // 初始化session $_SESSION[username] = true; echo "Session文件名称为:sess_" , session_id(); ?> |
session缓存
Session的缓存是将网页中的内容临时存储到IE客户端的Temporary Internet Files文件夹下,并且可以设置缓存的时间。当第一次浏览网页后,页面的部分内容在规定的时间内就被临时存储在客户端的临时文件夹中,这样在下次访问这个页面时,就可以直接读取缓存中的内容,从而提高网站的浏览效率。
Session缓存的完成使用的是session_cache_limiter()函数,其语法如下:
1 | <span class="hljs-keyword">string</span> session_cache_limiter ( [<span class="hljs-keyword">string</span> cache_limiter]) |
参数cache_limiter为public或private。同时Session缓存并不是指在服务器端而是客户端缓存,在服务器中没有显示。
缓存时间的设置,使用的是session_cache_expire()函数,其语法如下:
1 | <span class="hljs-keyword">int</span> session_cache_expire ( [<span class="hljs-keyword">int</span> new_cache_expire]) |
参数cache_expire是Session缓存的时间数字,单位是分钟。
下面是Session缓存页面过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | <?php session_cache_limiter('private'); $cache_limit = session_cache_limiter(); session_cache_expire(30); $cache_expire = session_cache_expire(); session_start(); ?> <html> <head> <title>Session客户端缓存</title> </head> <style type="text/css"> <!-- .black12 { font-family: "宋体"; font-size: 12px; line-height: 30px; color: #000000; text-decoration: none; } .red12 { font-family: "宋体"; font-size: 12px; line-height: 30px; color: red; text-decoration: none; } --> </style> <body> <table width="502" height="300" border="0" align="center" cellpadding="0" cellspacing="0" background="images/index_01.jpg"> <tr> <td valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0"> <tr> <td height="120"> </td> </tr> <tr> <td align="center" class="black12">缓存限制为 <span class="red12"><?=$cache_limit ?></span></td> </tr> <tr> <td align="center" class="black12">缓存Session页面失效时间在 <span class="red12"><?=$cache_expire ?></span> 分钟之后</td> </tr> </table></td> </tr> </table> </body> </html> |
Session数据库存储
通过改变Session存储文件夹使Session不至于将临时文件夹填满而造成站点瘫痪,但一个网站一天登陆几千人,一个月就上万人,这时站点中就存在这么多Session文件,要在这些文件中查询某个session_id也不是一件轻松的事情。这时就可以用Session数据库存储,也就是PHP中的session_set_save_handler()函数。
语法格式如下:
1 | bool session_set_save_handler ( string open, string close, string read, string write, string destroy, string gc) |
参数 | 说明 |
---|---|
open(save_path,session_name) | 找到Session存储地址,取出变量名称 |
close() | 不需要参数,关闭数据库 |
read(key) | 读取Session键值,key对应session_id |
write(key,data) | 其中data对应设置的Session变量 |
destroy(key) | 注销Session对应Session键值 |
gc(expiry_time) | 清除过期Session记录 |
一般应用参数直接使用变量,但是此函数中参数为6个函数,而且在调用时只是调用函数名称的字符串,下面将分别讲解这6个参数(函数),最后将把这些封装进类中。
(1)封装session_open()函数,连接数据库,代码如下:
1 2 3 4 5 6 7 | function _session_open($save_path,$session_name) { global $handle; $handle = mysql_connect('localhost','root','root') or die('数据库连接失败'); //连接MySQL数据库 mysql_select_db('db_database11',$handle) or die('数据库中没有此库名'); //找到数据库 return(true); } |
2)封装session_close()函数,关闭数据库连接,代码如下:
1 2 3 4 5 6 | function _session_close() { global $handle; mysql_close($handle); return(true); } |
在这个参数中不需要任何参数,所以不论是Session存储到数据库还是文件中,只需返回true即可。但是如果是MySQL数据库,最好是将数据库关闭,以保证以后不会出现麻烦。
(3)封装session_read()函数,在函数中设定当前时间的UNIX时间戳,根据$key值查找Session名称及内容,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function _session_read($key) { global $handle; //全局变量$handle连接数据库 $time = time(); //设定当前时间 $sql = "select session_data from tb_session where session_key = '$key' and session_time > $time"; $result = mysql_query($sql,$handle); $row = mysql_fetch_array($result); if ($row){ return($row['session_data']); //返回Session名称及内容 }else{ return(false); } } |
存储进数据库中的session_expiry是UNIX时间戳。
(4)封装session_write()函数,函数中设定Session失效时间,查找到Session名称及内容,如果查询结果为空,则将页面中Session根据session_id、session_name、失效时间插入数据库中;如果查询结果不为空,则根据$key修改数据库中Session存储信息,返回执行结果,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function _session_write($key,$data) { global $handle; $time = 60*60; //设置失效时间 $lapse_time = time() + $time; //得到UNIX时间戳 $sql = "select session_data from tb_session where session_key = '$key' and session_time > $lapse_time"; $result = mysql_query($sql,$handle); if (mysql_num_rows($result) == 0 ) { //没有结果 $sql = "insert into tb_session values('$key','$data',$lapse_time)";//插入数据库sql语句 $result = mysql_query($sql,$handle); }else{ $sql = "update tb_session set session_key = '$key',session_data = '$data',session_time = $lapse_time where session_key = '$key'"; //修改数据库sql语句 $result = mysql_query($sql,$handle); } return($result); } |
(5)封装session_destroy()函数,根据$key值将数据库中Session删除,代码如下:
1 2 3 4 5 6 7 | function _session_destroy($key) { global $handle; $sql = "delete from tb_session where session_key = '$key'"; //删除数据库sql语句 $result = mysql_query($sql,$handle); return($result); } |
(6)封装session_gc()函数,根据给出的失效时间删除过期Session,代码如下:
1 2 3 4 5 6 7 8 | function _session_gc($expiry_time) { global $handle; $lapse_time = time(); //将参数$expiry_time赋值为当前时间戳 $sql = "delete from tb_session where expiry_time < $lapse_time"; //删除数据库sql语句 $result = mysql_query($sql,$handle); return($result); } |
以上为session_set_save_handler()函数的6个参数(函数)。
至此关于PHP的Session讲解完毕。