php - session_write_close():无法使用用户定义的保存处理程序写入会话数据。PHP 7.3.1
问题描述
我编写了一个自定义会话处理程序类,它在大多数情况下都有效,直到我尝试注销我的用户并销毁会话,然后我不断收到以下错误:
ErrorException: 0
session_write_close(): Failed to write session data using user defined save handler. (session.save_path: D:\xampp\tmp)
我在 XAMPP 上运行 PHP 版本 7.3.1。
这是我的自定义课程
class CornerstoneSessionHandler implements SessionHandlerInterface {
/**
* Construct the Session
* No parameters required, nothing will be returned
*/
public function __construct() {
// Set the handler to overide SESSION
session_set_save_handler(
array($this, "open"),
array($this, "close"),
array($this, "read"),
array($this, "write"),
array($this, "destroy"),
array($this, "gc")
);
// Set the shutdown function
register_shutdown_function('session_write_close');
/** Define and initialise the Session Handler */
session_start();
}
/**
* Set the open callback
*
* @param string $savePath
* @param string $sessionName
*
* @return bool return value should be true for success or false for failure
*/
public function open($savePath, $sessionName) {
// Make the $csdb global accessible
global $csdb;
// Check that the DB connection is set
return ((!empty($csdb)) && $csdb->isConnected() != 1) ? FALSE : TRUE ;
}
/**
* Set the close callback
*
* @return bool return value can only be true for success
*/
public function close() {
return TRUE;
}
/**
* Set the read callback
*
* @param string $sessionID
*
* @return string return value should be the session data or an empty string
*/
public function read($sessionID) {
// Make the $csdb global accessible
global $csdb;
// Get the session from the database
$csdb->query_prepared("SELECT session_data FROM cs_session WHERE session_id=?", [$sessionID]);
// If results returned, continue
if($csdb->getNum_Rows() > 0) {
// Get the data
$result = $csdb->get_row(NULL);
return $result->session_data;
} else { // Else return an empty string
return '';
}
}
/**
* Set the write callback
*
* @param string $sessionID
* @param string $data
*
* @return bool return value should be true for success or false for failure
*/
public function write($sessionID, $data) {
// Make the $csdb global accessible
global $csdb;
// Set the time stamp
$access_dtm = new \DateTime();
// Replace the data
$csdb->query_prepared('REPLACE INTO cs_session(session_id, session_ip_address, session_data , session_access_dtm) VALUES (?, ?, ?, ?)', [$sessionID, $_SERVER['REMOTE_ADDR'], $data, $access_dtm->format('Y-m-d H:i:s')]);
// If modified a success, return true
if($csdb->getNum_Rows() > 0) {
return TRUE;
} else { // Else, return false
return FALSE;
}
}
/**
* Set the destroy callback
*
* @param string $sessionID
*
* @return bool return value should be true for success or false for failure
*/
public function destroy($sessionID) {
// Make the $csdb global accessible
global $csdb;
// Delete the session from the database
$csdb->delete('cs_session', where(eq('session_id', $sessionID)));
// If results returned, return true
if($csdb->affectedRows() > 0) {
return TRUE;
} else { // Else, return false
return FALSE;
}
}
/**
* Set the garbage collector callback
*
* @param string $lifetime
*
* @return bool return value should be true for success or false for failure
*/
public function gc($lifetime) {
// Make the $csdb global accessible
global $csdb;
// Set the date calculation
$expiredTime = new \DateTime();
$expiredTime->modify('-' . $lifetime . ' seconds');
// Get the session from the database
$csdb->delete('cs_session', where(lt('session_access_dtm', $expiredTime->format('Y-m-d H:i:s'))));
// If results deleted, return true
if($csdb->affectedRows() > 0) {
return TRUE;
} else { // Else, return false
return FALSE;
}
}
}
我使用ezSQL作为我的数据库处理程序。
这是我所有页面顶部的代码
/**
* Set session data so that logins work properly over all browsers
* This should fix login errors some users can face
* More info can be found at {@link https://www.php.net/manual/en/session.security.ini.php the php user manual}
*/
# PREVENTING SESSION HIJACKING
# Prevents javascript XSS attacks aimed to steal the session ID
ini_set('session.cookie_httponly', 1);
# Make sure the cookie lifetime is set to '0'
ini_set('session.cookie_lifetime', 0);
# Adds entropy into the randomization of the session ID, as PHP's random number
# generator has some known flaws
ini_set('session.entropy_file', '/dev/urandom');
# Uses a strong hash
ini_set('session.hash_function', 'whirlpool');
# Set the session save location (best for shared servers)
# Uncomment out the next line if you would like to set a custom path and haven't already set the value in your `php.ini` file.
# ini_set('session.save_path',realpath(ABSPATH . 'tmp' . DIRECTORY_SEPARATOR));
# Note: The folder referenced above must exist for it to work.
# Set the session garbage collection lifetime to custom defined minutes (PHP default is 24 minutes)
ini_set('session.gc_maxlifetime', (int)get_option("session_expire") * MINUTE_IN_SECONDS);
# Enable session garbage collection with a 1% chance of
# running on each session_start()
ini_set('session.gc_probability', 1);
ini_set('session.gc_divisor', 100);
# Uses a secure connection (HTTPS) if possible
# Allow cookies to be sent over insecure connections if not an HTTPS site
(SITE_HTTPS) ? ini_set('session.cookie_secure', 1) : ini_set('session.cookie_secure', false);
# PREVENTING SESSION FIXATION
# Session ID cannot be passed through URLs
# so only use cookies to store the session id on the client side
ini_set('session.use_only_cookies', 1);
# Set a custom session name
session_name('CSSESSID');
# Load the session class
new CornerstoneSessionHandler();
# Start the session if it's not already started
if (session_status() == PHP_SESSION_NONE) {session_start();}
奇怪的是,即使它给了我那个错误,如果我检查数据库,数据正在更新,不用担心。
这是我的注销代码
/**
* Logout the user
*
* @return bool
*/
public static function logoutUser() {
// Make the $fear global accessible
global $fear; // Direct access check
// Check if session set (just in case) and start if it isn't
if(session_id() == '') {session_start();}
// Delete the $_SESSION data set in `authenticateUser()`
unset($_SESSION['HTTP_USER_AGENT']);
unset($_SESSION['_cs-uid']);
unset($_SESSION['_cs-ue']);
unset($_SESSION['_cs-ul']);
unset($_SESSION['_cs-un']);
/**
* Get the "ext.auth.php" file and run `clearCustomAuth()` function
* to clear any custom set $_SESSION items
*/
require_once( get_lib_path('ext.auth.php') );
clearCustomAuth();
// Regenerate a new session ID just to be sure
session_regenerate_id();
// Destroy the session
session_destroy();
// Check if the $_COOKIE data if set
if(isset( $_COOKIE['_cs-ti'] ) && !empty( $_COOKIE['_cs-ti'] )) {
// Delete the cookie token from the database
if(!self::deleteAuthCookie($_COOKIE['_cs-ti'])) {
// Return false if cookie couldn't be deleted
return false;
}
}
// Return true if run all the way
return true;
}
我尝试过转移,session_regenerate_id()
但是如果我把它放在它之后session_destroy()
它说没有要重新生成的会话,但是如果我把它放在它之前session_destroy()
或者根本没有它,我的会话将从我的数据库中删除但我仍然可以看到它在我的 Firefox 检查器中的存储中。
尝试从数据库中删除会话时,它只会给我一个错误。其他一切正常,不用担心!我在测试中手动尝试从数据库中删除一个会话,但我仍然收到该错误。
有没有人能够看到我可能做错了什么或如何解决它?我刚刚才知道这对它来说非常新。如果我需要提供更多信息,请告诉我。我已经在网上搜索了将近 2 天,但没有运气。
解决方案
我看不出您需要设置关闭处理程序的原因。当 php 关闭时,会话会自动保存,即使您遇到致命错误也是如此。
即使没有更新/删除行,write、destroy 和 gc 也应该始终返回 true。这似乎违反直觉,但 php 认为删除不存在的会话也是成功的。
推荐阅读
- cmd - 检查正在运行的 lua 脚本
- ios - 如何构建自己的集成到 Watson 的 IOS/android 聊天界面
- javascript - 如何使用ajax中的数据将整数数组传递给控制器
- jenkins - Jenkins Job 在尝试执行文本替换时返回文件未找到
- java - 从 Kafka 消息中在 spring sleuth 中注入 TraceId
- c# - c# lambda 属性映射到字符串
- file - 独占从 TCL 中的文件读取
- .htaccess - htacces 重定向无限循环
- amazon-s3 - 如何配置 MarkLogic 在启动备份并指向 S3 兼容对象存储期间发送 PUT 请求?
- selenium - 为什么 WinAppDriver.exe 会立即关闭?