龙空技术网

互联网系统(APP、网站等)通信基石——会话(PHP版)

核子力量 178

前言:

眼前朋友们对“通信php”大约比较注意,同学们都想要剖析一些“通信php”的相关内容。那么小编在网摘上网罗了一些有关“通信php””的相关资讯,希望同学们能喜欢,兄弟们快快来了解一下吧!

一、会话概述

1.1、技术背景

互联网通信中采用的Http协议(建立TCP连接->Http请求->Http应答->断开TCP连接)本身是无状态的,即Http各请求之间是相互独立、互不相关的,而大量应用需要将各请求关联起来(如:用户登录系统购物、多次购买行为需要与该用户绑定),因此需要有一种机制实现Http各请求之间的关联

1.2、会话定义

用户端与服务端进行网络通信,用户从登录进入系统到注销退出系统,这一完整过程称为会话(Session);会话中,用户端与服务端进行的一序列通信处理(Http请求与应答)将始终与登录的具体用户相关联

1.3、实现原理

服务端收到用户端Http请求后,先从Http请求包中获取会话ID(如果没有,将自动生成一个会话ID),根据会话ID在内存中生成对应的散列表(如:PHP中的$_SESSION[])、检索上次保存的会话记录(如果检索不到,将自动生成一条与该会话ID绑定的空会话记录),将会话记录中的数据加载到散列表,通过散列表读写当前会话数据,最后请求处理结束时将散列表中的会话数据保存为会话记录、脚本结束时将当前的会话ID放入Http应答包发送给用户端(供下次Http请求使用)

二、会话ID的传递

从上述会话实现原理可知,会话ID将一序列Http数据包(请求/应答)关联起来,从而构成一个完整的会话,整个会话过程中需要在用户端与服务端通过Http数据包传递会话ID,具体传递方式有:Cookie方式传递、URL参数方式传递、数据内容方式传递,具体如下

2.1、Cookie方式传递

2.1.1、传递原理

Http请求过程:

用户端(如:浏览器)先从本地(内存或磁盘)读取保存的对应Cookie数据(名称、值、域名等),再将读取到的相应数据填写到Http请求数据包头的Cookie字段(首次请求时,由于本地无Cookie数据,该字段为空),而后将Http请求数据包发送到服务端;服务端收到Http请求数据包后解析时,将根据当前的会话名称匹配对应的Cookie名称,如果匹配到了、则读取对应的值(会话ID)作为当前的会话ID,如果匹配不到、将自动生成一个当前的会话ID;该过程中,用户端从本地读取保存的Cookie原则为:Cookie所声明的作用范围(由其路径与域共同决定)大于等于将要请求的资源所在的位置

Http应答过程:

服务端先将当前的会话名称、会话ID等数据分别填入Http应答数据包头的Cookie字段,而后将Http应答数据包发送到用户端;用户端收到Http应答数据包进行解析,再将解析得到的Cookie数据(名称、值、域名等)进行保存(至于保存到内存还是磁盘,由具体的程序设计决定,一般原则为:如果Cookie设置了有效时间,就保存到磁盘,否则将保存到内存)

2.1.2、环境配置

用户端配置:

使用Cookie方式传递时,用户端必须开启Cookie的接受与发送功能,否则将不能实现该传递功能;不同用户端开启的方法不一样,以下为IE浏览器开启Cookie接受与发送功能的相关步骤:

菜单栏“工具”->“Internet选项”->“隐私”->“选择Internet区域设置”->选择“接受所有Cookie”->点“确定”关闭

服务端配置:

使用Cookie方式传递时,服务端必须开启Cookie的接受与发送功能(一般默认为开启状态),否则将不能实现该传递功能;开启方法如下:

方法1:配置文件“php.ini”中的“session.use_cookies”配置项设置为“1”->重新启动服务器(如:Apache)

方法2:用ini_set()函数直接在PHP脚本中将“session.use_cookies”配置项设置为“1”

2.1.3、案例演示

创建如下PHP脚本文件(ByCookie.php):

<?php

/*

* ByCookie.php

*/

//打开错误及告警提示(不打开E_NOTICE,否则下面使用$_SESSION会有告警)

error_reporting((E_ALL | E_STRICT) & (~E_NOTICE));

//error_reporting(E_ALL | E_STRICT);

//设置会话名称

session_name('TransID');

//启动新会话或者重用现有会话

$startRst = session_start();

if (!$startRst)

{

echo 'Session start fail!'.'<br>';

return ;

}

//获取当前会话名称

$sessName = session_name();

echo 'session name:'.$sessName.'<br>';

//获取当前会话ID

$sessId = session_id();

echo 'session id:'.$sessId.'<br>';

//读写当前会话数据

echo 'Last request,session data:'.$_SESSION['count'].'<br>';

if (empty($_SESSION['count']))

{

$_SESSION['count'] = 1;

}

else

{

$_SESSION['count']++;

}

echo 'This request,session data:'.$_SESSION['count'].'<br>';

?>

在浏览器中用多个页面顺序打开上述“ByCookie.php”文件多次,便可以看到被多次传递的同一个会话ID及相关数据,结果如下:

2.2、URL参数方式传递

2.2.1、传递原理

首次请求时,服务端将当前的会话名称及会话ID放入Http应答数据包响应正文(作为参数附加到URL后)中发送到用户端;用户端通过URL触发连接请求(如:点击链接或提交表单)时,会话名称及会话ID被填写到Http请求数据包头的URL字段(作为参数附加到URL后),而后将Http请求数据包发送到服务端;服务端收到Http请求数据包后,通过$_GET[]全局变量即可得到请求数据包头URL字段中的参数(会话名称及会话ID);如果还有需要,服务端再将会话名称及会话ID放入Http应答数据包响应正文(作为参数附加到URL后)中发送到用户端、供用户端再次通过URL触发连接请求

2.2.2、案例演示

在同一目录下创建如下2个PHP脚本文件(ByURLSend.php及ByURLRcve.php):

文件1(ByURLSend.php):

<?php

/*

* ByURLSend.php

*/

//打开错误及告警提示(不打开E_NOTICE,否则下面使用$_SESSION会有告警)

error_reporting((E_ALL | E_STRICT) & (~E_NOTICE));

//error_reporting(E_ALL | E_STRICT);

//设置会话名称

session_name('TransID');

//启动新会话或者重用现有会话

$startRst = session_start();

if (!$startRst)

{

echo 'Session start fail!'.'<br>';

return ;

}

//获取当前会话名称

$sessName = session_name();

echo 'session name:'.$sessName.'<br>';

//获取当前会话ID

$sessId = session_id();

echo 'session id:'.$sessId.'<br>';

//读写当前会话数据

echo 'Last request,session data:'.$_SESSION['count'].'<br>';

if (empty($_SESSION['count']))

{

$_SESSION['count'] = 1;

}

else

{

$_SESSION['count']++;

}

echo 'This request,session data:'.$_SESSION['count'].'<br>';

?>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<p>

<!-- URL参数方式传递(方法1):使用链接,URL后附加参数(当前的会话名称及会话ID) -->

<a href="ByURLRcve.php?<?=session_name();?>=<?=session_id();?>">URL参数方式传递(方法1)</a>

</p>

<!-- URL参数方式传递(方法2):使用表单,URL后附加参数(当前的会话名称及会话ID) -->

<form id="form1" name="form1" method="post" action="ByURLRcve.php?<?=session_name();?>=<?=session_id();?>">

<input type="submit" name="Submit" value="URL参数方式传递(方法2)" />

</form>

<p>

<!-- URL参数方式传递(方法3):使用链接,URL后附加参数(SID常量);如果客户端未开启会话cookie,该常量的展开格式为“session_name=session_id”,

如果客户端已开启会话cookie,该常量可能为空字符串(是否为空字符串,与具体客户端的设计相关);这里用htmlspecialchars()函数打印 SID常量的展开字符串,目

的是为了避免XSS相关的攻击 -->

<a href="ByURLRcve.php?<?php echo htmlspecialchars(SID);?>">URL参数方式传递(方法3)</a>

</p>

文件2(ByURLRcve.php):

<?php

/*

* ByURLRcve.php

*/

//打开错误及告警提示(不打开E_NOTICE,否则下面使用$_SESSION会有告警)

error_reporting((E_ALL | E_STRICT) & (~E_NOTICE));

//error_reporting(E_ALL | E_STRICT);

//设置会话名称

session_name('TransID');

//获取当前会话名称

$sessName = session_name();

//获取当前会话ID

$sessId = $_GET[$sessName];

if ('' == $sessId)

{

echo 'Session id transmits fail!'.'<br>';

return ;

}

//设置当前会话ID

session_id($sessId);

//启动新会话或者重用现有会话

$startRst = session_start();

if (!$startRst)

{

echo 'Session start fail!'.'<br>';

return ;

}

//获取当前会话名称

$sessName = session_name();

echo 'session name:'.$sessName.'<br>';

//获取当前会话ID

$sessId = session_id();

echo 'session id:'.$sessId.'<br>';

//读写当前会话数据

echo 'Last request,session data:'.$_SESSION['count'].'<br>';

if (empty($_SESSION['count']))

{

$_SESSION['count'] = 1;

}

else

{

$_SESSION['count']++;

}

echo 'This request,session data:'.$_SESSION['count'].'<br>';

?>

在浏览器中打开“ByURLSend.php”,便能看到如下结果:

点击不同的链接,便可以看到在不同页面间传递的同一个会话ID及相关数据

2.3、数据内容方式传递

2.3.1、传递原理

首次请求时,服务端将当前的会话名称及会话ID放入Http应答数据包响应正文(通常以字段值的方式放置)中发送到用户端;用户端通过POST方法触发Http请求时,会话名称及会话ID作为Http请求数据包的请求数据发送到服务端;服务端收到Http请求数据包后,直接解析Http请求数据包的请求数据即可得到会话名称及会话ID;如果还有需要,服务端再将会话名称及会话ID放入Http应答数据包响应正文(通常以字段值的方式放置)中发送到用户端、供用户端再次POST方法触发Http请求

2.3.2、案例演示

在同一目录下创建如下2个PHP脚本文件(ByDataSend.php及ByDataRcve.php):

文件1(ByDataSend.php):

<?php

/*

* ByDataSend.php

*/

//打开错误及告警提示(不打开E_NOTICE,否则下面使用$_SESSION会有告警)

error_reporting((E_ALL | E_STRICT) & (~E_NOTICE));

//error_reporting(E_ALL | E_STRICT);

//设置会话名称

session_name('TransID');

//重用现有会话;

$startRst = session_start();

if (!$startRst)

{

echo 'Session start fail!'.'<br>';

return ;

}

//获取当前会话名称

$sessName = session_name();

echo 'session name:'.$sessName.'<br>';

//获取当前会话ID

$sessId = session_id();

echo 'session id:'.$sessId.'<br>';

//读写当前会话数据

echo 'Last request,session data:'.$_SESSION['count'].'<br>';

if (empty($_SESSION['count']))

{

$_SESSION['count'] = 1;

}

else

{

$_SESSION['count']++;

}

echo 'This request,session data:'.$_SESSION['count'].'<br>';

?>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<!-- 数据内容方式传递:直接作为数据内容字段传递 -->

<form id="form1" name="form1" method="post" action="ByDataRcve.php">

<input type="hidden" name="<?=session_name();?>" value="<?=session_id();?>" />

<input type="submit" name="Submit" value="数据内容方式传递" />

</form>

文件2(ByDataRcve.php):

<?php

/*

* ByDataRcve.php

*/

//打开错误及告警提示(不打开E_NOTICE,否则下面使用$_SESSION会有告警)

error_reporting((E_ALL | E_STRICT) & (~E_NOTICE));

//error_reporting(E_ALL | E_STRICT);

//设置会话名称

session_name('TransID');

//获取当前会话名称

$sessName = session_name();

//获取当前会话ID

$sessId = $_POST[$sessName];

if ('' == $sessId)

{

echo 'Session id transmits fail!'.'<br>';

return ;

}

//设置当前会话ID

session_id($sessId);

//重用现有会话;

$startRst = session_start();

if (!$startRst)

{

echo 'Session start fail!'.'<br>';

return ;

}

//获取当前会话名称

$sessName = session_name();

echo 'session name:'.$sessName.'<br>';

//获取当前会话ID

$sessId = session_id();

echo 'session id:'.$sessId.'<br>';

//读写当前会话数据

echo 'Last request,session data:'.$_SESSION['count'].'<br>';

if (empty($_SESSION['count']))

{

$_SESSION['count'] = 1;

}

else

{

$_SESSION['count']++;

}

echo 'This request,session data:'.$_SESSION['count'].'<br>';

?>

在浏览器中打开“ByDataSend.php”,便能看到如下结果:

点击“数据内容方式传递”按钮,便可以看到在不同页面间传递的同一个会话ID

标签: #通信php