翻译进度
9
分块数量
0
参与人数

Session

这是一篇协同翻译的文章,你可以点击『我来翻译』按钮来参与翻译。


HTTP Session

Introduction

Since HTTP driven applications are stateless, sessions provide a way to store information about the user across multiple requests. That user information is typically placed in a persistent store / backend that can be accessed from subsequent requests.

Laravel ships with a variety of session backends that are accessed through an expressive, unified API. Support for popular backends such as Memcached, Redis, and databases is included.

Configuration

Your application's session configuration file is stored at config/session.php. Be sure to review the options available to you in this file. By default, Laravel is configured to use the database session driver.

The session driver configuration option defines where session data will be stored for each request. Laravel includes a variety of drivers:

  • file - sessions are stored in storage/framework/sessions.
  • cookie - sessions are stored in secure, encrypted cookies.
  • database - sessions are stored in a relational database.
  • memcached / redis - sessions are stored in one of these fast, cache based stores.
  • dynamodb - sessions are stored in AWS DynamoDB.
  • array - sessions are stored in a PHP array and will not be persisted.

[!NOTE]
The array driver is primarily used during testing and prevents the data stored in the session from being persisted.

Driver Prerequisites

Database

When using the database session driver, you will need to ensure that you have a database table to contain the session data. Typically, this is included in Laravel's default 0001_01_01_000000_create_users_table.php database migration; however, if for any reason you do not have a sessions table, you may use the make:session-table Artisan command to generate this migration:

php artisan make:session-table

php artisan migrate

Redis

Before using Redis sessions with Laravel, you will need to either install the PhpRedis PHP extension via PECL or install the predis/predis package (~1.0) via Composer. For more information on configuring Redis, consult Laravel's Redis documentation.

[!NOTE]
The SESSION_CONNECTION environment variable, or the connection option in the session.php configuration file, may be used to specify which Redis connection is used for session storage.

Interacting With the Session

Retrieving Data

There are two primary ways of working with session data in Laravel: the global session helper and via a Request instance. First, let's look at accessing the session via a Request instance, which can be type-hinted on a route closure or controller method. Remember, controller method dependencies are automatically injected via the Laravel service container:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\View\View;

class UserController extends Controller
{
    /**
     * Show the profile for the given user.
     */
    public function show(Request $request, string $id): View
    {
        $value = $request->session()->get('key');

        // ...

        $user = $this->users->find($id);

        return view('user.profile', ['user' => $user]);
    }
}

When you retrieve an item from the session, you may also pass a default value as the second argument to the get method. This default value will be returned if the specified key does not exist in the session. If you pass a closure as the default value to the get method and the requested key does not exist, the closure will be executed and its result returned:

$value = $request->session()->get('key', 'default');

$value = $request->session()->get('key', function () {
    return 'default';
});

The Global Session Helper

You may also use the global session PHP function to retrieve and store data in the session. When the session helper is called with a single, string argument, it will return the value of that session key. When the helper is called with an array of key / value pairs, those values will be stored in the session:

Route::get('/home', function () {
    // Retrieve a piece of data from the session...
    $value = session('key');

    // Specifying a default value...
    $value = session('key', 'default');

    // Store a piece of data in the session...
    session(['key' => 'value']);
});

[!NOTE]
There is little practical difference between using the session via an HTTP request instance versus using the global session helper. Both methods are testable via the assertSessionHas method which is available in all of your test cases.

Retrieving All Session Data

If you would like to retrieve all the data in the session, you may use the all method:

$data = $request->session()->all();

Retrieving a Portion of the Session Data

The only and except methods may be used to retrieve a subset of the session data:

$data = $request->session()->only(['username', 'email']);

$data = $request->session()->except(['username', 'email']);

Determining if an Item Exists in the Session

To determine if an item is present in the session, you may use the has method. The has method returns true if the item is present and is not null:

if ($request->session()->has('users')) {
    // ...
}

To determine if an item is present in the session, even if its value is null, you may use the exists method:

if ($request->session()->exists('users')) {
    // ...
}

To determine if an item is not present in the session, you may use the missing method. The missing method returns true if the item is not present:

if ($request->session()->missing('users')) {
    // ...
}

Storing Data

To store data in the session, you will typically use the request instance's put method or the global session helper:

// Via a request instance...
$request->session()->put('key', 'value');

// Via the global "session" helper...
session(['key' => 'value']);

Pushing to Array Session Values

The push method may be used to push a new value onto a session value that is an array. For example, if the user.teams key contains an array of team names, you may push a new value onto the array like so:

$request->session()->push('user.teams', 'developers');

Retrieving and Deleting an Item

The pull method will retrieve and delete an item from the session in a single statement:

$value = $request->session()->pull('key', 'default');

Incrementing and Decrementing Session Values

If your session data contains an integer you wish to increment or decrement, you may use the increment and decrement methods:

$request->session()->increment('count');

$request->session()->increment('count', $incrementBy = 2);

$request->session()->decrement('count');

$request->session()->decrement('count', $decrementBy = 2);

Flash Data

Sometimes you may wish to store items in the session for the next request. You may do so using the flash method. Data stored in the session using this method will be available immediately and during the subsequent HTTP request. After the subsequent HTTP request, the flashed data will be deleted. Flash data is primarily useful for short-lived status messages:

$request->session()->flash('status', 'Task was successful!');

If you need to persist your flash data for several requests, you may use the reflash method, which will keep all of the flash data for an additional request. If you only need to keep specific flash data, you may use the keep method:

$request->session()->reflash();

$request->session()->keep(['username', 'email']);

To persist your flash data only for the current request, you may use the now method:

$request->session()->now('status', 'Task was successful!');

Deleting Data

The forget method will remove a piece of data from the session. If you would like to remove all data from the session, you may use the flush method:

// Forget a single key...
$request->session()->forget('name');

// Forget multiple keys...
$request->session()->forget(['name', 'status']);

$request->session()->flush();

Regenerating the Session ID

Regenerating the session ID is often done in order to prevent malicious users from exploiting a session fixation attack on your application.

Laravel automatically regenerates the session ID during authentication if you are using one of the Laravel application starter kits or Laravel Fortify; however, if you need to manually regenerate the session ID, you may use the regenerate method:

$request->session()->regenerate();

If you need to regenerate the session ID and remove all data from the session in a single statement, you may use the invalidate method:

$request->session()->invalidate();

Session Blocking

[!WARNING]
To utilize session blocking, your application must be using a cache driver that supports atomic locks. Currently, those cache drivers include the memcached, dynamodb, redis, mongodb (included in the official mongodb/laravel-mongodb package), database, file, and array drivers. In addition, you may not use the cookie session driver.

By default, Laravel allows requests using the same session to execute concurrently. So, for example, if you use a JavaScript HTTP library to make two HTTP requests to your application, they will both execute at the same time. For many applications, this is not a problem; however, session data loss can occur in a small subset of applications that make concurrent requests to two different application endpoints which both write data to the session.

To mitigate this, Laravel provides functionality that allows you to limit concurrent requests for a given session. To get started, you may simply chain the block method onto your route definition. In this example, an incoming request to the /profile endpoint would acquire a session lock. While this lock is being held, any incoming requests to the /profile or /order endpoints which share the same session ID will wait for the first request to finish executing before continuing their execution:

Route::post('/profile', function () {
    // ...
})->block($lockSeconds = 10, $waitSeconds = 10);

Route::post('/order', function () {
    // ...
})->block($lockSeconds = 10, $waitSeconds = 10);

The block method accepts two optional arguments. The first argument accepted by the block method is the maximum number of seconds the session lock should be held for before it is released. Of course, if the request finishes executing before this time the lock will be released earlier.

The second argument accepted by the block method is the number of seconds a request should wait while attempting to obtain a session lock. An Illuminate\Contracts\Cache\LockTimeoutException will be thrown if the request is unable to obtain a session lock within the given number of seconds.

If neither of these arguments is passed, the lock will be obtained for a maximum of 10 seconds and requests will wait a maximum of 10 seconds while attempting to obtain a lock:

Route::post('/profile', function () {
    // ...
})->block();

Adding Custom Session Drivers

Implementing the Driver

If none of the existing session drivers fit your application's needs, Laravel makes it possible to write your own session handler. Your custom session driver should implement PHP's built-in SessionHandlerInterface. This interface contains just a few simple methods. A stubbed MongoDB implementation looks like the following:

<?php

namespace App\Extensions;

class MongoSessionHandler implements \SessionHandlerInterface
{
    public function open($savePath, $sessionName) {}
    public function close() {}
    public function read($sessionId) {}
    public function write($sessionId, $data) {}
    public function destroy($sessionId) {}
    public function gc($lifetime) {}
}

Since Laravel does not include a default directory to house your extensions. You are free to place them anywhere you like. In this example, we have created an Extensions directory to house the MongoSessionHandler.

Since the purpose of these methods is not readily understandable, here is an overview of the purpose of each method:

  • The open method would typically be used in file based session store systems. Since Laravel ships with a file session driver, you will rarely need to put anything in this method. You can simply leave this method empty.
  • The close method, like the open method, can also usually be disregarded. For most drivers, it is not needed.
  • The read method should return the string version of the session data associated with the given $sessionId. There is no need to do any serialization or other encoding when retrieving or storing session data in your driver, as Laravel will perform the serialization for you.
  • The write method should write the given $data string associated with the $sessionId to some persistent storage system, such as MongoDB or another storage system of your choice. Again, you should not perform any serialization - Laravel will have already handled that for you.
  • The destroy method should remove the data associated with the $sessionId from persistent storage.
  • The gc method should destroy all session data that is older than the given $lifetime, which is a UNIX timestamp. For self-expiring systems like Memcached and Redis, this method may be left empty.

Registering the Driver

Once your driver has been implemented, you are ready to register it with Laravel. To add additional drivers to Laravel's session backend, you may use the extend method provided by the Session facade. You should call the extend method from the boot method of a service provider. You may do this from the existing App\Providers\AppServiceProvider or create an entirely new provider:

<?php

namespace App\Providers;

use App\Extensions\MongoSessionHandler;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\ServiceProvider;

class SessionServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        // ...
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Session::extend('mongo', function (Application $app) {
            // Return an implementation of SessionHandlerInterface...
            return new MongoSessionHandler;
        });
    }
}

Once the session driver has been registered, you may specify the mongo driver as your application's session driver using the SESSION_DRIVER environment variable or within the application's config/session.php configuration file.

本文章首发在 LearnKu.com 网站上。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 1
发起讨论 只看当前版本


KeenSting
session put 失效问题 需要注意的点
6 个点赞 | 3 个回复 | 分享 | 课程版本 5.5