您的位置:首页 > 编程语言 > PHP开发

php中cookie跨域的解决方案以及IE和safari浏览器中的坑

2015-10-13 23:23 671 查看
最近工作上遇到了一道难题:公司的合作商想将我们平台的用户引流到他们平台,即在他们的网站上用户可以使用在我们平台的用户名和密码进行登录,简言之需要做到用户在两个平台登录状态的同步。

一般来说用户登录完之后用户信息存储在cookie中,要实现登录状态的同步实际上就是要实现cookie的跨域共享。

具体的实现思路是,a网站不存储cookie,b网站提供cookie的获取接口,a网站实时请求该接口,获取用户信息。简要的示例如下:

cookie接口:passport.b.com/cookie.php

<?php
echo 'outputCookie'.'('.json_encode($_COOKIE).')';


a网站公用部分代码:

<div id="userinfo">
<div id="noLogin" style="display:none">
用户名:<input name="username" type="text" id="username" /><br />
密码:<input name="password" type="text" id="password" /><br />
<input type="submit" id="submit" value="登录"/>
<span id="tips"><?php echo isset($_GET['msg']) ? urldecode($_GET['msg']) : '' ?></span>
</div>
</div>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
function outputCookie(data){
if(data && data.username){
$("#userinfo").html('你好,' + data.username + '<a href="http://passport.b.com/logout.php">登出</a>');
}else{
// document.getElementById('noLogin').style.display="block";
$("#noLogin").show();
}
};
</script>
<script src="http://passport.b.com/cookie.php"></script>


在请求http://passport.b.com/cookie.php链接时,输出的数据将调用在js中定义的outputCookie方法,在该方法中处理有用户有关的逻辑。

原理与ajax的jsonp跨域请求的原理十分类似,不明白jsonp的机制的童鞋建议移步这篇文章:浅谈jsopn跨域请求原理及cors(跨域资源共享)解决方案

看起来很浅显而且容易,但是当真正实现起来时却遇到了IE和safari两只拦路虎。先上代码:

www.a.com/index.php(a站首页代码)

<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<div id="userinfo">
<div id="noLogin" style="display:none">
用户名:<input name="username" type="text" id="username" /><br />
密码:<input name="password" type="text" id="password" /><br />
<input type="submit" id="submit" value="登录"/>
<span id="tips"><?php echo isset($_GET['msg']) ? urldecode($_GET['msg']) : '' ?></span>
</div>
</div>

<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
function outputCookie(data){
if(data && data.username){
$("#userinfo").html('你好,' + data.username + '<a href="http://passport.b.com/logout.php">登出</a>');
}else{
// document.getElementById('noLogin').style.display="block";
$("#noLogin").show();
}
};

function doSomething(data){
if(data.status != 1){
$("#tips").html(data.msg);
}else{
window.location.reload();
}
}
</script>
<script>
$(function(){
$("#submit").click(function() {
var username = $("#username").val();
var password = $("#password").val();
if(!username || !password){
$("#tips").html('用户名和密码不能为空!');
}else{
//在safari之外的浏览器是可以这样实现的
var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = 'http://passport.b.com/login.php?username=' + username + '&password=' + password + '&callback=doSomething';
$("body").append( script );
}
});
});
</script>
<script src="http://passport.b.com/cookie.php"></script>


passport.b.com/login.php(b站登录接口)

<?php
if(empty($_GET['username']) ||  empty($_GET['password']) || empty($_GET['callback'])){
echo $_GET['callback'].'('.json_encode(array('status' => -1,'msg' => '参数不完整')).')';
}

if($_GET['username'] == 'ben' && $_GET['password'] == 'lalala'){
//设置cookie
setcookie('username', 'ben', time() + 60*60*24*365, '/');
echo $_GET['callback'].'('.json_encode(array('status' => 1,'msg' => 'ok')).')';
}else{
echo $_GET['callback'].'('.json_encode(array('status' => -2,'msg' => '用户名或密码错误')).')';
}
http://passport.b.com/logout.php(b站登出接口)
<?php
setcookie('username', 'ben', time() - 60, '/');

header("Cache-control:no-cache,no-store,must-revalidate");
header("Pragma:no-cache");
header("Expires:0");

header("Location:http://www.a.com");


以上的代码在firefox和chome中运行良好,在IE和safari中却出了问题:

IE的问题:

在IE中测试时发现login.php接口始终中不上cookie。

解决方案:

其实很简单,在种cookie前用php设置一下p3p头即可,在login.php的setcookie方法前加上如下代码:

<span style="font-size:10px;">header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');</span>


safari的问题:
在safari中有IE一样的问题,处理起来比IE要稍微复杂一点,必须使用302跳转来种cookie
解决方案:
不使用script的src标签请求cookie接口,直接使用location.href跳转到指定接口再跳转回该页面,整个过程在较短的时间内就能完成,不会对用户体验造成太大影响。

具体实现代码:

www.a.com/index.php部分代码:

<script>
$(function(){
$("#submit").click(function() {
var username = $("#username").val();
var password = $("#password").val();
if(!username || !password){
$("#tips").html('用户名和密码不能为空!');
}else{
<span style="color:#00cccc;">var explorer =navigator.userAgent;
if(explorer.indexOf("Safari") >= 0){
//safari下需要做跳转
location.href='http://passport.b.com/loginForSafari.php?username=' + username + '&password=' + password;</span>
}else{
//在safari之外的浏览器是可以这样实现的
var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = 'http://passport.b.com/login.php?username=' + username + '&password=' + password + '&callback=doSomething';
$("body").append( script );
}
}
});
});
</script>

passport.b.com/loginForSafari.php(b站为Safari设置的登录接口):

<?php
if(!empty($_GET['username']) && !empty($_GET['password'])){
if($_GET['username'] == 'ben' && $_GET['password'] == 'lalala'){
setcookie('username', 'ben', time() + 60*60*24*365, '/');
header("Location:http://www.a.com");
exit();
}
}
header("Location:http://www.a.com?msg=".urlencode('用户名或密码错误!'));
exit();


关于php中cookie跨域的解决方案以及IE和safari浏览器中的坑就介绍到这里,希望对各位有所帮助。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  php cookie跨域 IE p3p Safari