全部博文(2065)
分类:
2009-12-22 17:01:44
Php解决跨域名共享session方案整理专题
[整理人:hkebao#126.com 整理时间:
测试环境:
文件目录: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代码如下:
$lifeTime = 2 * 3600;
session_set_cookie_params($lifeTime); //这个函数必须要在session_start之前调用
session_start();
$_SESSION["admin"] = "test";
?>
说明:session_start() 函数 的作用就是创建session初始化一个变量。
请求地址: 能够创建一个session值!
2、
在同一个域名内获取这个session参数值!
请求地址:
能够获取到当前保存的session变量值!
PS:这两个是在同一个域名下面的所以能够正常地进行读取
3、
在另一个域中请求这个地址:
结果读不出来指定的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_c72665af
测试步骤:
1、
在创建session的服务器域下面。获取到当前的sessionid
然后创建超链接直接跳转到另一个域中去
session_start();
if(isset($_SESSION["admin"])){
$sessionid
= session_id() ;
}else{
echo("e");
}
?>
带上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的代码如下:
$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、
同一个域的获取代码:
session_start();
if(isset($_SESSION["admin"])){
echo
$_SESSION["admin"]; //直接获取
}else{
echo("e");
}
?>
3、
另一个域中获取SESSION数据
$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处理代码具体代码如下:
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的代码。如下
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数据
具体的代码如下:
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或其他的设备中去!)
尝试四、将session进行持久化。将session数据保存到memcache中
待续………..