Php解决跨域名共享session方案整理专题

Php解决跨域名共享session方案整理专题 2009-12-22 17:01:44

分类:

Php解决跨域名共享session方案整理专题

[整理人:hkebao#126.com 整理时间:2009-12-22]

测试环境:

文件目录:F:\PHP\opensource\aistockbot_0.2-04_beta-2\aistockbot  

IP: 192.168.100.90

域名:shop.hn81.com

 

文件目录:E:\uchome\wordpress

IP:192.168.100.40

域名:user.hn81.com

 

测试步骤:

1、   在shop域名下面创建一个文件里面记录用户的一个session值。PHP代码如下:

<?php

$lifeTime = 2 * 3600;        

session_set_cookie_params($lifeTime);                        //这个函数必须要在session_start之前调用

session_start();

$_SESSION["admin"] = "test"; 

?>

说明:session_start() 函数 的作用就是创建session初始化一个变量。

请求地址:http://shop.hn81.com/test/create.php   能够创建一个session值!

2、   在同一个域名内获取这个session参数值!

请求地址:http://shop.hn81.com/test/read.php              能够获取到当前保存的session变量值!

PS:这两个是在同一个域名下面的所以能够正常地进行读取

3、   在另一个域中请求这个地址:http://user.hn81.com/test/read.php

结果读不出来指定的session变量值。

 

以上是测试过程中发现的问题,现在讨论一下如何解决这个问题?

尝试一、通过带sessionid 的方法

PS:

1、通过PHP里面的session_id() ; 函数能够获取到当前的sessionid 值!

2、SESSION ID 可以通过两种方式保留在客户端,使得请求不同的页面时,PHP 程序可以获知客户端的 SESSION ID;一种是将 SESSION ID 自动加入到 GET 的 URL 中,或者 POST 的表单中,默认情况下,变量名为 PHPSESSID;另一种是通过 COOKIE,将 SESSION ID 保存在 COOKIE 中,默认情况下,这个 COOKIE 的名字为 PHPSESSID。

3、那么 SESSION 的数据保存在哪里呢?当然是在服务器端,但不是保存在内存中,而是保存在文件或数据库中。默认情况下,php.ini 中设置的 SESSION 保存方式是 files(session.save_handler = files),即使用读写文件的方式保存 SESSION 数据,而 SESSION 文件保存的目录由 session.save_path 指定,文件名以 sess_ 为前缀,后跟 SESSION ID,如:sess_c72665af28a8b14c0fe11afe3b59b51b。文件中的数据即是序列化之后的 SESSION 数据了。如果访问量大,可能产生的 SESSION 文件会比较多,这时可以设置分级目录进行 SESSION 文件的保存,效率会提高很多,设置方法为:session.save_path="N;/save_path",N 为分级的级数,save_path 为开始目录。当写入 SESSION 数据的时候,PHP 会获取到客户端的 SESSION_ID,然后根据这个 SESSION ID 到指定的 SESSION 文件保存目录中找到相应的 SESSION 文件,不存在则创建之,最后将数据序列化之后写入文件。读取 SESSION 数据是也是类似的操作流程,对读出来的数据需要进行解序列化,生成相应的 SESSION 变量。(session工作原理)

测试步骤:

1、   在创建session的服务器域下面。获取到当前的sessionid 然后创建超链接直接跳转到另一个域中去

<?php

session_start();

if(isset($_SESSION["admin"])){

         $sessionid = session_id() ;

}else{

         echo("e");

}

?>

<a href="http://user.hn81.com/test/read.php?session>链接</a>

带上sessionid 值。

2、   在另一个域中接收到这个sessionid 并提取出来这个值

if(isset($_GET["sessionid"])) {

         $sessionid = $_GET["sessionid"];                         //获取到这个sessionid值!

         session_id($sessionid);                                            //使用session

         session_start();

         echo $_SESSION['admin'];                                    //通过session 查找到实体数据出来!

}else{

         echo $_SESSION['admin'];                                    //直接获取不能得到数据!

         echo "no";

}

 

心得:通过传递sessionid 能够解决跨域共享session数据!

 

尝试二、通过扩大session的作用域范围

PS:刚犯了一个错误。浏览器之间是不能共cookie的。因为像FF与IE保存cookie的目录都不一样怎么可能共享?搞糊涂了!!!

因为session要使用前提是客户端的COOKIE必须要开启。所以可以考虑扩大其作用域范畴!

这种解决办法其实算是对第一种解决办法的迂回吧!具体如下:

PS:以后可以用这种办法!

1、   创建session的代码如下:

<?php

$lifeTime = 2 * 3600;        

session_start();

session_set_cookie_params($lifeTime);

setcookie(session_name(), session_id(), time() + $lifeTime, "/","hn81.com");       

//将session_id保存到客户端,呆会还会介绍将sessionid 保存到服务器端的解决办法!

$_SESSION["admin"] = "test"; 

?>

2、   同一个域的获取代码:

<?php

session_start();

if(isset($_SESSION["admin"])){

         echo $_SESSION["admin"];                                //直接获取

}else{

         echo("e");

}

?>

3、   另一个域中获取SESSION数据

<?php

$sessionid = $_COOKIE["PHPSESSID"];          //拿到COOKIE值即得到sessionid 值!

session_id($sessionid);                                            //通过ID去查找实体的SESSION数据文件

session_start();          

echo $_SESSION['admin'];                                    //获取数据

?>

PS:第二种办法是能够解决同一个大域共享session数据的办法的。即将key(ID)放到客户端

通过应用这种办法解决目前遇到的问题^_^。

这种情况:真实的session数据还是保存在服务器上面的。如果是多台服务器做负载均衡的话单用这种办法解决不了,为什么呢?因为每一台服务器上面保存的真实session数据不一致。所以可以将session层抽出来作持久化处理。所以就有了第三种办法!

尝试三、将session进行持久化。将session数据保存到数据库

具体实现的过程图:






将session的数据持久化处理。

这种情况也能够同一个应用跑在多台SERVER上面。

一般的代理转发架构如下:

PS:

1、   ini_set  函数相当于是直接修改了php.ini 配置文件。

2、   php.ini 里面关于 session 的配置
[Session]
session.save_handler = files ; handler used to store/retrieve data
; 存储/读入数据用的句柄
session.save_path = C:/php4 ; argument passed to save_handler
; in the case of files, this is the
; path where data files are stored
; 用于存放句柄文件的路径(一定要设置正确,否则不能执行)
session.use_cookies = 1 ; whether to use cookies
; 是否使用 cookies
session.name = PHPSESSID
; name of the session
; 在 cookie 里 session 使用的名字
; is used as cookie name
session.auto_start = 0 ; initialize session on request startup
; 是否在请求开始时自动启动,初始化 session
session.cookie_lifetime = 0 ; lifetime in seconds of cookie
; or if 0, until browser is restarted
; 在 cookie 里面 session 存在的时间秒数,0 直到浏览器重新启动
session.cookie_path = / ; the path the cookie is valid for
; cookie 里存放数值的位置
session.cookie_domain = ; the domain the cookie is valid for
; 存放数值的 cookie的主机(主键)
session.serialize_handler = php ; handler used to serialize data
; php is the standard serializer of PHP
; 序列化数据的句柄,标准句柄是 php
session.gc_probability = 1 ; percentual probability that the
; 'garbage collection' process is started
; on every session initialization
; 打开每个session初始化时自动开始 垃圾收集进程
session.gc_maxlifetime = 1440 ; after this number of seconds, stored
; data will be seen as 'garbage' and
; cleaned up by the gc process
; 当超过这个时间,存储的的数据会被认为是垃圾,被 gc 进程清除
session.referer_check = ; check HTTP Referer to invalidate
; externally stored URLs containing ids
; 检查包含 ids 的 HTTP 里无效的外部保存 URLs的内容
session.entropy_length = 0 ; how many bytes to read from the file
; 从文件里读入的允许字节数
session.entropy_file = ; specified here to create the session id
; 指定在这里建立 session id
; session.entropy_length = 16
; session.entropy_file = /dev/urandom
session.cache_limiter = nocache ; set to {nocache,private,public} to
; determine HTTP caching aspects
; 确定 HTTP 缓存外貌 {nocache,private,public}
session.cache_expire = 180 ; document expires after n minutes
; 超过 n 分钟文档到期

3、  session_set_save_handler 函数的作用是更改PHP默认的session方式。比如说现在要将session数据保存到数据库就可以用它!

测试过程如下:(以后可以直接复制运行我全部都通过测试的!)

一、 创建表

SQL语句如下:

CREATE TABLE `mysession` (

  `session_key` char(32) NOT NULL default '',

  `session_expiry` bigint(20) NOT NULL default '0',

  `session_data` longtext NOT NULL,

  PRIMARY KEY  (`session_key`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

二、 编写自定义session处理代码具体代码如下:

<?php

function mysession_open($save_path, $session_name)

{

         @mysql_connect("localhost", "root", "321") or die("数据库服务器连接失败");

         @mysql_select_db("phpsess") or die("数据库不存在或不可用");

         return true;

}

 

function mysession_close()

{

         return true;

}

 

function mysession_read($key)

{

         $expiry_time = time();                        //获取Session失效时间

         $ssql = "select session_data from mysession  "." where session_key = '$key' and session_expiry > $expiry_time";

         $query = @mysql_query($ssql) or die("SQL语句执行失败");

         if($row = mysql_fetch_array($query))

                   return $row['session_data'];

         else

                   return false;

}

 

function mysession_write($key, $data)

{

         $expiry_time = time() + 500;                        //获取Session失效时间

         $query = @mysql_query("select session_data from mysession "."where session_key = '$key'")

or die("SQL语句执行失败");

//如果不存在,则执行插入操作,否则执行更新操作

if(mysql_numrows($query) == 0)

{  

//执行SQL语句插入Session的值

$query = @mysql_query("insert into mysession(session_key,session_data,session_expiry) values('$key', '$data', $expiry_time)")

or die("SQL语句执行失败");

}

else

{

//执行SQL语句更新Session的值

$query = @mysql_query("update mysession set "

."session_data = '$data', session_expiry = $expiry_time "

."where session_key = '$key'")

or die("SQL语句执行失败");

}

return $query;

}

 

function mysession_destroy($key)

{

$query = @mysql_query("delete from mysession where session_key = '$key'")

or die("SQL语句执行失败");

return $query;

}

 

function mysession_gc($expiry_time)

{

$expiry_time = time();

//执行SQL语句删除Session

$query = @mysql_query("delete from mysession where session_expiry < $expiry_time")

or die("SQL语句执行失败");

return $query;

}

 

//重新配置一下php的配置信息

ini_set('session.use_trans_sid',    0);

//设置垃圾回收最大生存时间

ini_set('session.gc_maxlifetime',   50);

//使用 COOKIE 保存 SESSION ID 的方式

ini_set('session.use_cookies',1);

ini_set('session.cookie_path',      '/');

//多主机共享保存 SESSION ID 的 COOKIE

 

//这个非常关键。一定要将域定义好要不然会出问题。其他的域像.tianya.cn  .sina.cn   .126.com

ini_set('session.cookie_domain',".hn81.com");     //将域定义好

//设置用户自定义Session存储

ini_set('session.save_handler', 'user');

 

session_set_save_handler('mysession_open',

'mysession_close',

'mysession_read',

'mysession_write',

'mysession_destroy',

'mysession_gc');

?>

保存文件名为:session_inc.php
第三步、编写创建session的代码。如下

<?php

include('session_inc.php');         

$lifeTime = 2 * 3600;

session_set_cookie_params($lifeTime);

session_start();

$_SESSION['admin'] = "welcome to php";                         //将session参数值定义好

setcookie(session_name(), session_id(), time() + $lifeTime, "/","hn81.com");          //这个的作用是将 sessionid暂保存到用户客户端中去。是为了能够让用户在下次访问的时候将ID带过来作为key 进行DB查询用

 

到此,我们的session已经成功创建了。现在我需要访问它!

 

第四步、同一个域名访问方式如下

注意:是同一个域名哦。这种情况其实就是就是在前端加了一个负载均衡。像haxproxy、nginx等实体的session数据保存到了单个服务器上。所以将其迁到数据库中去!

这种情况取session的办法如下:

include('session_inc.php');        //包含session_set_save_handler定义的文件

session_start();

echo $_SESSION['admin'];       //与传统的一样是吧。只是多了一个 include文件!

 

第五步、不同域名访问方式如下:

这个时候就要依靠客户端的cookie了。通过sessionid 值提取对应的SESSION数据

具体的代码如下:

<?php

include('session_inc.php');                              //包含session_set_save_handler定义的文件

$sessionid =   $_COOKIE["PHPSESSID"];     //拿COOKIE

session_id($sessionid);                                            //通过ID去查找实体的SESSION数据文件

session_start();          

echo $_SESSION['admin'];                                    //获取数据

 

相比来讲多了两步操作。

同时我查看了一下DB。有记录!

 

心得:通过这种办法将SESSION数据迁到数据库中去。能够让多台服务器、多个域名共享SESSION数据

其中(如果只是处理单台多域名的话我们是可以通过走COOKIE的方法解决见上面二。如果有关联到多台服务器的时候就要考虑将SESSION迁到DB或其他的设备中去!)