Tôi đã tìm thấy trong quá trình gỡ lỗi vài giờ rằng các bài viết tham chiếu được tìm thấy trên nhiều tìm kiếm của Google cũng như một tập hợp con quan trọng của các câu trả lời Stack Overflow chẳng hạn như tại đây , tại đây và tại đây tất cả đều cung cấp thông tin không hợp lệ hoặc lỗi thời.
Những điều có thể gây ra sự cố [nghiêm trọng] khi lưu dữ liệu phiên vào cơ sở dữ liệu:
-
Trong khi tất cả các ví dụ trực tuyến nói rằng bạn có thể "điền"
session_set_save_handler
, không ai trong số họ nói rằng bạn cũng phải đặtregister_shutdown_function('session_write_close')
nữa ( tham khảo ). -
Một số hướng dẫn (cũ hơn) đề cập đến cấu trúc Cơ sở dữ liệu SQL đã lỗi thời và không nên được dùng. Cấu trúc cơ sở dữ liệu mà bạn cần để lưu dữ liệu phiên vào cơ sở dữ liệu là:
id
/access
/data
. Đó là nó. không cần nhiều cột dấu thời gian bổ sung như tôi đã thấy trên một vài "hướng dẫn" và ví dụ.- Một số hướng dẫn cũ hơn cũng có cú pháp MySQL lỗi thời như
DELETE * FROM ...
- Một số hướng dẫn cũ hơn cũng có cú pháp MySQL lỗi thời như
-
Lớp [được đưa ra trong câu hỏi của tôi] phải triển khai
SessionHandlerInterface
. Tôi đã thấy các hướng dẫn (được tham chiếu ở trên) cung cấp cho việc triển khaisessionHandler
mà không phải là một giao diện phù hợp. Có lẽ các phiên bản trước của PHP có một phương thức hơi khác (có thể là <5,4). -
Các phương thức của lớp phiên phải trả về các giá trị được thiết lập bởi hướng dẫn sử dụng PHP. Một lần nữa, có thể được kế thừa từ PHP trước 5.4 nhưng hai hướng dẫn tôi đã đọc nói rằng
class->open
trả về hàng được đọc, trong khi trạng thái thủ công PHP rằng nó cần trả vềtrue
hoặcfalse
chỉ. -
Đây là nguyên nhân gây ra Vấn đề ban đầu của tôi :Tôi đang sử dụng tên phiên tùy chỉnh (thực ra id là tên phiên và id phiên giống nhau! ) theo bài đăng StackOverflow rất hay này và điều này đã tạo ra một tên phiên dài 128 ký tự. Vì tên phiên là khóa duy nhất cần được bẻ khóa để xâm phạm phiên và tiếp quản bằng chiếm quyền điều khiển phiên thì một tên / id dài hơn là một điều rất tốt.
- Tuy nhiên, điều này đã gây ra sự cố vì MySQL đã âm thầm cắt id phiên xuống chỉ còn 32 ký tự thay vì 128, vì vậy nó không bao giờ có thể tìm thấy dữ liệu phiên trong cơ sở dữ liệu. Đây là một vấn đề hoàn toàn im lặng (có thể do lớp kết nối cơ sở dữ liệu của tôi không đưa ra cảnh báo về những thứ như vậy). Nhưng đây là điều cần chú ý. Nếu bạn gặp bất kỳ vấn đề nào với việc truy xuất phiên từ cơ sở dữ liệu, trước tiên hãy kiểm tra xem đầy đủ id phiên có thể được lưu trữ trong trường được cung cấp.
Vì vậy, với tất cả những điều đó, cũng có một số chi tiết bổ sung cần thêm vào:
Trang hướng dẫn sử dụng PHP (được liên kết ở trên) hiển thị một đống dòng không phù hợp cho một đối tượng lớp:
Trong khi đó, nó hoạt động tốt nếu bạn đặt nó vào hàm tạo lớp:
class MySessionHandler implements SessionHandlerInterface {
private $database = null;
public function __construct(){
$this->database = new Database(whatever);
// Set 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")
);
register_shutdown_function('session_write_close');
session_start();
}
...
}
Cái này có nghĩa là để bắt đầu một phiên trên trang đầu ra của bạn, tất cả những gì bạn cần là:
<?php
require "path/to/sessionhandler.class.php";
new MySessionHandler();
//Bang session has been setup and started and works
Để tham khảo, lớp giao tiếp Session hoàn chỉnh như sau, lớp này hoạt động với PHP 5.6 (và có thể là 7 nhưng chưa được thử nghiệm trên 7)
<?php
/***
* Created by PhpStorm.
***/
class MySessionHandler implements SessionHandlerInterface {
private $database = null;
public function __construct($sessionDBconnectionUrl){
/***
* Just setting up my own database connection. Use yours as you need.
***/
require_once "class.database.include.php";
$this->database = new DatabaseObject($sessionDBconnectionUrl);
// Set 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")
);
register_shutdown_function('session_write_close');
session_start();
}
/**
* Open
*/
public function open($savepath, $id){
// If successful
$this->database->getSelect("SELECT `data` FROM sessions WHERE id = ? LIMIT 1",$id,TRUE);
if($this->database->selectRowsFoundCounter() == 1){
// Return True
return true;
}
// Return False
return false;
}
/**
* Read
*/
public function read($id)
{
// Set query
$readRow = $this->database->getSelect('SELECT `data` FROM sessions WHERE id = ? LIMIT 1', $id,TRUE);
if ($this->database->selectRowsFoundCounter() > 0) {
return $readRow['data'];
} else {
return '';
}
}
/**
* Write
*/
public function write($id, $data)
{
// Create time stamp
$access = time();
// Set query
$dataReplace[0] = $id;
$dataReplace[1] = $access;
$dataReplace[2] = $data;
if ($this->database->noReturnQuery('REPLACE INTO sessions(id,access,`data`) VALUES (?, ?, ?)', $dataReplace)) {
return true;
} else {
return false;
}
}
/**
* Destroy
*/
public function destroy($id)
{
// Set query
if ($this->database->noReturnQuery('DELETE FROM sessions WHERE id = ? LIMIT 1', $id)) {
return true;
} else {
return false;
}
}
/**
* Close
*/
public function close(){
// Close the database connection
if($this->database->dbiLink->close){
// Return True
return true;
}
// Return False
return false;
}
/**
* Garbage Collection
*/
public function gc($max)
{
// Calculate what is to be deemed old
$old = time() - $max;
if ($this->database->noReturnQuery('DELETE FROM sessions WHERE access < ?', $old)) {
return true;
} else {
return false;
}
}
public function __destruct()
{
$this->close();
}
}
Cách sử dụng:Như được hiển thị ngay trên văn bản mã lớp.