经过大量调试,问题似乎(令人尴尬地)出在我的数据库会话代码中,而不是典型的会话问题。你可以在这里看到我的回答 - 谢谢
我知道这可能是类似问题的重复(例如一个、两个、三个),但尽管遵循了似乎是最佳实践,但我仍然遇到问题。
当使用 session_set_save_handler() 使用我的数据库会话类时,会话数据在从 session1.php 重定向后.php会话在会话 2 上开始时被清除。
我的观察概述:
- 数据在会话 1 中正确保存到数据库中.php
- 会话 2 中的 session_start() 上丢失数据.php 在
- 重定向之后和在 session2 中调用 session_start() 之前,数据仍在数据库中.php
- 会话 ID 保持不变,并存储在 cookie 中,该 cookie 在请求标头中正确发送回服务器
- 使用 PHP 的默认会话处理它可以正常工作
并注意:
- exit() 在 header() 之后使用
- 输出前每个页面上的 session_start()
我犯了一个愚蠢的错别字吗?犯了一个愚蠢的错误?或者这是一个奇怪的怪癖?
提前感谢您提供的任何帮助。
以下是代码(在修复此问题时提取到测试文件中):
会话1.php
<?php
require_once('session.php');
session_start();
$_SESSION['KEY'] = 'VALUE PHPSESSID: ' . session_id();
session_write_close();
header('Location: session2.php');
exit;
会话2.php
<?php
require_once('session.php');
session_start();
// Nothing?
var_dump( $_SESSION );
会话.php
<?php
define( "DB_HOST", 'localhost' );
define( "DB_USER", '******' );
define( "DB_PWD", '******' );
define( "DB_NAME", '******' );
require_once('class/DatabaseSessionHandler.php');
// Use the DatabaseSessionHandler class to handle sessions
$session_handler = new DatabaseSessionHandler;
// Set up the handler above as the default session handler
session_set_save_handler(
array($session_handler, 'open'),
array($session_handler, 'close'),
array($session_handler, 'read'),
array($session_handler, 'write'),
array($session_handler, 'destroy'),
array($session_handler, 'gc')
);
DatabaseSessionHandler.php
<?php
class DatabaseSessionHandler
{
protected $connection;
protected $session_life_time;
public function __construct()
{
// Ensure that everything is closed correctly as
// per warning on http://uk3.php.net/session_set_save_handler
register_shutdown_function( 'session_write_close' );
}
public function open( $save_path, $session_name )
{
$this->connection = new mysqli( DB_HOST, DB_USER, DB_PWD, DB_NAME );
$this->session_life_time = get_cfg_var( "session.gc_maxlifetime" );
if ( $this->connection->connect_error )
return false;
return true;
}
public function close()
{
$this->connection->close();
return true;
}
public function read( $session_id )
{
$data = '';
$statement = $this->connection->prepare( "SELECT `session_data`
FROM `session`
WHERE `session_id` = ? " );
$statement->bind_param( "s", $session_id );
$statement->execute();
$statement->bind_result( $data );
return (string) $data;
}
public function write( $session_id, $session_data )
{
$expiry_time = time() + $this->session_life_time;
$statement = $this->connection->prepare( "REPLACE INTO `session`
(`session_id`, `session_data`,
`expiry_time`)
VALUES (?, ?, ?)" );
$statement->bind_param( "ssi", $session_id, $session_data, $expiry_time );
if ( !$statement->execute() )
return false;
return true;
}
public function destroy( $session_id )
{
$statement = $this->connection->prepare( "DELETE FROM `session`
WHERE `session_id` = ?" );
$statement->bind_param( "s", $session_id );
if ( !$statement->execute() )
return false;
return true;
}
public function gc( $max_lifetime )
{
$current_time = time();
$statement = $this->connection->prepare( "DELETE FROM `session`
WHERE `expiry_time` < ?" );
$statement->bind_param( "i", $current_time );
if ( !$statement->execute() )
return false;
return true;
}
}
您清除的会话数据少于当前时间。 它应该是当前时间 - max_lifetime
这是解决方案
public function gc( $max_lifetime )
{
$current_time = time() - $max_lifetime;
$statement = $this->connection->prepare( "DELETE FROM `session`
WHERE `expiry_time` < ?" );
$statement->bind_param( "i", $current_time );
if ( !$statement->execute() )
return false;
return true;
}
经过大量的文件记录和打印变量(某些会话函数是在向浏览器发送输出后调用的,因此您无法以正常方式输出错误)事实证明问题出在我的数据库会话代码上。
在将MySQLi输出绑定到变量后,我忘记添加"$statement->fetch()",因此我从未真正将数据从数据库中获取。
这是一个令人尴尬的错误,但它有助于带回家,如果你的软件有问题,通常是你的代码有问题,而不是你正在使用的语言或库。
感谢那些评论和回答的人,因此,在过去的几天里,我学到了很多关于PHP会话的知识。