Nhảy tới nội dung

Session

Session cho phép lưu trữ dữ liệu người dùng giữa các request HTTP. Framework hỗ trợ nhiều driver lưu trữ khác nhau và tích hợp sẵn các tính năng như flash message, CSRF token, và lịch sử URL.

Cấu hình

File cấu hình session nằm tại config/session.php:

return [
// Driver: 'file', 'database', 'null'
'driver' => env('SESSION_DRIVER', 'file'),

// Thời gian sống của session (phút)
'lifetime' => env('SESSION_LIFETIME', 120),

// Xóa session khi đóng trình duyệt
'expire_on_close' => false,

// Thư mục lưu session (driver: file)
'files' => storage_path('framework/sessions'),

// Tên bảng (driver: database)
'table' => 'sessions',

// Kết nối database (null = dùng mặc định)
'connection' => null,

// Định dạng serialize: 'php' hoặc 'json'
'serialization' => 'php',

// Tên cookie session
'cookie' => env('SESSION_COOKIE', 'tourdb_session'),

// Xác suất chạy garbage collection [probability, total]
'lottery' => [2, 100],

// Cấu hình cookie
'path' => '/',
'domain' => env('SESSION_DOMAIN', null),
'secure' => env('SESSION_SECURE_COOKIE', false),
'http_only' => true,
'same_site' => 'lax',
'partitioned' => false,

// Session blocking (tránh race condition)
'block' => false,
'block_store' => null,
'block_lock_seconds' => 10,
'block_wait_seconds' => 10,
];

Drivers

File Driver

Lưu session dưới dạng file trong thư mục cấu hình:

'driver' => 'file',
'files' => storage_path('framework/sessions'),

Database Driver

Lưu session trong bảng database. Cần tạo bảng trước:

CREATE TABLE sessions (
id VARCHAR(255) NOT NULL PRIMARY KEY,
payload TEXT NOT NULL,
last_activity INT NOT NULL,
ip_address VARCHAR(45),
user_agent VARCHAR(500)
);
'driver' => 'database',
'table' => 'sessions',

Null Driver

Dùng khi không cần session (mọi thao tác đều bị bỏ qua):

'driver' => 'null',

Sử dụng

Qua Facade

use Vietiso\Core\Session\Facade\Session;

// Lưu dữ liệu
Session::put('user_id', 123);

// Lấy dữ liệu
$userId = Session::get('user_id');

// Lấy dữ liệu với giá trị mặc định
$name = Session::get('name', 'Guest');

Qua Request

use Vietiso\Core\Http\Request;

public function show(Request $request): Response
{
$session = $request->session();

$session->put('key', 'value');
$value = $session->get('key');
}

Đọc và Ghi Dữ Liệu

// Lưu một giá trị
Session::put('key', 'value');

// Lưu nhiều giá trị cùng lúc (dot notation)
Session::put('user.name', 'John');
Session::put('user.email', 'john@example.com');

// Kiểm tra tồn tại (trả về false nếu null)
if (Session::has('user_id')) {
// ...
}

// Kiểm tra tồn tại bất kỳ key nào
if (Session::hasAny(['user_id', 'token'])) {
// ...
}

// Lấy và xóa ngay (pull)
$token = Session::pull('one_time_token');

// Xóa một key
Session::forget('key');

// Xóa toàn bộ session
Session::flush();

Push và Increment

// Thêm phần tử vào array trong session
Session::push('cart.items', ['id' => 1, 'qty' => 2]);
Session::push('cart.items', ['id' => 2, 'qty' => 1]);

// Tăng giá trị số
Session::increment('page_views');
Session::increment('page_views', 5); // tăng 5

// Giảm giá trị số
Session::decrement('credits');
Session::decrement('credits', 10); // giảm 10

Flash Message

Flash data chỉ tồn tại cho request tiếp theo, rất hữu ích để hiển thị thông báo sau redirect.

// Lưu flash message
Session::flash('success', 'Đặt tour thành công!');
Session::flash('error', 'Có lỗi xảy ra, vui lòng thử lại.');

// Đọc flash message (ở request tiếp theo)
$message = Session::get('success');

Flash Input (Old Input)

Dùng để giữ lại giá trị form sau khi redirect về trang lỗi:

// Lưu toàn bộ input vào flash
Session::flashInput($request->all());

// Kiểm tra có old input không
if (Session::hasOldInput('email')) {
$email = Session::getOldInput('email');
}

// Lấy old input với giá trị mặc định
$email = Session::getOldInput('email', '');

Lỗi Validation

Session tích hợp sẵn cơ chế truyền lỗi giữa các request:

// Lưu lỗi (thường dùng sau validation thất bại)
Session::setErrors([
'email' => 'Email không hợp lệ.',
'name' => 'Họ tên không được để trống.',
]);

// Đọc lỗi (ở request tiếp theo)
$errors = Session::getErrors();
// ['email' => 'Email không hợp lệ.', ...]

CSRF Token

Token được tạo tự động khi session khởi động và có thể tái tạo thủ công:

// Lấy CSRF token hiện tại
$token = Session::get('_token');

// Tái tạo token mới
$newToken = Session::regenerateToken();

Lịch Sử URL

Session tự động theo dõi lịch sử URL (tối đa 10 URL gần nhất):

// Lấy URL trước đó (mặc định: 1 bước trước)
$previousUrl = Session::getPreviousUrl();

// Lấy URL 2 bước trước
$twoBack = Session::getPreviousUrl(2);

Session ID

// Lấy session ID hiện tại (chuỗi 40 ký tự alphanumeric)
$id = Session::getId();
// hoặc
$id = Session::id();

// Đặt session ID thủ công (phải hợp lệ: 40 ký tự alphanumeric)
Session::setId('abc123...');

// Kiểm tra ID có hợp lệ không
$valid = Session::isValidId('abc123...'); // bool

Middleware StartSession

StartSession middleware tự động khởi động và lưu session cho mỗi request. Đăng ký trong vietiso:

use Vietiso\Core\Session\Middleware\StartSession;

App::getInstance()
->withMiddleware(static function (MiddlewareCollection $middlewares): void {
$middlewares->use([
StartSession::class,
// ...
]);
})
->start();

Middleware thực hiện các bước sau theo thứ tự:

  1. Khởi động session và đọc dữ liệu từ handler
  2. Gán session vào $request để controller có thể truy cập
  3. Ghi lại URL hiện tại vào lịch sử
  4. Xử lý request
  5. Gắn cookie session vào response
  6. Lưu session xuống storage (thực hiện bằng Coroutine::defer)
  7. Chạy garbage collection theo xác suất (lottery) khi middleware bị hủy

Lifecycle của Session

Request đến


StartSession::handle()

├─ manager->driver() → tạo Session instance
├─ session->start() → đọc data từ handler, xử lý flash/errors/token
├─ Coroutine::defer(session->save()) → đặt lịch lưu sau response
├─ request->setSession(session)
├─ session->setCurrentUrl(...)


Controller xử lý


Response trả về với Set-Cookie header


Coroutine chạy session->save() → ghi data xuống handler

Tùy Chỉnh Handler

Có thể tạo session handler riêng bằng cách implement SessionHandlerInterface:

use SessionHandlerInterface;

class RedisSessionHandler implements SessionHandlerInterface
{
public function open(string $path, string $name): bool { return true; }
public function close(): bool { return true; }

public function read(string $sessionId): string|false
{
return Redis::get("session:$sessionId") ?: '';
}

public function write(string $sessionId, string $data): bool
{
return (bool) Redis::setex("session:$sessionId", 3600, $data);
}

public function destroy(string $sessionId): bool
{
Redis::del("session:$sessionId");
return true;
}

public function gc(int $lifetime): int
{
return 0; // Redis tự xử lý TTL
}
}

Đăng ký driver trong SessionManager hoặc tạo session thủ công:

$session = new Session(
name: config('session.cookie'),
handler: new RedisSessionHandler(),
id: $request->cookie->get(config('session.cookie')),
serialization: 'json'
);