Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Session\Middleware;
4
 
5
use Closure;
6
use Illuminate\Contracts\Session\Session;
7
use Illuminate\Http\Request;
8
use Illuminate\Routing\Route;
9
use Illuminate\Session\SessionManager;
10
use Illuminate\Support\Carbon;
11
use Illuminate\Support\Facades\Date;
12
use Symfony\Component\HttpFoundation\Cookie;
13
use Symfony\Component\HttpFoundation\Response;
14
 
15
class StartSession
16
{
17
    /**
18
     * The session manager.
19
     *
20
     * @var \Illuminate\Session\SessionManager
21
     */
22
    protected $manager;
23
 
24
    /**
25
     * The callback that can resolve an instance of the cache factory.
26
     *
27
     * @var callable|null
28
     */
29
    protected $cacheFactoryResolver;
30
 
31
    /**
32
     * Create a new session middleware.
33
     *
34
     * @param  \Illuminate\Session\SessionManager  $manager
35
     * @param  callable|null  $cacheFactoryResolver
36
     * @return void
37
     */
38
    public function __construct(SessionManager $manager, callable $cacheFactoryResolver = null)
39
    {
40
        $this->manager = $manager;
41
        $this->cacheFactoryResolver = $cacheFactoryResolver;
42
    }
43
 
44
    /**
45
     * Handle an incoming request.
46
     *
47
     * @param  \Illuminate\Http\Request  $request
48
     * @param  \Closure  $next
49
     * @return mixed
50
     */
51
    public function handle($request, Closure $next)
52
    {
53
        if (! $this->sessionConfigured()) {
54
            return $next($request);
55
        }
56
 
57
        $session = $this->getSession($request);
58
 
59
        if ($this->manager->shouldBlock() ||
60
            ($request->route() instanceof Route && $request->route()->locksFor())) {
61
            return $this->handleRequestWhileBlocking($request, $session, $next);
62
        }
63
 
64
        return $this->handleStatefulRequest($request, $session, $next);
65
    }
66
 
67
    /**
68
     * Handle the given request within session state.
69
     *
70
     * @param  \Illuminate\Http\Request  $request
71
     * @param  \Illuminate\Contracts\Session\Session  $session
72
     * @param  \Closure  $next
73
     * @return mixed
74
     */
75
    protected function handleRequestWhileBlocking(Request $request, $session, Closure $next)
76
    {
77
        if (! $request->route() instanceof Route) {
78
            return;
79
        }
80
 
81
        $lockFor = $request->route() && $request->route()->locksFor()
82
                        ? $request->route()->locksFor()
83
                        : 10;
84
 
85
        $lock = $this->cache($this->manager->blockDriver())
86
                    ->lock('session:'.$session->getId(), $lockFor)
87
                    ->betweenBlockedAttemptsSleepFor(50);
88
 
89
        try {
90
            $lock->block(
91
                ! is_null($request->route()->waitsFor())
92
                        ? $request->route()->waitsFor()
93
                        : 10
94
            );
95
 
96
            return $this->handleStatefulRequest($request, $session, $next);
97
        } finally {
98
            $lock?->release();
99
        }
100
    }
101
 
102
    /**
103
     * Handle the given request within session state.
104
     *
105
     * @param  \Illuminate\Http\Request  $request
106
     * @param  \Illuminate\Contracts\Session\Session  $session
107
     * @param  \Closure  $next
108
     * @return mixed
109
     */
110
    protected function handleStatefulRequest(Request $request, $session, Closure $next)
111
    {
112
        // If a session driver has been configured, we will need to start the session here
113
        // so that the data is ready for an application. Note that the Laravel sessions
114
        // do not make use of PHP "native" sessions in any way since they are crappy.
115
        $request->setLaravelSession(
116
            $this->startSession($request, $session)
117
        );
118
 
119
        $this->collectGarbage($session);
120
 
121
        $response = $next($request);
122
 
123
        $this->storeCurrentUrl($request, $session);
124
 
125
        $this->addCookieToResponse($response, $session);
126
 
127
        // Again, if the session has been configured we will need to close out the session
128
        // so that the attributes may be persisted to some storage medium. We will also
129
        // add the session identifier cookie to the application response headers now.
130
        $this->saveSession($request);
131
 
132
        return $response;
133
    }
134
 
135
    /**
136
     * Start the session for the given request.
137
     *
138
     * @param  \Illuminate\Http\Request  $request
139
     * @param  \Illuminate\Contracts\Session\Session  $session
140
     * @return \Illuminate\Contracts\Session\Session
141
     */
142
    protected function startSession(Request $request, $session)
143
    {
144
        return tap($session, function ($session) use ($request) {
145
            $session->setRequestOnHandler($request);
146
 
147
            $session->start();
148
        });
149
    }
150
 
151
    /**
152
     * Get the session implementation from the manager.
153
     *
154
     * @param  \Illuminate\Http\Request  $request
155
     * @return \Illuminate\Contracts\Session\Session
156
     */
157
    public function getSession(Request $request)
158
    {
159
        return tap($this->manager->driver(), function ($session) use ($request) {
160
            $session->setId($request->cookies->get($session->getName()));
161
        });
162
    }
163
 
164
    /**
165
     * Remove the garbage from the session if necessary.
166
     *
167
     * @param  \Illuminate\Contracts\Session\Session  $session
168
     * @return void
169
     */
170
    protected function collectGarbage(Session $session)
171
    {
172
        $config = $this->manager->getSessionConfig();
173
 
174
        // Here we will see if this request hits the garbage collection lottery by hitting
175
        // the odds needed to perform garbage collection on any given request. If we do
176
        // hit it, we'll call this handler to let it delete all the expired sessions.
177
        if ($this->configHitsLottery($config)) {
178
            $session->getHandler()->gc($this->getSessionLifetimeInSeconds());
179
        }
180
    }
181
 
182
    /**
183
     * Determine if the configuration odds hit the lottery.
184
     *
185
     * @param  array  $config
186
     * @return bool
187
     */
188
    protected function configHitsLottery(array $config)
189
    {
190
        return random_int(1, $config['lottery'][1]) <= $config['lottery'][0];
191
    }
192
 
193
    /**
194
     * Store the current URL for the request if necessary.
195
     *
196
     * @param  \Illuminate\Http\Request  $request
197
     * @param  \Illuminate\Contracts\Session\Session  $session
198
     * @return void
199
     */
200
    protected function storeCurrentUrl(Request $request, $session)
201
    {
202
        if ($request->isMethod('GET') &&
203
            $request->route() instanceof Route &&
204
            ! $request->ajax() &&
205
            ! $request->prefetch() &&
206
            ! $request->isPrecognitive()) {
207
            $session->setPreviousUrl($request->fullUrl());
208
        }
209
    }
210
 
211
    /**
212
     * Add the session cookie to the application response.
213
     *
214
     * @param  \Symfony\Component\HttpFoundation\Response  $response
215
     * @param  \Illuminate\Contracts\Session\Session  $session
216
     * @return void
217
     */
218
    protected function addCookieToResponse(Response $response, Session $session)
219
    {
220
        if ($this->sessionIsPersistent($config = $this->manager->getSessionConfig())) {
221
            $response->headers->setCookie(new Cookie(
222
                $session->getName(), $session->getId(), $this->getCookieExpirationDate(),
223
                $config['path'], $config['domain'], $config['secure'] ?? false,
224
                $config['http_only'] ?? true, false, $config['same_site'] ?? null
225
            ));
226
        }
227
    }
228
 
229
    /**
230
     * Save the session data to storage.
231
     *
232
     * @param  \Illuminate\Http\Request  $request
233
     * @return void
234
     */
235
    protected function saveSession($request)
236
    {
237
        if (! $request->isPrecognitive()) {
238
            $this->manager->driver()->save();
239
        }
240
    }
241
 
242
    /**
243
     * Get the session lifetime in seconds.
244
     *
245
     * @return int
246
     */
247
    protected function getSessionLifetimeInSeconds()
248
    {
249
        return ($this->manager->getSessionConfig()['lifetime'] ?? null) * 60;
250
    }
251
 
252
    /**
253
     * Get the cookie lifetime in seconds.
254
     *
255
     * @return \DateTimeInterface|int
256
     */
257
    protected function getCookieExpirationDate()
258
    {
259
        $config = $this->manager->getSessionConfig();
260
 
261
        return $config['expire_on_close'] ? 0 : Date::instance(
262
            Carbon::now()->addRealMinutes($config['lifetime'])
263
        );
264
    }
265
 
266
    /**
267
     * Determine if a session driver has been configured.
268
     *
269
     * @return bool
270
     */
271
    protected function sessionConfigured()
272
    {
273
        return ! is_null($this->manager->getSessionConfig()['driver'] ?? null);
274
    }
275
 
276
    /**
277
     * Determine if the configured session driver is persistent.
278
     *
279
     * @param  array|null  $config
280
     * @return bool
281
     */
282
    protected function sessionIsPersistent(array $config = null)
283
    {
284
        $config = $config ?: $this->manager->getSessionConfig();
285
 
286
        return ! is_null($config['driver'] ?? null);
287
    }
288
 
289
    /**
290
     * Resolve the given cache driver.
291
     *
292
     * @param  string  $driver
293
     * @return \Illuminate\Cache\Store
294
     */
295
    protected function cache($driver)
296
    {
297
        return call_user_func($this->cacheFactoryResolver)->driver($driver);
298
    }
299
}