极品分享

PHP Session失效不传递的解决办法

在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是否禁用的检测和提示。

<style>
.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;}
</style>

<div class="show" id="NoJs">你禁用了javascript,请开始!否则无法使用后台!</div>
<div class="close" id="NoCookie">你禁用了cookie,请开始!否则无法使用后台!</div>

<script>
//检测是否禁用了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"; 
}
</script>


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的格式为:

http://baidu.com/index.php?PHPSESSID=dsfwer23r23ed

每次自动将sessionid以get参数形式添加到url上,在每个页面直接获得get参数获得sessionid并使用即可

<?php

if($_GET["PHPSESSID"]){
    session_id($_GET["PHPSESSID"]);//这步必须在session_start()之前获取并确定sessionid
 }
 
 session_start();
 echo session_id().'<br/>';

(2)、如果没有修改php.ini配置文件权限,可使用手动GET传sessionid、隐藏表单传递sessionid、服务端将sessionid保存在文件中读写、将sessionid保存在数据库中。这四种方案都可以解决。

A、手动GET传值

s1.php

<?php 
session_start(); 
$_SESSION[’var1’]="中华人民共和国"; 
$sn = session_id(); 
$url="<a href=".""s2.php?PHPSESSID=".$sn."">下一页</a>"; 
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(); 
?>
<input type="text" name="PHPSESSION" value="<?php echo $sn;?>">


C、服务端将session保存在文件中。

login.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html> 
<head> 
<title>Login</title> 
<meta http-equiv="Content-Type" content="text/html; charset=gb2312"> 
</head> 
<body> 
请登录: 
<form name="login" method="post" action="mylogin1.php"> 
用户名:<input type="text" name="name"><br> 
口 令:<input type="password" name="pass"><br> 
<input type="submit" value="登录"> 
</form> 
</body> 
</html>


mylogin1.php

<?php
$name=$_POST[’name’]; 
$pass=$_POST[’pass’]; 
if(!$name || !$pass) { 
echo "用户名或密码为空,请<a href="login.html">重新登录</a>"; 
die(); 
} 
if (!($name=="youngong" && $pass=="123") { 
echo "用户名或密码不正确,请<a href="login.html">重新登录</a>"; 
die(); 
} 
ob_start(); 
session_start(); 
$_SESSION[’user’]= $name; 
$psid=session_id(); 
$fp=fopen("e:/tmp/phpsid.txt","w+"; 
fwrite($fp,$psid); 
fclose($fp); 
//身份验证成功,进行相关操作 
echo "已登录<br>"; 
echo "<a href="mylogin2.php">下一页</a>";
?>


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 "请<a href="login.html">登录</a>后浏览"; 
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使用还有不清楚的地方,可参见之前的文章:


PHP的session会话基本使用


2018-06-17 0 /
PHP学习
/
标签: 

评论回复

回到顶部