我知道这已被多次询问过,我已经搜过了SO,尝试了所提供的每种组合以及我能想到的每种方法,而且我仍然处于亏损状态。
以下是该方案:
我刚刚编写并完全测试了登录系统。代码按原样处理,但$_SESSION
没有结转。
假设我输入了正确的详细信息:
我检查了多个不同的东西。 print_r($_SESSION)
在表单提交时返回索引(登录所在的位置)上的“Array([user] => 1)”,但在下一页(dashboard.php)上返回“Array()”
这是我的index.php
<?php
include(__DIR__ . '/includes/class_mtg_sessions.php');
$session = new Session();
$session->start_session('_mtg', true);
if(isset($_SESSION['user'])) {
header("Location: dashboard.php");
exit;
}
include(__DIR__ . '/includes/header.php');
?><div id="templatemo_main">
<div class="content_wrapper">
<div class="col_1">
<h2>Client Area</h2>
<p><img src="<?php echo IMAGE_URL; ?>/icon_04.png" alt="Image 4" class="img_fl" /></p>
<p><div id="contact_form" class="col_2 left">
<h3>Login</h3><?php
if(isset($_POST['submit'])) {
$str = array('name', 'password');
foreach($str as $what) {
$_POST[$what] = isset($_POST[$what]) && is_string($_POST[$what]) ? strtolower($db->escape(trim($_POST[$what]))) : null;
if(empty($_POST[$what]))
$mtg->error("You didn't enter a valid ".$what);
}
$selectUser = $db->query("SELECT `id` FROM `users` WHERE ((LOWER(`username`) = '".$_POST['name']."') OR (LOWER(`email`) = '".$_POST['name']."'))");
if(!$db->num_rows($selectUser))
$mtg->error("There doesn't appear to be anyone on record with that ".(filter_var($_POST['name'], FILTER_VALIDATE_EMAIL) ? 'email' : 'username'));
$select = $db->query("SELECT `id`, `username` FROM `users` WHERE LOWER(`username`) = '".$_POST['name']."' OR LOWER(`email`) = '".$_POST['name']."' AND `password` = '".$mtg->fuzzehCrypt($_POST['password'])."'");
if(!$db->num_rows($select))
$mtg->error("Invalid ".(filter_var($_POST['name'], FILTER_VALIDATE_EMAIL) ? 'email' : 'username')."/password combination");
$row = $db->fetch_row($select);
$_SESSION['user'] = $row['id'];
$mtg->success("Welcome back ".$mtg->format($row['username'])."!<br />Redirecting you now...<meta http-equiv='refresh' content='3; url=dashboard.php' />");
echo "</div></div></div></div>";
include(__DIR__ . '/includes/footer.php');
exit;
}
?><form method="post" name="contact" action="index.php">
<div class="col_3">
<label for="name">ID</label>
<input name="name" type="text" class="required input_field" id="name" placeholder="Username/Email" required />
</div>
<div class="col_3 no_margin_right">
<label for="password">Password</label>
<input name="password" type="password" class="required input_field" id="password" maxlength="30" placeholder="Password" required />
</div>
<div class="clear"></div>
<input type="submit" name="submit" value="Submit" class="submit_btn left" />
<input type="reset" name="reset" value="Reset" class="submit_btn right" />
</form>
</div></p>
</div>
</div>
<div class="content_wrapper">
<div class="col_1">
<h2>New member?</h2>
<p><div id="contact_form" class="col_2 left">
Don't have an account? <a href='register.php'>Sign up now!</a><br />
It's completely free and it allows you to track everything about your order(s), place new orders, directly manage how your current order is being processed and much more!
</div></p>
</div>
</div>
</div><?php
include(__DIR__ . '/includes/footer.php');
这是dashboard.php
<?php
include(__DIR__ . '/includes/class_mtg_sessions.php');
$session = new Session();
$session->start_session('_mtg', true);
if(!isset($_SESSION['user'])) {
header("Location: index.php");
exit;
}
include(__DIR__ . '/includes/header.php');
$mtg->userdata($_SESSION['user']);
?> <div id="templatemo_main">
<div class="content_wrapper">
<div class="col_1">
<h2>Client Area</h2>
<p><img src="<?php echo IMAGE_URL; ?>/icon_04.png" alt="Image 4" class="img_fl" /></p>
<p><div id="contact_form" class="col_2 left">
<h3>Dashboard</h3>
Dashboard coming soon
</div></p>
</div>
</div>
</div><?php
include(__DIR__ . '/includes/footer.php');
最后,我正在使用的会话类。
<?php
ini_set('display_errors', true);
error_reporting(E_ALL);
class Session {
function __construct() {
session_set_save_handler(
array(&$this, 'open'),
array(&$this, 'close'),
array(&$this, 'read'),
array(&$this, 'write'),
array(&$this, 'destroy'),
array(&$this, 'gc')
);
register_shutdown_function('session_write_close');
}
function start_session($session_name, $secure) {
if(in_array('sha512', hash_algos()))
ini_set('session.hash_function', 'sha512');
ini_set('session.hash_bits_per_character', 5);
ini_set('session.use_only_cookies', 1);
$cookieParams = session_get_cookie_params();
session_set_cookie_params($cookieParams['lifetime'], $cookieParams['path'], $cookieParams['domain'], $secure, true);
session_name($session_name);
session_start();
session_regenerate_id(true);
}
function open() {
include(__DIR__ . '/definitions.php');
$this->db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_BASE) or exit("Couldn't connect to the database");
return true;
}
function close() {
$this->db->close();
return true;
}
function read($id) {
if(!isset($this->read_stmt))
$this->read_stmt = $this->db->prepare("SELECT `data` FROM `sessions` WHERE `id` = ? LIMIT 1");
$this->read_stmt->bind_param('s', $id);
$this->read_stmt->execute();
$this->read_stmt->store_result();
$this->read_stmt->bind_result($data);
$this->read_stmt->fetch();
$key = $this->getkey($id);
$data = $this->decrypt($data, $key);
return $data;
}
function write($id, $data) {
$key = $this->getkey($id);
$data = $this->encrypt($data, $key);
$time = time();
if(!isset($this->w_stmt))
$this->w_stmt = $this->db->prepare("REPLACE INTO `sessions` (`id`, `set_time`, `data`, `session_key`) VALUES (?, ?, ?, ?)") or trigger_error(mysqli_error($this->db));
$this->w_stmt->bind_param('siss', $id, $time, $data, $key);
$this->w_stmt->execute();
return true;
}
function destroy($id) {
if(!isset($this->delete_stmt))
$this->delete_stmt = $this->db->prepare("DELETE FROM `sessions` WHERE `id` = ?") or trigger_error(mysqli_error($this->db));
$this->delete_stmt->bind_param('s', $id);
$this->delete_stmt->execute();
return true;
}
function gc($max) {
if(!isset($this->gc_stmt))
$this->gc_stmt = $this->db->prepare("DELETE FROM `sessions` WHERE `set_time` < ?") or trigger_error(mysqli_error($this->db));
@$this->gc_stmt->bind_param('s', (time() - $max));
$this->gc_stmt->execute();
return true;
}
private function getkey($id) {
if(!isset($this->key_stmt))
$this->key_stmt = $this->db->prepare("SELECT `session_key` FROM `sessions` WHERE `id` = ? LIMIT 1") or trigger_error(mysqli_error($this->db));
$this->key_stmt->bind_param('s', $id);
$this->key_stmt->execute();
$this->key_stmt->store_result();
if($this->key_stmt->num_rows == 1) {
$this->key_stmt->bind_result($key);
$this->key_stmt->fetch();
return $key;
} else {
$random_key = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true));
return $random_key;
}
}
private function encrypt($data, $key) {
$salt = 'agar16565!sfrb0a0$£%^&njswdUEB(*£8034672839ngrwu*(£89bgaq90hmw4n';
$key = substr(hash('sha256', $salt . $key . $salt), 0, 32);
if(!function_exists('mcrypt_get_iv_size'))
exit("mCrypt not enabled");
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_ECB, $iv));
return $encrypted;
}
private function decrypt($data, $key) {
$salt = 'agar16565!sfrb0a0$£%^&njswdUEB(*£8034672839ngrwu*(£89bgaq90hmw4n';
$key = substr(hash('sha256', $salt . $key . $salt), 0, 32);
if(!function_exists('mcrypt_get_iv_size'))
exit("mCrypt not enabled");
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($data), MCRYPT_MODE_ECB, $iv);
return $decrypted;
}
}
users
和sessions
表的数据库结构(使用SHOW CREATE TABLE
):
CREATE TABLE `sessions` (
`id` char(128) NOT NULL,
`set_time` char(10) NOT NULL,
`data` text NOT NULL,
`session_key` char(128) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
KEY `session_key` (`session_key`),
KEY `set_time` (`set_time`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL DEFAULT '',
`email` varchar(255) NOT NULL DEFAULT '',
`verified` enum('Yes','No','Flagged') NOT NULL DEFAULT 'No',
`ver_code` varchar(255) NOT NULL DEFAULT '',
`password` varchar(255) NOT NULL DEFAULT '',
`ip` varchar(255) NOT NULL DEFAULT '',
`country` varchar(255) NOT NULL DEFAULT '',
`type` enum('standard','admin') NOT NULL DEFAULT 'standard',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `email` (`email`),
KEY `type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
现在,我在同一服务器上托管的不同站点上使用相同的类,它的工作非常好。 我已经检查了tmp目录的权限,这些都很好(我有WHM / SSH访问权限) 所有应该连接到数据库的类都已完全正常连接,没有问题
有人请把我从痛苦中解救出来,并保留我理智中剩下的东西!
[编辑] [1]
我尝试了w00d的方法(将session_regenerate_id(true)
设置为false
),但仍然没有运气)
我也尝试完全删除session_regenerate_id(true);
,同样的问题仍然存在
[编辑] [2]
删除对会话类的调用并使用标准session_start()
似乎“修复”它,但在这样做时,我不情愿地禁用了数据库系统。
正如我所说的那样,该类在使用相同服务器的另一个站点上完美运行,那么这可能是什么问题呢?
答案 0 :(得分:0)
问题可能在这里:
session_regenerate_id(true);
为什么呢? taken here
bool session_regenerate_id([bool $ delete_old_session = false]) session_regenerate_id()将使用new替换当前会话ID 一,并保留当前的会话信息。
每次执行start_session
时,它都会替换信息。
您可以尝试删除true
,看看它是否按预期工作。
答案 1 :(得分:0)
“会话可能正在使用”的原因
会话作业结束后放置硬编码session_write_close();
应该注意register_shutdown_function()不保证session_write_close();正如你所做的那样