在PHP中使用过SESSION的过程中,可能会碰到这么一个问题,SESSION变量不能跨页传递。这令我苦恼了好些日子,最终通过查资料思考并解决了这个问题。我认为,出现这个问题的原因有以下几点:
1、客户端禁用了cookie
2、浏览器出现问题,暂时无法存取cookie
3、php.ini中的session.use_trans_sid = 0或者编译时没有打开--enable-trans-sid选项
针对这种情况,我们可以提供两种解决思路:
1、网页做cookie是否禁用的检测,如果禁用了提示用户开启cookie再继续使用。
2、不做检测和提示,换跑道直接规避出现这种情况的可能性。即,不使用cookie来记录session_id
一、PHP中的SESSION机制说明:
在默认情况下,当访客访问网站时,php程序通过预先写好的session_start();命令在服务器端为该访客创建一个session文件,用于存储该访客的变量。
并将创建好的session文件的id发送给客户端,客户端浏览器收到该session_id时,将该session_id存储在浏览器本地cookie中。
当访客离开该网页进入其他网页时,浏览器从本地cookie中取出session_id再发送给服务端,服务端php执行到session_strart()时将不再创建新的session给该访客,而是根据该session_id获得该访客的session变量继续使用,在各个跨网页间进行变量传递,已达到跨网页传递数据和用户信息不丢失的目的。
但是,当访客的客户端浏览器如果禁用了cookie,客户端将无法保存session值,当用户离开该网页进入其他网页时,服务端无法获得session_id和继续使用该session文件,就会把访客当做新用户,再次创建一个session文件给其使用。这样以来session就无法做到跨网页传递数据的目的了。
表现出来的现象就是session失效无法跨网页传递数据。
session id可以使用客户端的Cookie或者Http1.1协议的Query_String(就是访问的URL的“?”后面的部分)来传送给服务器,并非只能使用cookie。
二、对该问题的解决方法:
1、做cookie是否禁用的检测,如果禁用了提示用户开启后再使用。
这里使用js来检测客户端浏览器cookie是否禁用。并提示
这里为了避免js也被禁用,也做了js是否禁用的检测和提示。
.close{display:none;color:red;font-size:16px;font-weight:bold;text-align:center;}
.show{color:red;font-size:16px;font-weight:bold;text-align:center;}
你禁用了javascript,请开始!否则无法使用后台! 你禁用了cookie,请开始!否则无法使用后台!
//检测是否禁用了js
var NoJs= document.getElementById("NoJs");
NoJs.className="close";
//检测是否禁用了cookie
function CookieEnable(){
var result=false;
if(navigator.cookiesEnabled) return true;
document.cookie = "testcookie=yes;";
var cookieSet = document.cookie;
if (cookieSet.indexOf("testcookie=yes") > -1) result=true;
document.cookie = "";
return result;
}
if(!CookieEnable()){
//alert("对不起,您的浏览器的Cookie功能被禁用,请开启");
var NoCookie= document.getElementById("NoCookie");
NoCookie.className="show";
}
2、不使用cookie存储session_id的方法:
(1)、开启透明SID
需要修改的php.ini是:
session.use_trans_sid = 1 //由0改为1
session.use_only_cookies = 0 //是否只使用cookie来保存session值 该参数为1时,上述机制失效。
session.use_cookies = 0 //设置客户端是否使用cookie来保存session值 该参数的值不影响上述机制的进行。这个可改可不改
当在php开启了透明SID后(也就是自动模式),系统会将url后面自动添加PHPSESSID参数。也就是URL的格式为:
每次自动将sessionid以get参数形式添加到url上,在每个页面直接获得get参数获得sessionid并使用即可<?php
if($_GET["PHPSESSID"]){
session_id($_GET["PHPSESSID"]);//这步必须在session_start()之前获取并确定sessionid
}
session_start();
echo session_id().'
';
(2)、如果没有修改php.ini配置文件权限,可使用手动GET传sessionid、隐藏表单传递sessionid、服务端将sessionid保存在文件中读写、将sessionid保存在数据库中。这四种方案都可以解决。
A、手动GET传值
s1.php<?php
session_start();
$_SESSION[’var1’]="中华人民共和国";
$sn = session_id();
$url="下一页";
echo $url;
?>
s2.php<?php
session_id($_GET['PHPSESSID']); //设置session_id必须要在session_start()前
session_start();
echo "传递的session变量var1的值为:".$_SESSION[’var1’];
?>
B、隐藏表单传递session_id
在form表单中,增加<?php
$sn = session_id();
?>
">
C、服务端将session保存在文件中。
login.htmlHTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
Login
请登录:
用户名:
口 令:
mylogin1.php<?php
$name=$_POST[’name’];
$pass=$_POST[’pass’];
if(!$name || !$pass) {
echo "用户名或密码为空,请重新登录";
die();
}
if (!($name=="youngong" && $pass=="123") {
echo "用户名或密码不正确,请重新登录";
die();
}
ob_start();
session_start();
$_SESSION[’user’]= $name;
$psid=session_id();
$fp=fopen("e:/tmp/phpsid.txt","w+";
fwrite($fp,$psid);
fclose($fp);
//身份验证成功,进行相关操作
echo "已登录
";
echo "下一页";
?>
mylogin2.php<?php
$fp=fopen("e:/tmp/phpsid.txt","r";
$sid=fread($fp,1024);
fclose($fp);
session_id($sid);
session_start();
if(isset($_SESSION[’user’]) && $_SESSION[’user’]="laogong" {
echo "已登录!";
}
else {
//成功登录进行相关操作
echo "未登录,无权访问";
echo "请登录后浏览";
die();
}
?>
注:这里可以将每个txt文件名用会员的id命名,方便读写又区分不同用户。
D、将sessionid保存在数据库中。
简单说就是当用户登录成功时,控制器获得了该用户的会员信息和sessionid,将sessionid保存到数据库表中。
当用户进入其他页面时,通过查询数据表中该会员id关联的sessionid来获得session值。如果session失效,则无法获得session值则需要重新登录。
这里就不举例了。
三、种特殊情况:就是服务器配置方面有问题,session文件的保存路径是没有读写权限的,导致session文件无法创建。
解决方法:
1、先建立一个phpinfo文件,查看下你的服务器session存放路径。
phpinfo.php<?php
phpinfo();
?>
运行该文件后查看 session.save_path 的值就是存放路径。
2、测试该存放session文件的路径是否有读写权限:
写一个文件:test.php来测试一下:
echo var_dump(is_writeable(ini_get(“session.save_path”)));
?>
如果返回bool(false),证明文件夹写权限被限制了,你可以给加上写入权限或者在PHP程序中指定一个文件夹存放session。
PHP中指定session存放路径://设置当前目录下session子文件夹为session保存路径。
$sessSavePath = dirname(__FILE__).’/session/’;
//如果新路径可读可写(可通过FTP上变更文件夹属性为777实现),则让该路径生效。
if(is_writeable(sessSavePath) && is_readable(sessSavePath) && is_readable(sessSavePath))
{
session_save_path($sessSavePath);
}else{
echo $sessSavePath." 指定session路径不可读写,请修改权限为777";
}
四、种特殊情况:Bom头原因导致Cookie无法送出。
登录成功后又跳转到登录页面,在提交信息后输出session都是正常的,没有问题,但是页面跳转后,session出现丢失现象,无法正常完成登陆。
通过查找资料,发现原来是bom头的原因。受COOKIE送出机制的限制,在这些文件开头已经有BOM的文件中,COOKIE无法送出(因为在COOKIE送出前PHP已经送出了文件头),所以登入和登出功能失效。一切依赖COOKIE、SESSION实现的功能全部无效。
正确的处理方法是去掉某些文件的bom,一般情况是在入口文件出现的bom问题,我处理的方法是用Notepad++打开文件,格式选择以UTF-8无bom格式编码,然后保存,重新上传到服务器即可。但一定要注意,去掉bom上传到服务器之前需要把服务器上源文件删掉,上传覆盖不能去掉bom。
PS:如果文件是UTF-8编码,则确保所有文件都是UTF-8 不能用UTF-8 + BOM
好了,通过这篇文章,我们就对session跨网页失效的原因和解决方案做了详细的说明。
碰到类似奇怪问题,就迎刃而解了。
如果对PHP的Session使用还有不清楚的地方,可参见之前的文章: