PHP会话ID在页面之间变化

12

我遇到了一个问题,就是在两个页面之间失去了PHP会话。

session_start() 在一个名为 session-inc.php 的文件中被包含到需要设置会话的每个页面中。这对站点上的所有页面都有效,除了一个特定的页面 member-profile.php。当访问此页面时,会设置并使用一个新的具有不同 id(相同会话名称)的会话。

一些更多的细节:

  • 会话名称是手动设置的
  • 所有页面都在同一个服务器上,使用相同的域名
  • 如果在 member-profile.php 文件中的 include('session-inc.php') 之前添加额外的 session_start(),会话将正确转移
  • 我尝试在 .htaccess 中设置 session_cookie_domain 和 session.session_name,这对于此域名有效,但会话停止传递到我们的支付域
  • 我们正在运行 apache 2.2.6 和 php 5.2.5

将 session_start() 放在 member-profile.php 文件中的 include('session-inc.php') 之前是解决此问题的快速脏方法,但我想知道为什么会出现这种情况。

谢谢

Will


你能发布一下你的文件 session-inc.php 的内容吗?在 member-profile.php 中,include('session-inc.php'); 是你做的第一件事吗? - Dominik
11个回答

8
根据PHP文档,必须在向浏览器发送任何输出之前调用session_start函数--这个页面是否存在流氓的CR/LF、Unicode字节顺序标记或类似的东西,在你包含session-inc.php文件之前导致输出?

嗨,Ken我已经检查了脚本,似乎在session_start()调用之前没有任何输出。 - willparkinson

3
在将传统网站从PHP4迁移到PHP5时,我注意到了一个php.ini配置设置,它会导致php在每个请求时自动启动会话。这是一种替代方法,可以避免在每个页面上放置“session_start()”的方法。
有多种方法可以启用此设置:
将以下行放入php.ini中:
session.auto_start = on

或者将以下内容加入您的Apache虚拟站点配置文件或.htaccess文件中:

<IfModule mod_php5.c>
  php_flag session.auto_start on
</IfModule>

它应该使$_SESSION的更改在所有页面上都可用


在每个页面上放置 session_start() 并不会在每个请求上创建一个新的会话。根据手册,session_start() 通过传递 GET 或 POST 请求中的会话标识符或通过 cookie 传递来创建一个会话或恢复当前会话。 - user559533

3
我刚遇到了这个问题。有趣的是,通过 http://127.0.0.1 而不是 http://localhost 进行浏览可以帮助我解决它。

2
那不是一个答案,那只是回避问题的方式。 - John
这也是关于约翰实际问题的一个线索。 - undefined

1
我刚刚花了一整天的时间来诊断我的Ionic3-PHP项目中的问题。简而言之,确保您的客户端实际上发送了会话凭据。
为了帮助犯同样错误的人,我将分享如何找到问题的方法。我使用了以下工具来诊断客户端和服务器上的会话:
1)在服务器上添加一个包含phpinfo()的测试文件以查看PHP会话选项。
2)检查PHP代码,确保在session_start()行之前没有任何输出,无论是有意还是无意的。检查Visual Studio Code的状态栏,确保PHP文件中没有字节顺序标记(BOM)。
3)查看服务器PHP日志(对我来说是/var/log/nginx/error.log)。在php文件中添加error_log()行以转储session_id()或$_SESSION数组。
4)使用tcpdump -An 'port 80 or port 443'查看实际的HTTP请求和响应。(这就是我发现缺失cookie的地方)。
对于Ionic3数据提供程序,客户端的正确语法是:
    var obsHttp = this.http.post(url, body,
  { headers: new HttpHeaders({
    'Content-Type':'application/x-www-form-urlencoded'
  }),withCredentials: true }).timeout(this.timeoutTime);

注意 withCrentials:true,需要调用 subscribe() 方法来发送请求。

0

找到了问题

在我的情况下,这是由于Varnish设置引起的,请检查您的Varnish设置。您可以从Varnish设置中排除PHPSESSID cookie。


0
我不是专家,但在仔细调查了Firefox上打开的两个网页的cookie信息中的域名后找到了解决方案。(右键单击页面,选择检查和存储)。检查了域名,发现一个是www.example.com,另一个没有www(example.com)。将所有页面链接更改为相同的格式,我的问题得到了解决。

1
目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何撰写好答案的更多信息。 - Sujith Sandeep

0

发现问题

第二个域的主要包含文件开头有一个字节顺序标记。正如Ken所说,不能在会话开始之前有任何输出,因此它没有正确设置会话。


0
解决方案: 在php.ini文件中添加以下代码:session.auto_start = on
这将解决页面重新加载(刷新/更改页面)时重新生成会话ID的问题。
此问题出现在CPanel更新后(包括Multi PHP),即使php版本保持不变。
PHP.ini文件根本没有这个变量。进入Cpanel-> MultiPHP INI编辑器->编辑模式(不是基本模式,基本模式下没有此设置),并添加该行。按保存按钮保存。
提示/何时使用此解决方案: 要确定是否存在此问题,请在index.php文件的开头和结尾放置一行代码以检查会话ID。使用函数:session_id(); 浏览页面/重新加载页面。如果session_id值发生更改,则问题不在您的代码中,此解决方案应解决您的问题(会话在您的代码之外丢失)。
我还尝试验证Web服务器上保存会话的可用性(session.save_path),但即使它是一个线索,也不是这种情况。 我想这是Cpanel与MULTIPHP UPDATE的“功能”,这种情况可能经常发生。

0

我曾经遇到过这个问题,原因是PHP在第一个100个cookie之后忽略了所有的cookie。(我问了这个问题以找出原因, 但目前还没有人弄清楚)。浏览器发送了PHPSESSID*,但由于它是第110个cookie,所以PHP忽略了它。

为了确定这个问题是否影响了您,使用浏览器的开发工具查看浏览器发送的请求中的cookie列表,并将其与PHP中的$_COOKIE数组进行比较。它们应该是相同的。但如果浏览器发送了PHPSESSID*,而$_COOKIE中没有PHPSESSID*,那么这就解释了为什么会话不起作用。

我通过减少我的网站使用的cookie数量来解决这个问题,这也是一个好的实践。

* PHPSESSID是默认的会话名称。您的网站可能使用不同的名称。


0
为了解决每个请求后session_id的变化,您需要修改php配置文件中的参数 session.auto_start session.cookie_httponly
要找到使用的php配置文件。
php -i | grep "php.ini"

然后你打开它,尝试找到参数 session.auto_start。你设置

session.auto_start = 1
session.cookie_httponly = 0

最后,您重新启动了httpd / apache服务。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接