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ự:
- Khởi động session và đọc dữ liệu từ handler
- Gán session vào
$requestđể controller có thể truy cập - Ghi lại URL hiện tại vào lịch sử
- Xử lý request
- Gắn cookie session vào response
- Lưu session xuống storage (thực hiện bằng
Coroutine::defer) - 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'
);