Bạn đang sử dụng Codeigniter. Nó có tính năng lưu trữ các phiên vào cơ sở dữ liệu đã được tích hợp sẵn.
Chỉ cần xóa mã không hoạt động của bạn và sử dụng tính năng của Codeigniter để thay thế. Bạn chỉ cần định cấu hình nó.
Ngoài ra, nếu bạn thực sự muốn "ở lại với mình", có nhiều vấn đề với mã của bạn. Chúng rất dễ phát hiện nếu bạn tuân theo các điểm sau:
- Đọc về từng hàm gọi lại cho trình xử lý lưu phiên. Đặc biệt là dữ liệu họ nhận được và ở định dạng nào (không làm như vậy dẫn đến ít nhất một lỗi có thể kích hoạt hành vi mà bạn mô tả là "không hoạt động").
- Ghi nhật ký lỗi. Việc gặp sự cố với trình xử lý lưu dẫn đến lỗi có thể khiến chúng không nhìn thấy được vì không thể xuất ra trình duyệt nữa. Điều này yêu cầu bạn ghi lỗi vào tệp. Điều này rất quan trọng khi bạn khắc phục sự cố bằng trình xử lý lưu phiên.
- Di chuyển mã tương tác cơ sở dữ liệu ra khỏi đường đi. Điều này cũng cho phép bạn cung cấp thông tin lỗi tốt hơn trong trường hợp tương tác cơ sở dữ liệu không thành công (không làm như vậy ẩn ít nhất một lỗi có thể dẫn đến hành vi mà bạn mô tả là "không hoạt động").
- Xóa mã không cần thiết. Ý tôi là, nó không cần thiết. Có mã không cần thiết có thể bao gồm các lỗi dẫn đến tình huống "không hoạt động" mà bạn có ở đây. Vì vậy, bạn đang tự cản trở mình hoàn thành công việc mà không có lý do. Một ví dụ:
ini_set("session.save_handler", "user");
- miễn là bạn không có manh mối về những gì bạn làm, đừng làm điều đó. Không có trình xử lý lưu xác định trước nào được gọi làuser
trong PHP, bạn cũng không phải định nghĩa cái đó.
Và về cơ bản đó là nó. Vì vậy, tôi có thể phát hiện ra hai lỗi thực sự gây ra điều này, các bước khác là cần thiết để bạn có thể giải quyết các sự cố trong tương lai:
- Đảm bảo bạn luôn liên quan đến cùng một bảng cơ sở dữ liệu. Ví dụ:nếu bạn viết vào bảng
MY_SESSIONS
và đọc từ bảngSESSIONS
, điều này sẽ không bao giờ hiệu quả. - Đảm bảo rằng dữ liệu bạn cung cấp lại cho PHP tương thích với dữ liệu mà PHP mong đợi. Ví dụ:nếu bạn lưu trữ dữ liệu được mã hóa Base64 vào cơ sở dữ liệu và đưa nó trở lại cơ sở dữ liệu đã mã hóa Base64 của PHP, thì PHP không thể làm gì với dữ liệu đó.
Các vấn đề tiềm ẩn khác không hiển thị trong mã của bạn:
- Lược đồ cơ sở dữ liệu bạn có không phù hợp với dữ liệu bạn lưu trữ trong đó (bạn chưa cung cấp lược đồ bảng nên không thể nói liệu điều này có gây ra sự cố cho bạn hay không).
- Bộ định danh liên kết cơ sở dữ liệu có thể thay đổi vì chính bộ mã đang tạo kết nối cơ sở dữ liệu. Điều này có thể dẫn đến các tác dụng phụ tiềm ẩn. Việc cung cấp mã nhận dạng liên kết một cách rõ ràng cho kết nối cơ sở dữ liệu sẽ giúp bạn có một giấc ngủ thoải mái.
- Lỗi trong các truy vấn SQL không được chú ý vì thiếu phần xử lý lỗi cho các phần cơ sở dữ liệu.
Mã mẫu:
ob_start();
session_name("test");
session_set_cookie_params(0, '/', '.test.com');
$s = new SessionManagement();
$s->register();
session_start();
ECHO $_SESSION['test'], "\n"; # value
SessionManagement
được cấu trúc lại lớp:
class SessionManagement
{
private $_timeout;
private $_db;
public function __construct() {
$CI =& get_instance();
$CI->load->database();
$this->_db = new LegacyMysqlDatabase(
$CI->db->hostname, $CI->db->username, $CI->db->password, $CI->db->database
);
$this->_timeout = 60 * 60 * 10;
}
public function _open() {
return TRUE;
}
public function _close() {
return TRUE;
}
public function _read($session_id) {
$db = $this->_db;
$session_id = $db->escape($session_id);
$sql = "SELECT session_data
FROM SESSION
WHERE session_id = '$session_id'";
if (!($result = $db->query($sql)) || !$result->getNumberOfRows()) {
return '';
}
$record = $result->fetchAssoc();
return $record['session_data'];
}
public function _write($session_id, $session_data) {
$db = $this->_db;
$session_id = $db->escape($session_id);
$session_data = $db->escape($session_data);
$session_expires = time() + $this->_timeout;
$sql = "REPLACE INTO SESSION (session_id, session_data, session_expires)
VALUES ('$session_id', '$session_data', $session_expires)";
return (bool)$db->query($sql); // cast to bool because PHP would cast to int
}
public function _gc($max) {
return TRUE;
}
public function _destroy($id) {
$db = $this->_db;
$session_id = $db->escape($id);
$sql = "DELETE
FROM SESSION
WHERE session_id = '$id'";
return $db->query($sql);
}
public function register() {
$registered = session_set_save_handler(
array($this, '_open'),
array($this, '_close'),
array($this, '_read'),
array($this, '_write'),
array($this, '_destroy'),
array($this, '_gc')
);
if (!$registered) {
throw new Exception('Can not register session savehandler.');
}
}
}
Mã tương tác cơ sở dữ liệu với xử lý lỗi:
class LegacyMysqlDatabase
{
private $_hostname;
private $_username;
private $_password;
private $_database;
private $_link;
private $_initError = false;
public function __construct($hostname, $username, $password, $database) {
$this->_hostname = $hostname;
$this->_username = $username;
$this->_password = $password;
$this->_database = $database;
}
public function query($sql) {
$link = $this->getLink();
$result = mysql_query($sql, $link);
if ($result === false) {
trigger_error(sprintf('Query "%s" failed: #%d: %s', $sql, mysql_errno($link), mysql_error($link)));
throw new Exception('Failed to query Mysql database.');
}
return new LegacyMysqlResult($result);
}
public function escape($string) {
return mysql_real_escape_string($string, $this->getLink());
}
private function getLink() {
if ($this->_initError) {
throw new Exception('Failed to initialize the database.');
}
if ($this->_link === null) {
$this->_initError = true;
$result = mysql_connect($this->_hostname, $this->_username, $this->_password);
if (!$result) {
throw new Exception('Can not connect to Mysql database.');
}
$this->_link = $result;
$selected = mysql_select_db($this->_database, $this->_link);
if (!$selected) {
trigger_error(sprintf('Can not select Mysql database "%s": #%d: %s', $this->_database, mysql_errno($result), mysql_error($result)));
throw new Exception(sprintf('Can not select Mysql database "%"', $this->_database));
}
$this->_initError = false;
}
return $this->_link;
}
}
class LegacyMysqlResult
{
private $_result;
public function __construct($result) {
$this->_result = $result;
}
public function getNumberOfRows() {
return mysql_num_rows($this->_result);
}
public function fetchAssoc() {
return mysql_fetch_assoc($this->_result);
}
}