PHP5 session 详解【经典】

原文:http://www.pkwind.com/php5-session-xiang-jie-jing-dian

http协议是WEB服务器与客户端
(浏览器)相互通信的协议,它是一种无状态协议。所谓无状态,指的是不会维护http请求数据,http请求是独立的,不持久的。而越来越复杂的WEB应
用,需要保存一些用户状态信息。这时候,Session这种方案应需而生。PHP从4.1开始支持Session管理。

session是很抽象的一个概念。我们不妨先从与它几个息息相关的有迹可寻的小切入点入手,然后逐渐地认识了解它。

session存储

首先,我们为什么需要Session,就是因为我们需要:存储各个用户的状态数据。那么试问,如果由你来设计解决这个需求的方案,那么也许你会设置这样一个数据表用与存储各个用户的状态信息:






















uid created data max_age
94c55770fdf044a7 1270802787 jtUsername=admin 14400
2c37df64277e4409 1270822787 jtUsername=Joe;jtBooks=8; 14400

uid : 用户唯一标识符,区分其它用户 created : 记录产生时间
data : 存放与用户相关的数据 max_age :
记录的有效时间

同样地,PHP设计管理session方案也大致如此,它分别包含了以下信息:

1,session id
用户session唯一标识符,随机生成的一串字符串,具有唯一性,随机性。主要用于区分其它用户的session数据。用户第一次访问web页面的时候,php的session初始化函数调用会分配给当前来访用户一个唯一的ID,也称之为session_id。

2,session data

我们把需要通过session保存的用户状态信息,称为用户session数据,也称为session数据。一般是在当前session生命周期,相应用的$_SESSION数据。

3,session file

PHP默认将session数据存放在一个文件里。我们把存放session数据的文件称为session文件。它由特殊的php.ini设置
session.save_path指定session文件的存放路径,CentOS5.3操作系统,PHP5.1默认存放在/var/lib/php
/session目录中。用户session文件的名称,就是以sess_为前缀,以session_id为结尾命名,比如session
id为vp8lfqnskjvsiilcp1c4l484d3,那么session文件名就是
sess_vp8lfqnskjvsiilcp1c4l484d3

4,session lifetime

我们把初始化session开始,直到注销session这段期间,称为session生命周期,这样有助于我们理解session管理函数。

由此,我们可见:当每个用户访问web, PHP的session初始化函数都会给当前来访用户分配一个唯一的session
ID。并且在session生命周期结束的时候,将用户在此周期产生的session数据持久到session文件中。用户再次访问的时
候,session初始化函数,又会从session文件中读取session数据,开始新的session生命周期。

与session存储相关php.ini设置

1,session.save_handler = file

用于读取/回写session数据的方式,默认是files。它会让PHP的session管理函数使用指定的文本文件存储session数据

2,session.save_path = “/var/lib/php/session”

指定保存session文件的目录,可以指定到别的目录,但是指定目录必须要有httpd守护进程属主(比如apache或www等)写权限,否则无法回
存session数据。当指定目录不存在时,php session环境初始化函数是不会帮你创建指定目录的,所以需要你手工建立指定目录。

它还可以写成这样session.save_path = “N;/path”
其中N是整数。这样使得不是所有的session文件都保存在同一个目录中,而是分散在不同目录。这对于服务器处理大量session文件是很有帮助的。(注:目录需要自己手工创建)

3,session.auto_start = 0

如果启用该选项,用户的每次请求都会初始化session。我们推荐不启用该设置,最好通过session_start()显示地初始化session。

Session同步数据

一旦调用了session_start()初始化session,就意味着开始了一个session生命周期。也就是宣布了,可以使用相关函数操
作$_SESSION来管理session数据。这个session生命周期产生的数据并没有实时地写入session文件,而是通过$_SESSION
变量寄存在内存中。那么,寄存在内存的数据什么时候会写入到session文件?这也是我们这一小节的主要测试内容。

在进行测试之前,先让我们介绍几个影响session数据的PHP函数、或事件

1,session_start()

函数session_start会初始化session,也标识着session生命周期的开始。要使用session,必须初始化一个session环境。有点类似于OOP概念中调用构造函数构创建对象实例一样。

session初始化操作,声明一个全局数组$_SESSION,映射寄存在内存的session数据。如果session文件已经存在,并且保存有
session数据,session_start()则会读取session数据,填入$_SESSION中,开始一个新的session生命周期。

2,$_SESSION

它是一个全局变量,类型是Array,映射了session生命周期的session数据,寄存在内存中。在session初始化的时候,从session文件中读取数据,填入该变量中。在session生命周期结束时,将$_SESSION数据写回session文件。

3, session_register()

在session生命周期内,使用全局变量名称将注全局变量注册到当前session中。所谓注册,就是将变量填入$_SESSION中,值为NULL。
它不会对session文件进行任何IO操作,只是影响$_SESSION变量。注意,它的正确写法是
session_register(‘varname’),而不是session_register($varname)

4, session_unregister()

与session_register操作正好相反,即在session生命周期,从当前session注销指定变量。同样只影响$_SESSION,并不进行任何IO操作。

5,session_unset()

在session生命周期,从当前session中注销全部session数据,让$_SESSION成为一个空数组。它与
unset($_SESSION)的区别在于:unset直接删除$_SESSION变量,释放内存资源;另一个区别在
于,session_unset()仅在session生命周期能够操作$_SESSION数组,而unset()则在整个页面(page)生命周期都能
操作$_SESSION数组。session_unset()同样不进行任何IO操作,只影响$_SESSION数组。

6,session_destroy()

如果说session_start()初始化一个session的话,而它则注销一个session。意味着session生命周期结束了。在
session生命周期结整后,session_register, session_unset,
session_register都将不能操作$_SESSION数组,而$_SESSION数组依然可以被unset()等函数操作。这
时,session意味着是未定义的,而$_SESSION依然是一个全局变量,他们脱离了关映射关系。

通过session_destroy()注销session,除了结束session生命周期外,它还会删除sesion文件,但不会影响当前$_SESSION变量。即它会产生一个IO操作。

7,session_regenerate_id()
调用它,会给当前用户重新分配一个新的session
id。并且在结束当前页面生命周期的时候,将当前session数据写入session文件。前提是,调用此函数之前,当前session生命周期没有被
终止(参考第9点)。它会产生一个IO操作,创建一个新的session文件,创建新的session文件的是在session结束之前,而不是调用此函
数就立即创建新的session文件。

8, session_commit()

session_commit()函数是session_write_close()函数的别名。它会结束当前session的生命周期,并且将
session数据立即强制写入session文件。不推荐通过session_commit()来手工写入session数据,因为PHP会在页面生命
周期结束的时候,自动结束当前没有终止的session生命周期。它会产生一个IO写操作

9,end session

结束session,默认是在页面生命周期结束的之前,PHP会自动结束当前没有终止的session。但是还可以通过session_commit()
与session_destroy()二个函数提前结束session。不管是哪种方式,结束session都会产生IO操作,分别不一样。默认情况,产
生一个IO写操作,将当前session数据写回session文件。session_commit()则是调用该函数那刻,产生一个IO写操作,将
session数据写回session文件。而session_destroy()不一样在于,它不会将数据写回session文件,而是直接删除当前
session文件。有趣的是,不管是session_commit(),还是session_destroy()都不会清空$_SESSION数组,更
不会删除$_SESSION数组,只是所有session_*函数不能再操作session数据,因为当前的session生命周期终止了,即不能操作一
个未定义对象。

为了验证以上陈述,我们可以做以下测试

任务1观察session初始化与默认结束session的时候,产生的IO操作




 <?php
//@file test_session_2.php
session_start();
$pg_uuid = ‘ac606826-9620-490b-b850-ea9dbce6cfd5‘;
//注册全局变量pg_uuid到session,但$_SESSION[‘pg_uuid‘]值为NULL,只影响$_SESSION
session_register(‘pg_uuid‘);
var_dump($_SESSION);
fopen(__FILE__, "r");

[[email protected] ~]# strace -p `cat /var/run/httpd.pid` 





 Process 21819 attached – interrupt to quit
...
st_mode=S_IFREG|0644, st_size=72, ...}) = 0
open("/var/www/html/test_session.php", O_RDONLY) = 17
fstat64(17, {st_mode=S_IFREG|0644, st_size=72, ...}) = 0
lseek(17, 0, SEEK_CUR) = 0
read(17, "<p;?php\n//@file test_session.php\ns"..., 8192) = 72
read(17, "", 8192) = 0
read(17, "", 8192) = 0
close(17) = 0
gettimeofday({1270906664, 11602}, NULL) = 0
open("/var/lib/php/session/sess_4j38nv7l1fq1bj6n80l6g9cum5", O_RDWR|O_CREAT, 0600) = 17
flock(17, LOCK_EX) = 0
fcntl64(17, F_SETFD, FD_CLOEXEC) = 0
fstat64(17, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
time(NULL) = 1270906664
open("/var/www/html/test_session.php", O_RDONLY) = 18
fstat64(18, {st_mode=S_IFREG|0644, st_size=72, ...}) = 0
lseek(18, 0, SEEK_CUR) = 0
close(18) = 0
chdir("/var/lib/php/session") = 0
pwrite64(17, "", 0, 0) = 0
close(17) = 0
setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={0, 0}}, NULL) = 0
writev(16, [{"HTTP/1.1 200 OK\r\nDate: Sat, 10 A"..., 385}], 1) = 385
write(12, "192.168.0.98 - - [10/Apr/2010:21"..., 207) = 207
shutdown(16, 1 /* send */) = 0
epoll_wait(15,

蓝色加粗,通过系统内核函数open调
用打开session文件,这是由session_start()产生的调用,注意这里并没有产生读文件操作。红色部分,将一个空字符串写入
session文件。由此可见session初始化在页面生命周期开始之时,手工调用session_start可以初始化session文件,而在页面
生命周期结束之时,会自动地注销session,结束当前session生命周期,同时在此周期产生的session数据写回session文件,我们把
这种方式结束的session,称为session默认结束。

任务2观察session_register()查看它是否会产生磁盘操作,还是只操作$_SESSION。




 <?php

//@file test_session_2.php

session_start();

$pg_uuid = ‘ac606826-9620-490b-b850-ea9dbce6cfd5‘;

session_register(‘pg_uuid‘);
//注册全局变量pg_uuid到session,但值为NULL,只影响$_SESSION

var_dump($_SESSION);

fopen(__FILE__, "r");

[[email protected] ~]# strace -p `cat
/var/run/httpd.pid`

Process 21819 attached - interrupt to quit

...

open("/var/www/html/test_session_2.php", O_RDONLY) =
17

fstat64(17, {st_mode=S_IFREG|0644, st_size=148, ...}) =
0

lseek(17, 0, SEEK_CUR)          
       = 0

read(17, "<?php\nsession_start();\n$pg_uuid "..., 8192) =
148

read(17, "", 8192)            
         = 0

read(17, "", 8192)            
         = 0

close(17)              
                = 0

open("/var/lib/php/session/sess_4j38nv7l1fq1bj6n80l6g9cum5",
O_RDWR|O_CREAT, 0600) = 17

flock(17, LOCK_EX)            
         = 0

fcntl64(17, F_SETFD, FD_CLOEXEC)        =
0

fstat64(17, {st_mode=S_IFREG|0600, st_size=0, ...}) =
0

time(NULL)              
               =
1270907613

open("/var/www/html/test_session_2.php", O_RDONLY) =
18

fstat64(18, {st_mode=S_IFREG|0644, st_size=148, ...}) =
0

lseek(18, 0, SEEK_CUR)          
       = 0

close(18)              
                = 0

chdir("/var/lib/php/session")        
  = 0

pwrite64(17, "pg_uuid|N;", 10, 0)       =
10

close(17)              
                = 0

setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={0,
0}}, NULL) = 0

writev(16, [{"HTTP/1.1 200 OK\r\nDate: Sat, 10 A"..., 328},
{"array(1) {\n  [\"pg_uuid\"]=>\n  NUL"..., 36}], 2) =
364

write(12, "192.168.0.98 - - [10/Apr/2010:21"..., 210) =
210

shutdown(16, 1 /* send */)          
   = 0

epoll_wait(15,

通过上面的观察,蓝色部分还是由
session初始化(session_start)产生,注意这里依然没读文件操作,这是因为session文件为空。红色部分,依然是默认结束
session产生的文件写操作(pwrite)。由此,我们可以知道session_register()不会对session文件操作,即不会
把$_SESSION中的数据写回session文件,它没有产生任何IO操作。而只在session生命周期是影响当前$_SESSION变量,
即$_SESSION[‘pg_uuid’] = NULL。所以,推荐使用$_SESSION[‘pg_uuid’] = $pg_uuid;

任务3观察session_destroy()与session_unset()的区别




 <?php

session_start();

echo "<br/>---1--<br/>";

$pg_uid = 1;

//$_SESSION[‘pg_uid‘]; //该行会报一个Notice消息,即没有初始化该变量

$_SESSION[‘pg_name‘] = ‘boys‘;
//填入到$_SESSION变量,但不立即写入session文件,值为boys

$pg_sex = 1;

$pg_theme = ‘default‘;

session_register(‘pg_sex‘);
//填入到$_SESSION变量,但不立即写入session文件,值为NULL

session_register(‘pg_theme‘);
//填入到$_SESSION变量,但不立即写入session文件,值为NULL

var_dump($_SESSION);

//--

echo "<br/>---2--<br/>";

unset($_SESSION[‘pg_theme‘]);
//从$_SESSION清除该元素,不立即同步到session文件

unset($_SESSION[‘pg_name‘]);
//从$_SESSION清除该元素,不立即同步到session文件

session_unregister(‘pg_sex‘);
//从$_SESSION清除该元素,不立即同步到session文件

session_unregister(‘pg_uid‘);
//从$_SESSION清除该元素,不立即同步到session文件

var_dump($_SESSION);

echo "<br/>---3--<br/>";

$_SESSION[‘pg_members‘] = 5;
//填入$_SESSION数组,但不立即同步到session文件,值为5

$pg_boy = 6;

session_register(‘pg_boy‘);
//填入$_SESSION数组,但不立即同步到session文件,值为NULL

session_unset($_SESSION); //清空$_SESSION

var_dump($_SESSION);

echo "<br/>---4--<br/>";

$_SESSION[‘pg_boss‘] = 3;
//填入$_SESSION数组,但不立即同步到session文件,值为3

$pg_girls = 6;

session_register(‘pg_girls‘);
//填入$_session数组,但不立即同步到session文件,值为NULL

session_destroy(); //注销session_destroy

var_dump($_SESSION);

echo "<br/>---5---<br/>";

session_unregister(‘pg_boss‘);
//pg_boss不会被清除,还为NULL

session_unset();
//不会清空$_SESSION数组,因为session已被session_destroy注销

var_dump($_SESSION);

fopen(__FILE__, "r");

//@这里是页面析构的时候-- 本应该将$_SESSION数据同步到session文件, 真的吗???

//@事实,没有发生任何IO操作,即没有将$_SESSION数据回写,怎么回事???

//@因为被session_destroy()消毁了session...

程序输出:




 ---1--

array(3) { ["pg_name"]=> string(4) "boys" ["pg_sex"]=>
NULL ["pg_theme"]=> NULL }

---2--

array(0) { }

---3--

array(0) { }

---4--

array(2) { ["pg_boss"]=> int(3) ["pg_girls"]=> NULL
}

---5---

array(2) { ["pg_boss"]=> int(3) ["pg_girls"]=> NULL
}

[[email protected] ~]# strace -p `cat /var/run/httpd.pid`




 Process 21819 attached - interrupt to quit

...

open("/var/www/html/test_session_3.php", O_RDONLY) =
17

fstat64(17, {st_mode=S_IFREG|0644, st_size=706, ...}) =
0

lseek(17, 0, SEEK_CUR)          
       = 0

read(17, "<?php\nsession_start();\necho \"<br"..., 8192)
= 706

read(17, "", 8192)            
         = 0

read(17, "", 8192)            
         = 0

close(17)              
                = 0

open("/var/lib/php/session/sess_4j38nv7l1fq1bj6n80l6g9cum5",
O_RDWR|O_CREAT, 0600) = 17

flock(17, LOCK_EX)            
         = 0

fcntl64(17, F_SETFD, FD_CLOEXEC)        =
0

fstat64(17, {st_mode=S_IFREG|0600, st_size=10, ...}) =
0

pread64(17, "pg_uuid|N;", 10, 0)        =
10

close(17)              
                = 0

unlink("/var/lib/php/session/sess_4j38nv7l1fq1bj6n80l6g9cum5")
= 0

time(NULL)              
               =
1270910665

open("/var/www/html/test_session_3.php", O_RDONLY) =
17

fstat64(17, {st_mode=S_IFREG|0644, st_size=706, ...}) =
0

lseek(17, 0, SEEK_CUR)          
       = 0

close(17)              
                = 0

chdir("/var/lib/php/session")        
  = 0

setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={0, 0}},
NULL) = 0

...

write(12, "192.168.0.98 - - [10/Apr/2010:22"..., 211) =
211

shutdown(16, 1 /* send */)          
   = 0

蓝色部分是我们熟悉的session初
始化的时候产生的open系统内核调用。绿色部分,是一个IO读操作,因为上一次访问页面的时候,产生了session数据,所以这一次会将上次的
session填入$_SESSION中。红色部分,可以看出,这里调用unlink删除session文件,而且后面(页面生命周期结束时),一直没有
看到前两例看到的任何与session文件有关的IO写操作,即没有将$_SESSION中的数据写回session文件。我们也没有在
session.save_path找到相应的session文件

[[email protected] html]# ls /var/lib/php/session/sess_4j38nv7l1fq1bj6n80l6g9cum5 ls: /var/lib/php/session/sess_4j38nv7l1fq1bj6n80l6g9cum5: No such file or directory

注: 虽然删除了session文件,但用户再次访问web的时候,并不会给用户重新分配一个新的session id,而是依然用该session
id,并且会重新创建文件名相同的session文件,即sess_SESSION-ID

任务4测试并观察session_regenerate_id行为,以及$_SESSION的变化




 <?php
session_start(); $_SESSION[‘pfid‘] = 123; var_dump($_SESSION); session_regenerate_id(); var_dump($_SESSION); fopen(__FILE__, "r");

[[email protected] ~]# strace -p `cat /var/run/httpd.pid` 




 Process 22641 attached – interrupt to quit
... open("/var/www/html/test_session_4.php", O_RDONLY) = 17 fstat64(17, {st_mode=S_IFREG|0644, st_size=141, ...}) = 0 lseek(17, 0, SEEK_CUR) = 0 read(17, "<?php\nsession_start();\n$_SESSION"..., 8192) = 141 read(17, "", 8192) = 0 read(17, "", 8192) = 0 close(17) = 0 open("/var/lib/php/session/sess_4j38nv7l1fq1bj6n80l6g9cum5", O_RDWR|O_CREAT, 0600) = 17 flock(17, LOCK_EX) = 0 fcntl64(17, F_SETFD, FD_CLOEXEC) = 0 fstat64(17, {st_mode=S_IFREG|0600, st_size=11, ...}) = 0 pread64(17, "pfid|i:123;", 11, 0) = 11 gettimeofday({1270915896, 122016}, NULL) = 0 time(NULL) = 1270915896 open("/var/www/html/test_session_4.php", O_RDONLY) = 18 fstat64(18, {st_mode=S_IFREG|0644, st_size=141, ...}) = 0 lseek(18, 0, SEEK_CUR) = 0 close(18) = 0 chdir("/var/lib/php/session") = 0 close(17) = 0 open("/var/lib/php/session/sess_qoa6knu9fg77un8le99o1vk1c7", O_RDWR|O_CREAT, 0600) = 17 flock(17, LOCK_EX) = 0 fcntl64(17, F_SETFD, FD_CLOEXEC) = 0 pwrite64(17, "pfid|i:123;", 11, 0) = 11 close(17) = 0 setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={0, 0}}, NULL) = 0 writev(16, [{"HTTP/1.1 200 OK\r\nDate: Sat, 10 A"..., 386}, {"array(1) {\n [\"pfid\"]=>\n int(12"..., 75}], 2) = 461 write(12, "192.168.0.98 - - [11/Apr/2010:00"..., 210) = 210 shutdown(16, 1 /* send */) = 0

观察测试结果,蓝色部分照旧是
session初始化的时候产生的系统内核open调用,接着绿色部分是一个IO读操作,即读取session文件中的数据,由第一个
var_dump($_SESSION)输出。随后,往session加入新的一条已定义了的session记录,并且通过
session_commit()将记录写回去。红色部分就是由session_commit产生的一次IO写操作。之
后,session_unset()并没有生效,同时,我们也没有在页面生命周期结束的时候看到任何与session文件有关的IO写操作。这也正说明
了,session_commit()调用的当下,就会将session数据写回session文件,并且会像session_destroy一样注销
session,但与session_destroy不同的时,session_commit不会删除session文件,而且会将当前的session
数据写回session文件。我们可以查看,调用session_commit之后,session文件还是依然存在的

[[email protected] html]# ls -lt /var/lib/php/session 
 -rw------- 1 apache apache 31 Apr 11 03:18 sess_qoa6knu9fg77un8le99o1vk1c7  
 -rw------- 1 apache apache 11 Apr 11 00:08 sess_4j38nv7l1fq1bj6n80l6g9cum5 …

总结:

1, 用户注销web应用系统,最好的调用方式依次是 session_unset();  session_destroy();
 unset($_SESSION);




 <?php
function user_sigout() {
 global $user; sys_event_register(‘user_sigout‘, $user); session_unset(); //清空session session_destroy(); //删除session文件 if (isset($_SESSION)) { unset($_SESSIONI); //注销$_SESSION } return TRUE; }

2,
尽量将键与值填入$_SESSION,而不推荐使用session_register()。同样,尽量使用unset($_SESSION[‘var’]),而不使用session_unregister()。

3,
对于可能产生大量session的WEB应用,推荐使用的session.save_path的格式是session.save_path=”N:/path”。注意:这些目录需要手工创建,并且有httpd守护进程属主写权限。这样做可以获得更好的性能

4, 如果调用了session_regenerate_id()给用户分配了新的session
id。该函数并不会主动删除旧的session文件,需要定时清理旧的session文件,这样更优化。

5,
尽量不要使用session_commit()提交sessioin数据,因为它同时会结束当前session,PHP默认会在页面生命周期的时候提交session数据到session文件

Session ID传递

session终究是因为管理用户状态 信息才存在的。我们曾探讨过session id的意义:每个来访问用户都会被分配一个唯一的session
id,用于区分其它用户的session数据。换句话说,session id是用户表明身份的一种标识,就像入场券一样。用户一旦从被分配了session
id之后的每次访问(http请求)都会携带这个session
id给服务端,用于加载该用户的session数据。那么,通过什么方式传给服务端?这是我们这节探讨的内容。

用户端与服务端的web通信协议是
http。而PHP通过http取得用户数据惯用的三种方法分别是:POST方法、GET方法还有Cookie。而PHP默认传递方法正是Cookie,
也是最佳方法。只有在客户端不支持Cookie的时候(浏览器禁用了Cookie功能)才会通过GET方法来传递session_id,即通过在URL的
query_string部分传递session id。

确定了传递方法,我们还有必要清楚一下session
id的传递过程。用户通过浏览器访问网页,将URL输入地址栏回车,浏览器发出请求,在调用sockect
send之前浏览器引擎会搜索有效的Cookies记录封装在http请求头的Cookie字段,一同发送出去。服务端器接收到请求后,交给PHP处理。
这时,session初始化函数如果在$_COOKIE中没有找到以session_name()作为键值存储的生素(值为session
id),则会以为用户是第一次访问web。作为第一次访问的用户,session初始化函数总会随机生成一个session_id并且通过
setcookie()函数调用将新生成的session_id以”sesseson_name =
session_id”的格式填入http响应头Set-Cookie字段,发送给客户端(这样接下来的请求,http请求头Cookie字段都会携带该
Cookie记录给web服务器)。如果初始化函数发现用户端Cookies中已定义了存在$_COOKIE[‘sess_name’],则会加载
与$_COOKIE[‘sess_name’]相对应的session文件($_COOKIE[‘sess_name’]就是session
ID)。如果用户Cookie记录过期,则会被浏览器删除。之后的下一次请求,服务器会以为用户又是第一次访问,如此循环。

让我们通过测与来验证以上的陈述




 <?php//p1.php

session_start();

通过截取到的http数据包如下
#
T 192.168.0.98:2290 -<
192.168.0.8:8080 [AP]
GET /a.php HTTP/1.1..Host:
192.168.0.8:8080..Connection: keep-alive..User-Agent: Mozilla/5.0
(Windows; U; Windows NT 5.1
; en-US) AppleWebKit/533.2 (KHTML, like
Gecko) Chrome/5.0.342.3 Safari/533.2..Accept:
application/xml,application/xhtml+

xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5..Accept-Encoding:
gzip,deflate,sdch..Accept-Language: zh-CN,zh;
q=0.8..Accept-Charset:
GBK,utf-8;q=0.7,*;q=0.3….
##
T 192.168.0.8:8080 -<
192.168.0.98:2290 [AP]
HTTP/1.1 200 OK..Date: Mon, 12 Apr 2010 08:25:11
GMT..Server: Apache/2.2.3 (CentOS)..X-Powered-By:
PHP/5.1.6..Set-Cookie
: PHPSESSID=bk7655dqrm5m884c9nitfi7j00;
path=/..Expires: Thu, 19 Nov 1981 08:52:00 GMT..Cache-Control: no-store,
no-cach
e, must-revalidate, post-check=0, pre-check=0..Pragma:
no-cache..Content-Length: 0..Connection: close..Content-Type: tex

t/html; charset=UTF-8….

##

第一次访问/a.php的时候,请求包
里面没有设置任何Cookie,所以这里的Cookie字段为空。当然服务器php也就得不到的$_COOKIE[‘PHPSESSID’](即session
id为空)。如此,服务器会以为用户是第一次访问web。所以session初始化的时候,会给用户分配一个唯一的session_id并且以
Cookie的方法传回给了用户端。

我们再来观察第二次请求与响应,会有哪些变化:




 #
T 192.168.0.98:2314 -< 192.168.0.8:8080 [AP]
GET
/a.php HTTP/1.1..Host: 192.168.0.8:8080..Connection:
keep-alive..User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1
;
en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.3
Safari/533.2..Cache-Control: max-age=0..Accept: applicat

ion/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5..Accept-Encoding:
gzip,deflate,sdch..
Accept-Language: zh-CN,zh;q=0.8..Accept-Charset:
GBK,utf-8;q=0.7,*;q=0.3..Cookie:
PHPSESSID=bk7655dqrm5m884c9nitfi7j00..
..
##
T 192.168.0.8:8080
-< 192.168.0.98:2314 [AP]
HTTP/1.1 200 OK..Date: Mon, 12 Apr 2010
08:32:13 GMT..Server: Apache/2.2.3 (CentOS)..X-Powered-By:
PHP/5.1.6..Expires: T
hu, 19 Nov 1981 08:52:00 GMT..Cache-Control:
no-store, no-cache, must-revalidate, post-check=0, pre-check=0..Pragma:
no-
cache..Content-Length: 0..Connection: close..Content-Type:
text/html; charset=UTF-8….

##

首先,我们观察http请求,加红色部分是第一次http请求头没有出现的内容。我们可以看到,该Cookie正是第一次访问,服务端通过Set-
Cookie要求浏览器设置的Cookie。它们是一样的,即session_id为bk7655dqrm5m884c9nitfi7j00。然后,我们
再观察这次的http响应,明显没有再要求用户端设置键为session_name()的Cookie了。

我们再来测试伪造一个session_id发送给服务,观察服务端响应。我们写一个测试脚本,如下:




 <?php
$host = ‘192.168.0.8‘; $port = 8080; $path = ‘/p1.php‘; $sid = "PHPSESSID=dk7655dqrm5m884c9nitfi7j00"; $fp = fsockopen($host, $port, $error_no, $error_desc, 30); if ($fp) { fputs($fp, "GET {$path} HTTTP/1.1\r\n"); fputs($fp, "Host: {$host}\r\n"); fputs($fp, "Cookie: {$sid}\r\n"); fputs($fp, "Connection: close\r\n\r\n"); while (!feof($fp)) { $d .= fgets($fp, 4096); } fclose(); echo $d; }

抓到的http请求、响应数据包如下:




 #
T 192.168.0.98:2400 -< 192.168.0.8:8080 [AP]
GET
/p1.php HTTTP/1.1..
Host: 192.168.0.8..Cookie:
PHPSESSID=dk7655dqrm5m884c9nitfi7j00..Connection: close….
##
T
192.168.0.8:8080 -< 192.168.0.98:2400 [AP]
HTTP/1.1 200 OK..Date:
Mon, 12 Apr 2010 09:03:09 GMT..Server: Apache/2.2.3
(CentOS)..X-Powered-By: PHP/5.1.6..Expires: T
hu, 19 Nov 1981 08:52:00
GMT..Cache-Control: no-store, no-cache, must-revalidate, post-check=0,
pre-check=0..Pragma: no-
cache..Content-Length: 11..Connection:
close..Content-Type: text/html; charset=UTF-8….hello
world

##

上面的session_id是用户端伪造的一个值,它并不实际存在。收到这样的请求,服务端并没有检查,而是以这个session_id创建了相应的
session文件。并且,从httpd响应头部信息来看,并没给用户端分配session
id(没有Set-Cookie)。由此,我们可以推断:只要http请求头部包含了以session_name()作为键值的Cookie,那么服务端
就不认为用户是第一次访问web,亦不会给客户端分配session_id。否则,分配新的session_id,并通过Set-Cookie要求浏览器
创建该Cookie.
我们再来观察一下,通过session_regenerate_id()函数给用户分配一个新的session_id的情况




 <?php//@file: p2.php

session_start();

session_regenerate_id();

抓取到的http数据包如下




 ####
T 192.168.0.98:2763 -< 192.168.0.8:8080 [AP]
GET
/p2.php HTTP/1.1..Host: 192.168.0.8:8080..Connection:
keep-alive..User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.
1;
en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.3
Safari/533.2..Cache-Control: max-age=0..Accept: applica

tion/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5..Accept-Encoding:
gzip,deflate,sdch.
.Accept-Language: zh-CN,zh;q=0.8..Accept-Charset:
GBK,utf-8;q=0.7,*;q=0.3..Cookie: PHPSESSID=bk7655dqrm5m884c9nitfi7j00.

… ##
T 192.168.0.8:8080 -< 192.168.0.98:2763 [AP]
HTTP/1.1 200
OK..Date: Mon, 12 Apr 2010 11:39:10 GMT..Server: Apache/2.2.3
(CentOS)..X-Powered-By: PHP/5.1.6..Expires: T
hu, 19 Nov 1981 08:52:00
GMT..Cache-Control: no-store, no-cache, must-revalidate, post-check=0,
pre-check=0..Pragma: no-
cache..Set-Cookie:
PHPSESSID=f7q6jfdug4ekfsjhop6jftgna7; path=/..Content-Length:
0..Connection: close..Content-Type: tex
t/html;
charset=UTF-8….

##
上面可以观察得到,http请求头Cookie部分带了session
id,并且这个session_id还是用户第一次访问web时被分配得到的。这一次,http响应头跟第二次示例http响应有些不一样,而是像第一次
访问那样通过Set-Cookie去要求用户端浏览器更新用户的session
id。这意味着:session_genrate_id()给用户端重新生成的session id也是通过Cookie的方法传递。

1,User01和User02第一次去访问/p1.php,分别被分配了一个session id。

2,User01和User02第二次访问web,都会使用由/p1.php分配的session_id

3,User01因为访问了
/p2.php,脚本/p2.php中的session_regenerate_id()给用户User01重新分配了一个新session_id,从用
户User01第4次访问的session_id就可以看得出来,与前面几几次的session_id不同了。

4,User02因为没有访问/p2.php,也就没有被服务端重新分配session
id,一下沿用着上一次分配的session_id

与session id传递的有关的php.ini设置
1,session.use_cookie = 1

是否采用Cookie方法传递session id值。默认是1,表示启用。
2,session.name = PHPSESSID

不管是Cookie传递sessioin_id,还是GET方法传递session_id,都需要使用键值。他们的格式分别是Cookie: 
sess_name=session_id;和/path.php?sess_name=session_id,其中sess_name就是由这里指定 的。

3,session.use_only_cookies = 0
表示只使用Cookie 的方法传递session
id。我们说过,传递cookie的方法,除了cookie,还有GET方法,GET方法是不安全的方法。在用户端禁用了cookie的时候,会采用
GET方法传递session_id,可以通过这个设置尽用GET方法传递session_id。
4,session.cookie_lifetime = 0,
session.cookie_path = / 以及session.cookie_domain =

如果使用Cookie方法传递session_id的话,这里分别指定了cookie有效域、目录和时间。分别对应setcookie()函数的形
参$expire、$path和$domain。其中cookie_lifetime=0表示直到关闭浏览器才删除Cookie。还可以使用
session_set_cookie_params()函数修改这些值。
5,session_name([string $name])

获取或更新session_name。如果传了name,则表示不使用默认的名称PHPSESSID(由session.name)指定,否则获取当前
session_name。注意:如果设置session_name,则必须在session_start()之前调用才生效。

6,session_id([string $id])

与session_name()类似,但它是读取或者设置session_id的方法。同样,设置session_id的话,必须在session_start()之前调用才有效。

7,session_set_cookie_params()和session_get_cookie_params()

通过session_set_cookie_params()可以重新设定session.cookie_lifetime,
session.cookie_path以及session.cookie_domain这三个php.ini设置。而
session_get_cookie_params()则是获取这些设定的值。
Session回收

通过上文几节介绍,我们知道session数据存放在服务端指定的session.save_path目录中,同时会在用户端存放一条Cookie用以记录分配给用户的session
id。所以,session数据失效分服务端和客户端,要删除(回收)的对象也很清楚:
1,服务端:删除过期的session文件,启动PHP
GC回收。

2,用户端:使存储了过期session_id的用户端Cookie记录过期。通过将Cookie的Expire设置为负值,要求客户端删除Cookie。

服务端:删除过期的session文件
PHP
GC进程被启动以后,则会扫描session.save_path,找出过期的session,并删除该session文件。所谓,过期的
session,是指操作系统当前时间与session文件最后访问时间之差大于session.gc_maxlifetime的话,该session认
为是过期了。注意:有时候,你会发现,即便是文件过期了,有可能也没有被及时地删除掉。这是因为,每次session初始化的时候,并不会都启动PHP
GC进程的,启动GC进程会大大降低php的运行效率。所有一个启动概率,这个概率由php.ini设定session.gc_probability /
session.gc_divisor二个设置决定,默认概率是1%(1/1000)。这意味着,每1000次用户请求中,会启动1次PHP
GC回收session文件。比如,我们下面看到的,过期的session文件依然存在:

# date;find /var/lib/php/session -type f -atime -1440 -print |xargs ls -lt 
-rw------- 1 apache apache 0 Apr 12 20:01 /var/lib/php/session/sess_5tlaq5a8im3ob1bikn62motpv7  
-rw------- 1 apache apache 0 Apr 12 19:39 /var/lib/php/session/sess_f7q6jfdug4ekfsjhop6jftgna7  
-rw------- 1 apache apache 0 Apr 12 17:03 /var/lib/php/session/sess_dk7655dqrm5m884c9nitfi7j00

我们可以通过编辑设置,来验证启动php session的GC机制




 <?php//@file session_gc.php

ini_set(“session.gc_probability”, 100);

ini_set(“session.gc_divisor”, 100);

ini_set(“session.gc_maxlifetime”, 1440);

session_start();

[[email protected] ~]# strace -p `cat /var/run/httpd.pid` 
open("/var/www/html/session_gc.php", O_RDONLY) = 17 fstat64(17, {st_mode=S_IFREG|0644, st_size=144, ...}) = 0 lseek(17, 0, SEEK_CUR) = 0 brk(0x8d35000) = 0x8d35000 read(17, "<?php\nini_set(\"session.gc_probab"..., 8192) = 144 read(17, "", 8192) = 0 read(17, "", 8192) = 0 close(17) = 0 open("/var/lib/php/session/sess_5tlaq5a8im3ob1bikn62motpv7", O_RDWR|O_CREAT, 0600) = 17 flock(17, LOCK_EX) = 0 fcntl64(17, F_SETFD, FD_CLOEXEC) = 0 fstat64(17, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0 open("/var/lib/php/session", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY) = 18 fcntl64(18, F_SETFD, FD_CLOEXEC) = 0 time(NULL) = 1271125492 getdents(18, /* 13 entries */, 32768) = 516 stat64("/var/lib/php/session/sess_bk7655dqrm5m884c9nitfi7j00", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0 unlink("/var/lib/php/session/sess_bk7655dqrm5m884c9nitfi7j00") = 0 stat64("/var/lib/php/session/sess_4j38nv7l1fq1bj6n80l6g9cum5", {st_mode=S_IFREG|0600, st_size=11, ...}) = 0 unlink("/var/lib/php/session/sess_4j38nv7l1fq1bj6n80l6g9cum5") = 0 stat64("/var/lib/php/session/sess_n660qmcl38solbmp7vkhafqg17", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0 unlink("/var/lib/php/session/sess_n660qmcl38solbmp7vkhafqg17") = 0 stat64("/var/lib/php/session/sess_5tlaq5a8im3ob1bikn62motpv7", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0 unlink("/var/lib/php/session/sess_5tlaq5a8im3ob1bikn62motpv7") = 0 stat64("/var/lib/php/session/sess_qoa6knu9fg77un8le99o1vk1c7", {st_mode=S_IFREG|0600, st_size=31, ...}) = 0 unlink("/var/lib/php/session/sess_qoa6knu9fg77un8le99o1vk1c7") = 0 stat64("/var/lib/php/session/sess_dutbc682k3h4cgho2sgugc0id4", {st_mode=S_IFREG|0600, st_size=23, ...}) = 0 unlink("/var/lib/php/session/sess_dutbc682k3h4cgho2sgugc0id4") = 0 stat64("/var/lib/php/session/sess_vp8lfqnskjvsiilcp1c4l484d3", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0 unlink("/var/lib/php/session/sess_vp8lfqnskjvsiilcp1c4l484d3") = 0 stat64("/var/lib/php/session/sess_dk7655dqrm5m884c9nitfi7j00", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0 unlink("/var/lib/php/session/sess_dk7655dqrm5m884c9nitfi7j00") = 0 stat64("/var/lib/php/session/sess_f7q6jfdug4ekfsjhop6jftgna7", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0 unlink("/var/lib/php/session/sess_f7q6jfdug4ekfsjhop6jftgna7") = 0 getdents(18, /* 0 entries */, 32768) = 0 close(18) = 0 chdir("/var/lib/php/session") = 0 pwrite64(17, "", 0, 0) = 0 close(17) = 0 setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={0, 0}}, NULL) = 0 writev(16, [{"HTTP/1.1 200 OK\r\nDate: Tue, 13 A"..., 327}], 1) = 327 write(12, "192.168.0.98 - - [13/Apr/2010:10"..., 205) = 205 shutdown(16, 1 /* send */) = 0

从上面蓝色部分可以看出,通过用
stat64检查session文件的状态,如果发现过期了,则会通过调用系统内核函数ulink()删除过期的session文件。可
见,session初始化的时候会启动GC,
GC会扫描session.save_path中的所有session文件,查看他们状态并且将过期的文件删除。正因为如此,所以默认设置启动的概率是
1/1000。

客户端:删除过期session id的cookie记录

如果用户发现session已经过期,但是服务端的GC还没有启动,服务端可以手通过手工代码setcookie的方式要求用户端浏览器删除键值为
session_name()的Cookie记录。这样,下回访问的时候,浏览器以为用户是第一次访问,并且重新给访问用户分配一个新的
session_id。较好的做法类似这样:




 <?php
//@file session_destroy.php session_start(); $sess_name = session_name(); $sess_id = session_id(); list(, $path, $domain, ,) = session_get_cookie_params(); if ($sess_name &amp;&amp; isset($_COOKIE[$sess_name])) { setcookie($sess_name, ‘‘, -1, $path, $domain); if ($sess_id) { session_destroy(); } }

抓取的http数据包如下:




 #
T 192.168.0.98:2638 -< 192.168.0.8:8080 [AP]
GET
/session_destroy.php HTTP/1.1..Host: 192.168.0.8:8080..Connection:
keep-alive..User-Agent: Mozilla/5.0 (Windows; U;
Windows NT 5.1; en-US)
AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.3
Safari/533.2..Accept: application/xml,appl

ication/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5..Accept-Encoding:
gzip,deflate,sdch..Accept-Langu
age: zh-CN,zh;q=0.8..Accept-Charset:
GBK,utf-8;q=0.7,*;q=0.3..Cookie:
PHPSESSID=rjdtgvmueggplgqno66qlfket1….
##
T 192.168.0.8:8080 -<
192.168.0.98:2638 [AP]
HTTP/1.1 200 OK..Date: Tue, 13 Apr 2010 07:08:24
GMT..Server: Apache/2.2.3 (CentOS)..X-Powered-By: PHP/5.1.6..Expires:
T
hu, 19 Nov 1981 08:52:00 GMT..Cache-Control: no-store, no-cache,
must-revalidate, post-check=0, pre-check=0..Pragma: no-

cache..Set-Cookie: PHPSESSID=deleted; expires=Mon, 13-Apr-2009 07:08:23
GMT..Content-Length: 222..Connection: close..Con
tent-Type: text/html;
charset=UTF-8….
##
T 192.168.0.98:2642 -< 192.168.0.8:8080
[AP]
GET /p1.php HTTP/1.1..Host: 192.168.0.8:8080..Connection:
keep-alive..User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.
1;
en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.3
Safari/533.2..Accept: application/xml,application/xhtml

+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5..Accept-Encoding:
gzip,deflate,sdch..Accept-Language: zh-CN,zh
;q=0.8..Accept-Charset:
GBK,utf-8;q=0.7,*;q=0.3….
##
T 192.168.0.8:8080 -<
192.168.0.98:2642 [AP]
HTTP/1.1 200 OK..Date: Tue, 13 Apr 2010 07:09:15
GMT..Server: Apache/2.2.3 (CentOS)..X-Powered-By:
PHP/5.1.6..Set-Cookie
: PHPSESSID=lbmk3sc5a88e9cjuekr0aa9pc3;
path=/..Expires: Thu, 19 Nov 1981 08:52:00 GMT..Cache-Control: no-store,
no-cach
e, must-revalidate, post-check=0, pre-check=0..Pragma:
no-cache..Content-Length: 11..Connection: close..Content-Type: te

xt/html; charset=UTF-8….hello world

##

上面观察可以知道,通过访问/session_destroy.php,它要求客户端将session_id的Cookie记录删除。而接下来访问
/p1.php的时候,http请求头没有通过Cookie将用户的session
id带给服务器(因为刚被要求删除)。而第二次请求/p1.php的http响应里头可以看到,服务端又给用户重新分配了一个新的session
id,而且不会继续使用过去的session数据。

与session回收相关的php.ini设置:
1,
session.gc_probability和session.gc_divisor

由这二个函数决定了启用GC的概率,默认是1/1000。也就是说,每一千次用户请求中有一次会启动GC回收session。启动GC进程不宜过于频繁。
上面的例子,我们可以看到,它会每次检查session.save_path目录下每个文件的状态。这样会降低php的执行效率。
2,
session.gc_maxlifetime = 1440
设置session存活时间,单位是秒。每次GC启动后,
会通过stat得到session文件最后访问的unix时间,通过现在时间减去文件最后访问时间之间大于session.gc_maxlifetime,则会删除该文件。

总结

1, PHP使用Cookie的方法传递session id。尽量不要使用GET方法传递session
id,因为这样很不安全。

2, 可以通过setcookie()的方法,将客户端的session id的Cookie记录删除。

3, PHP GC进程由session初始化启动。但不是每一次用户请求都会被启动,它的启动概率默认是1/1000。过于频繁访问的网站,并发量大的网站,可减小PHP GC的启动频率。PHP
GC回收session会降低php的执行效率。

4, 通过下面代码,优化session回收




 <?php

session_start();

if (isset($_SESSION[‘SESS_TIMEOUT‘])) {

if ($_SERVER[‘REQUEST_TIME‘] >
$_SESSION[‘SESS_TIMEOUT‘]) {

setcookie(session_name(), session_id(), -1,
‘/’);

session_unset();

session_destroy();

}

} else {

$_SESSION[‘SESS_TIMEOUT‘] = $_SERVER[‘REQUEST_TIME‘] +
3600;

}


PHP5 session 详解【经典】

时间: 2024-10-24 21:26:59

PHP5 session 详解【经典】的相关文章

PHP5 session 详解【经典】 -- 转帖

PHP5 session 详解[经典] http协议是WEB服务器与客户端(浏览器)相互通信的协议,它是一种无状态协议.所谓无状态,指的是不会维护http请求数据,http请求是独立的,非持久的.而越来越复杂的WEB应用,需要保存一些用户状态信息.这时候,Session这种方案应需而生.PHP从4.1开始支持Session管理. session是很抽象的一个概念.我们不妨先从与它几个息息相关的有迹可寻的小切入点入手,然后逐渐地认识了解它. session存储 首先,我们为什么需要Session,

PHP5 session 详解

http协议是WEB服务器与客户端(浏览器)相互通信的协议,它是一种无状态协议.所谓无状态,指的是不会维护http请求数据,http请求是独立的,非持久的.而越来越复杂的WEB应用,需要保存一些用户状态信息.这时候,Session这种方案应需而生.PHP从4.1开始支持Session管理. session是很抽象的一个概念.我们不妨先从与它几个息息相关的有迹可寻的小切入点入手,然后逐渐地认识了解它. session存储 首先,我们为什么需要Session,就是因为我们需要存储各个用户的状态数据.

[转]PHP5 session 详解

来源:http://blog.163.com/lgh_2002/blog/static/4401752620105246517509/ http协议是WEB服务器与客户 端(浏览器)相互通信的协议,它是一种无状态协议.所谓无状态,指的是不会维护http请求数据,http请求是独立的,非持久的.而越来越复杂的WEB 应用,需要保存一些用户状态信息.这时候,Session这种方案应需而生.PHP从4.1开始支持Session管理. session是很抽象的一个概念.我们不妨先从与它几个息息相关的有迹

Cookie与Session详解

来源:<PHP核心技术与最佳实践> 列旭松 陈文 著 Cookie与Session详解读书笔记,从概念.操作.应用.注意事项以及区别等几方面详细阐述两者的基础知识,它们都是针对HTTP协议的局限性而提出的一种保持客户端和服务器间保持会话连接状态的机制.. 一.Cookie详解 Cookie在远程浏览器端存储数据并以此跟踪和识别用户的机制.从实现上说,Cookie是存储在客户端上的一小段数据,浏览器(即客户端)通过HTTP协议和服务器端进行Cookie交互. Cooke独立于语言存在,严格地说,

.net的session详解 存储模式 存到数据库中 使用范围与大小限制 生命周期

Session又称为会话状态,是Web系统中最常用的状态,用于维护和当前浏览器实例相关的一些信息.举个例子来说,我们可以把已登录用户的用户名放在Session中,这样就能通过判断Session中的某个Key来判断用户是否登录,如果登录的话用户名又是多少. 我们知 道,Session对于每一个客户端(或者说浏览器实例)是"人手一份",用户首次与Web服务器建 立连接的时候,服务器会给用户分发一个 SessionID作为标识.SessionID是一个由24个字符组成的随机字符串.用户每次提

.net Session 详解

(一) 描述当用户在 Web 应用程序中导航 ASP.NET 页时,ASP.NET 会话状态使您能够存储和检索用户的值.HTTP 是一种无状态协议.这意味着 Web 服务器会将针对页面的每个 HTTP 请求作为独立的请求进行处理.服务器不会保留以前的请求过程中所使用的变量值的任何信息.ASP.NET 会话状态将来自限定时间范围内的同一浏览器的请求标识为一个会话,当每个用户首次与这台WWW服务器建立连接时,他就与这个服务器建立了一个Session,同时服务器会自动为其分配一个SessionID,用

javaEE session详解

1也可以记录状态信息,与cookie不同,cookie是记录在客户端的,session是记录在服务器端的. 2session是服务器哦开辟的一块内存,session是与浏览器(或子窗口)关联在一起的,其他浏览器访问不了. 3原理:在第一次访问服务器的时候,服务器会创建一个SessionID,会在服务器的Session内存里保存SessionID,然 后把这个SessionID通过response返回给浏览器(浏览器就获得了这个SessionID),在第二次访问服务器,浏览器通 过request提

【SQL】ROW_NUMBER() OVER(partition by 分组列 order by 排序列)用法详解+经典实例

原文:[SQL]ROW_NUMBER() OVER(partition by 分组列 order by 排序列)用法详解+经典实例 #用法说明 select row_number() over(partition by A order by B ) as rowIndex from table A :为分组字段 B:为分组后的排序字段. table 表的结构 多为:  多人 多条的相关数据.(比如:订单信息) 此条sql语句,多用于对数据进行分组排序,并对每个组中的数据分别进行编号,编号从1开始

Session详解与应用(java,js)

Session机制 在学习session之前,我们首先要了解一下保存在客户端的会话跟踪机制cookie-------cookie详解与应用 除了使用Cookie,Web应用程序中还经常使用Session来记录客户端状态.Session是服务器端使用的一种记录客户端状态的机制,使用上比Cookie简单一些,相应的也增加了服务器的存储压力. 1  什么是Session Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上.客户端浏览器访问