关于 php:session_set_save_handler 导致登录循环
session_set_save_handler causing login loop
我正在尝试使用 session_set_save_handler() 将会话写入数据库。我遇到了一个无限循环,我的系统想要让我登录,但找不到会话,所以它让我退出......但会话显然存在 - 只是不在表中。
无论如何,这是我的会话函数代码 - 我不认为这里有什么问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
<?php // session.functions.php $db = new mysqli("127.0.0.1","user","pass","db"); // define 'openSession()' function function openSession($sessionPath, $sessionName) { return true; } // define 'closeSession()' function function closeSession() { return true; } // define 'readSession()' method function readSession($sessionId) { global $db; // escape session ID $sessionId = $db->real_escape_string($sessionId); $result = $db->query("SELECT sessiondata FROM sessions WHERE sessionid='$sessionId' AND expiry > NOW()"); if ($result->num_rows > 0) { $row = $result->fetchRow(); return $row['sessiondata']; } // return empty string return""; } // define 'writeSession()' function function writeSession($sessionId, $sessionData) { global $db; $expiry = time() + get_cfg_var('session.gc_maxlifetime') - 1; // escape session ID & session data $sessionId = $db->real_escape_string($sessionId); $sessionData = $db->real_escape_string($sessionData); $result = $db->query("SELECT sessionid FROM sessions WHERE sessionid='$sessionId'"); // check if a new session must be stored or an existing one must be updated ($result->num_rows > 0) ? $db->query("UPDATE sessions SET sessionid='$sessionId',expiry='$expiry',sessiondata= '$sessionData' WHERE sessionid='$sessionId'") or die(mysqli_error($db)) : $db->query("INSERT INTO sessions (sessionid,expiry,sessiondata) VALUES ('$sessionId','$expiry','$sessionData')") or die(mysqli_error($db)); return true; } // define 'destroySession()' function function destroySession($sessionId) { global $db; // escape session ID $sessionId = $db->real_escape_string($sessionId); $db->query("DELETE FROM sessions WHERE sessionid='$sessionId'"); return true; } // define 'gcSession()' function function gcSession($maxlifetime) { global $db; $db->query("DELETE FROM sessions WHERE expiry < NOW()"); return true; } ?> |
这是登录的会话设置:
1 |
$this->set_session(array_merge($rs->fetch_assoc(), array('expires' => time() + (15 * 60))));
|
按功能设置:
1 2 3 4 5 |
private function set_session($a=false) { if (!empty($a)) { $_SESSION['exp_user'] = $a; } } |
我的登录系统如何检查我是否已经登录?
1 2 3 4 5 6 7 |
public function check_status() { if (empty($_SESSION['exp_user']) || @$_SESSION['exp_user']['expires'] < time()) { return false; } else { return true; } } |
原来,$_SESSION的值,根据var_dump是array(0) { }
以及检查 Web 应用程序本身:
1 2 3 4 5 6 7 8 |
// This is in authorisation.php if(empty($_SESSION['exp_user']) || @$_SESSION['exp_user']['expires'] < time()) { header("location:/login.php"); //@ redirect } else { $_SESSION['exp_user']['expires'] = time()+(15*60); //@ renew 15 minutes //echo $SID = session_id(); } |
现在,这就是我在顶部的 index.php 文件中的内容:
1 2 3 4 |
require('includes/session.functions.php'); session_set_save_handler('openSession', 'closeSession', 'readSession', 'writeSession', 'destroySession', 'gcSession'); session_start(); include('includes/authorisation.php'); |
这是数据库:

如果我注释掉 session_set_save_handler(),我们不会得到循环,但是,如果我保持它在那里运行,我会得到索引和登录系统之间的循环(已经登录 -> 索引 ::check登录循环。)
1 2 3 |
print_r(session_set_save_handler('openSession', 'closeSession', 'readSession', 'writeSession', 'destroySession', 'gcSession')); == 1 var_dump(session_set_save_handler('openSession', 'closeSession', 'readSession', 'writeSession', 'destroySession', 'gcSession')); == bool(true) |
知道我做错了什么吗?
- 您的数据库架构丢失。加上一个教程:在数据库中存储会话
- get_magic_quotes_gpc() 和数据库转义是两个不同的主题。不要混合它们。
- 添加了数据库模式并从代码中删除了 get_magic_quotes_gpc()。
- 检查session_set_save_handler的返回值,失败返回FALSE,成功返回TRUE。
- bool(true) 或 1。显然,它可以使用 print_r 和 var_dump 检查
- 好的。下一个:当您将其写入数据库时??,您需要转义 id 旁边的 $sessionData 。
- 只是在脚本中更改了它:)
- 因此,为了更好地调试,请删除重定向标头。只需打印一个链接而不是一条消息。然后 exit; 在该点停止执行(也可以使用标题)。然后是 var_dump if 之前的 $_SESSION。这将为您提供更多信息,并且您不会自动循环。
- ok,$_SESSION的值,根据var_dump是array(0) { }
- 如果会话正确存储在数据库中(检查会话数据是否实际包含某些内容),则读取失败。如果会话数据库中的数据为空,则写入失败。
- 在我看来,就像写作失败了:调用非成员函数来转义 $sessionID。
- 调用该函数时,看起来全局数据库对象已经被销毁。我想知道为什么,也许您在某处未设置 $db 变量?这是手册中的其他一些重要说明: 注意:直到输出流关闭后才会执行"写入"处理程序。因此,"write"处理程序中调试语句的输出将永远不会在浏览器中看到。如果需要调试输出,建议将调试输出写入文件。
- Nopem $db 永远不会取消设置,我什至在 session.functions.php 中重新定义了它
- 这是我发现的: 注意:未定义的变量:第 35 行 /home/erp/public_html/includes/session.functions.php 中的 sessionId。它完美地写入数据库 - (通过使用函数输入任意数据进行检查)。
- 检查第 35 行,这里的代码没有行号。
- 第 35 行是 $sessionId = $db->real_escape_string($sessionId);
- 这边比较晚,祝你进一步调试好运。
- 谢谢hakre,现在是12:26:/
- 外部参考:stackoverflow.com/questions/6418856/…
您似乎混淆了两种不同的时间格式。在 mysql 中,NOW() 以以下格式为您提供时间:
Returns the current date and time as a value in 'YYYY-MM-DD HH:MM:SS' or YYYYMMDDHHMMSS.uuuuuu format, depending on whether the function is used in a string or numeric context.
在 php 中,time() 给你:
Returns the current time measured in the number of seconds since the Unix Epoch (January 1 1970 00:00:00 GMT).
在您的 sql 语句中,您正在比较两者,您可以吗?因为它们是完全不同的格式。
- 在服务器上的脚本中修复。没有骰子。
原来有一个额外的 session_start(),它会重置会话。