注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

@fc_lamp

关注Web应用解决方案MySql/PHP/Python一盏名为"飞川"的灯~

 
 
 

日志

 
 

PHP SESSION Name 引用SESSION ID(SESSION NAME与SESSION ID的关系)Discuz! 用户(自动)登录原理  

2011-11-29 14:08:00|  分类: Web技术-Php |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

(注:本文中提到的SESSION ID均以COOKIE方式存放)

一老生常谈

SESSION与COOKIE问题,可以说是一个老生常谈的问题,对于什么是SESSION,什么是COOKIE,我这里就不多说了,

GOOGLE一下一大把。

二 原理

今天,我要说的是如何使用session name引用SESSION ID问题(官网说明:session.name指定会话名以用做 cookie 的名字。只能由字母数字组成,默认为PHPSESSID)。即:人为修改PHP自动生成的SESSION ID。

首先,我们知道 一旦 PHP session_start()后就开启了一个会话。这当种了两件事:

一 是把相关SESSION信息存放于服务器端(产生一个类似于sess_XXX这样的文件),XXX就是SESSION ID 。

二 是把会话名session name(默认为:PHPSESSID),以及SESSION ID发给浏览器以cookie的方式存起来(即:cookie_name : SESSION ID),也就是 以 session name 为 键,session id 为值的HASH值存入COOKIE。

这样,当再次访问页面时,浏览器再把COOKIE里的SESSION ID发给服务器(当然,COOKIE里的值是没有过期的),PHP比对服务器上的SESSION文件,如果没有得话,会产生一个新的SESSION文件,如果有得话,则直接使用。

这里有两点值的说明一下:

1 :对于登录合不合法之类的是你自己写PHP脚本来判断的,即比对$_SESSION里的值(因为新产生的SESSION文件里是没有任何值的)。

2 :把COOKIE里的SESSION ID传给服务器(PHP)后,在使用SESSION ID之前有一个选择。前面,我们说过SESSION ID在COOKIE里是以键值配对方式存放的,键即为会话名(session name),一般如果没有事先声明(在session_start()之前)PHP是使用默认的会话名,即PHPSESSID,所以不同页面可以有不同的会话名。如下图所示:

PHP SESSION Name 引用SESSION ID(SESSION NAME与SESSION ID的关系)Discuz! 用户(自动)登录原理 - fc-lamp - fc-lamp的博客

所以,对于特殊的SESSION ID,要使用时必须事先声明(设置)会话名,才能正常的引用。

三 方法

那么如何设置会话名(session name)呢?设置session name的方试一般有两种:

1:在php.ini配置文件里修改:在php.ini文件里找到:session.name = PHPSESSID  即可完成设置

2:使用session_name()函数设置,eg:session_name('test9');

这里要注意一下:关于session name的问题。恩,在这里我直接引用官网上的一段话(简单的E文,想必大家都看的懂):

The session name references the session id in cookies and URLs. It should contain only alphanumeric characters; it should be short 

and descriptive (i.e. for users with enabled cookie warnings). Ifnameis specified, the name of the current session is changed to its value.

The session name can't consist of digits only, at least one letter must be present. Otherwise a new session id is generated every time.

以上这段非常重要,请你一定要仔细看。或者去官网:http://cn.php.net/manual/zh/function.session-name.php

Eg1 同一页面操作同一SESSION NAME

有了以上的说明后我们来看一段同一页面重复的操作同一个session.name代码:


    if(isset($_COOKIE['test9'])){//如果已有值,则销毁
        session_name('test9');
        session_start();
        setcookie('test9','',time()-3600);//相应COOKIE也过期(这段代码实际上可以不要)
        session_unset();
        session_destroy();
    }
    //重新播种SESSION
    session_name('test9');
    session_id(md5(uniqid()));
    session_start();
    $_SESSION['test'] = 'test';

    var_dump($_COOKIE);



Eg2 使用session name 引用不同的session id

我们首先在 test.php 文件写入如下代码,在Firefox里执行:


<?php
session_name('test99'); #告诉浏览器取键为 test99的COOKIE值返给服务器。
session_start(); #创建,并赋值SESSION
$_SESSION['test99']= '99';


然后,修改一下代码,再执行:


<?php
session_name('test66');
session_start();
$_SESSION['aa']= 'aa';


运行完后,我们使用Firefox来查看COOKIE信息,如下图:

PHP SESSION Name 引用SESSION ID(SESSION NAME与SESSION ID的关系)Discuz! 用户(自动)登录原理 - fc-lamp - fc-lamp的博客
我们可以看到相关的cookie信息已按我们设想的存好了,实际上这时候(当然,你没有修改SESSION默认的存放方式)服务器上会有

出现两个文件:PHP SESSION Name 引用SESSION ID(SESSION NAME与SESSION ID的关系)Discuz! 用户(自动)登录原理 - fc-lamp - fc-lamp的博客。这两个文件里就分别存放了相关的SESSION信息。

好了,接着我们在另一个页面里分别来获取它们,首先我们在 test2.php文件里,写入如下代码,然后在firefox里运行:


<?php
session_name('test66');
session_start();#使用,获取SESSION内容
var_dump($_SESSION);


你会看到如下输出:

array(1) { ["aa"]=> string(2) "aa"}

我们再修改代码,运行:


<?php
session_name('test99');
session_start();
var_dump($_SESSION);


你会看到如下输出:

array(1) { ["test99"]=> string(2) "99"}

 

四  用户登录过期问题

  由以上就很容易想到用户登录过期、退出问题,这里给一个一般性做法:

//当用户登录时,过期时间可以这样设置

session_set_cookie_params ( 120 );//过期时间两分钟(session_set_cookie_params可参官网手册)

session_start ();

不过, 这里还要注意一下这里所设置的过期仅是COOKIE上的,服务器端的SESSION文件并不会立即被系统删除。

原因参看:《如何设置一个严格30分钟过期的Session》 #ini_set('session.gc_maxlifetime', 10);


//当以下为用户退出操作

$session_name = session_name ();
setcookie ( $session_name, null, - 1, '/' ); //这一歩是让浏览器里的会话 cookie标识过期(当然这里是默认的PHP SESSION名称) 
$_SESSION = array (); //这一歩会让SESSION文件整个被清空 
session_destroy ();//这一歩销毁所有与当前SESSION相关的数据(并且SESSION文件可能删除,这是由服务器的临时文件回收机制决定的)


恩,还有一个问题这里友情提一下:如果说现了SESSION或者COOKIE不能正常获取(丢失),一般出现以下问题:

1 使用session_start() 或者setcookie() 函数之前出现了输出内容,如 header(),或者空白字符像UTF-8编码中BOM ,

   又或者文件等编码格式不对。

2  服务器的时间设置不正确, 像session_set_cookie_params(),setcookie() 的lifetime 参数不正常。这一问题尤其在chrome与IE下面很明显,cookie值根本就无法写入,friefox却不没有影响。

3  域名不正确,如:fc_lamp.com 这是一个不正确的域名,当使用IE浏览器访问时,COOKIE是无法被成功设置(种植)的。当在friefox、chrome浏览器中却没有问题。


五 Discuz! 用户(自动)登录原理

Discuz!完全摒弃了PHP原生的SESSION登录方式,而是自己使用了一套“SESSION”方式。实际上,也很多的PHP框架没有使用PHP原生的SESSION方式,比如CI框架。虽然PHP提供了额外的session_set_save_handler SESSION保存方式。

他们都还是没有使用PHP原生的SESSION方式,可能是因为出于安全与性能方面的考虑,也可能是其它原因。那么这里简单说说Discuz!用户登录的原理,仅从代码上来看:

 

* 用户是否正常登录是由$_G['uid'] 决定,而$_G['uid']如何获取:

* 1 在用户登录时,将uid与pwd一起加密后存入auth,调用setloginstatus()方法是在 

* /source/class/class_membersearch.php 152行

* setloginstatus($result['member'], $_G['gp_cookietime'] ? 2592000 : 0);

* 而这里的$_G['gp_cookietime']就是是否要自动登录。

* 定义setloginstatus()方法是在

* /source/function/function_member.php 78行

* setloginstatus($member, $cookietime)

*2 当用户访问需要登录某页面时,通过先通过$discuz = & discuz_core::instance ()调用_init_input()方法

*  _init_input() 方法是在/source/class/class_core.php 53行

* 将原生的PHP全局变量$_POST,$_GET,$_COOKIE等写到入$_G变量中。

* 然后再$discuz->init()来调用_init_user ()

* _init_user()方法是在/source/class/class_core.php 413行

* 从$_G变量中找出auth,并从auth中找出用户密码与uid,然后用udi查寻member表查出密码,最后使用auth解密出来的

* 密码与数据库中查寻出来的密码比对,如果成功就注入$_G['uid']。

*/

 

 另外:官网上也有讨论设置SESSION生命周期的问题,可以看看。地址:http://cn.php.net/manual/zh/function.session-set-cookie-params.php


六 PHP COOKIE跨子域的设置
   
     默认情况下,PHP设置的SESSION COOKIE NAME 只在当前域下有效。
     ssoa.fc_lamp.com/index.php

//1 PHP默认行为(只在子域有效)
session_start();
$_SESSION['test'] = 'test';

  ssob.fc_lamp.com/index.php

<?php
session_start();
var_dump($_SESSION);
var_dump($_COOKIE);
exit;

先请求 ssoa.fc-lamp.com/index.php  我们可以得到相关的COOKIE

* 名称:PHPSESSID
* 内容:9q0khoialnnfcg7aq309g0he33
* 主机:ssoa.fc_lamp.com
* 路径:/


再请求ssob.fc-lamp.com/index.php,页面输出:
array   empty 
array   empty
且产生了相应的COOKIE

* 名称:PHPSESSID
* 内容:oql2ta7o6c1epdghni5lq4p307
* 主机:ssob.fc-lamp.com
* 路径:/

那么我们如何使ssoa子域里设置的SESSION在ssob子域里也能得到呐(注意ssoa与ssob都在同一台机子上)?
这里就要使存储在COOKIE里的PHP SESSION唯一标识SESSION ID在全域可用。
方法: 我们修改ssoa 代码

//2 更改默认行为 方式一(所有子域都生效)
session_set_cookie_params(0,'/','.fc-lamp.com');
session_start();
$_SESSION['test'] = 'test';

刷新 ssoa,此时产生了如下COOKIE

* 名称:PHPSESSID
* 内容:n5an1p7eg2j6n65gqgdgneri20
* 域:.fc-lamp.com
* 路径:/

再来刷新ssob,页面输出:

array
'test' => string 'test' (length=4)
array
'PHPSESSID' => string 'j0t1rfej37fir60aft46rr0hb4' (length=26)

ssob 此时没有产生新的COOKIE值。
如果我们覆盖,PHP默认的SESSION COOKIE NAME
setcookie('PHPSESSID','tset99',0,'/','.fc-lamp.com'); 
注意这里域要设来和上面一样,都是主域名下,不然会单独产一个在 ssoa.fc_lamp.com域外下的COOKIE
先刷新ssoa, 再刷新ssob页面,则输出

array
empty
array
'PHPSESSID' => string 'tset99' (length=6)

实际上:从这里可以看出 session_start() 再做基本的两件事情之前,会根据浏览器传上来的SESSION COOKIE NAME(默认是PHPSESSID)所对应的SESSION ID 来查找对应的SESSION文件,有得话会解析出数据来加入到全局变量$_SESSION中。如果没有则会相应生成一个SESSION文件。
这里还有一种方式来设置SESSION COOKIE NAME全域可用:

$name = session_name();
session_start();
setcookie($name,session_id(),0,'/','.fc-lamp.com');

我们使用setcookie 方式设置了一个在所有域都生效的COOKIE。而这个COOKIE恰又与 PHP SESSION ID在COOKIE存储的 KEY和VALUE都一样。
实际上,默认产生的这个COOKIE(session_start()产生的)和我们手动设置(setcookie)COOKIE是不相干的,完全独立的。
如图:
PHP SESSION Name 引用SESSION ID(SESSION NAME与SESSION ID的关系)Discuz! 用户(自动)登录原理 - fc_lamp - @fc_lamp
另外,如果你是从JS方式(或者其它二次加载方式种植COOKIE)在IE游览中你可能需要设置P3P协议:

header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');


 









 



  评论这张
 
阅读(1601)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017