Completed
Push — master ( a8d4f8...8bb334 )
by Alexander
220:03 queued 217:16
created

Session::offsetExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\web;
9
10
use Yii;
11
use yii\base\Component;
12
use yii\base\InvalidArgumentException;
13
use yii\base\InvalidConfigException;
14
15
/**
16
 * Session provides session data management and the related configurations.
17
 *
18
 * Session is a Web application component that can be accessed via `Yii::$app->session`.
19
 *
20
 * To start the session, call [[open()]]; To complete and send out session data, call [[close()]];
21
 * To destroy the session, call [[destroy()]].
22
 *
23
 * Session can be used like an array to set and get session data. For example,
24
 *
25
 * ```php
26
 * $session = new Session;
27
 * $session->open();
28
 * $value1 = $session['name1'];  // get session variable 'name1'
29
 * $value2 = $session['name2'];  // get session variable 'name2'
30
 * foreach ($session as $name => $value) // traverse all session variables
31
 * $session['name3'] = $value3;  // set session variable 'name3'
32
 * ```
33
 *
34
 * Session can be extended to support customized session storage.
35
 * To do so, override [[useCustomStorage]] so that it returns true, and
36
 * override these methods with the actual logic about using custom storage:
37
 * [[openSession()]], [[closeSession()]], [[readSession()]], [[writeSession()]],
38
 * [[destroySession()]] and [[gcSession()]].
39
 *
40
 * Session also supports a special type of session data, called *flash messages*.
41
 * A flash message is available only in the current request and the next request.
42
 * After that, it will be deleted automatically. Flash messages are particularly
43
 * useful for displaying confirmation messages. To use flash messages, simply
44
 * call methods such as [[setFlash()]], [[getFlash()]].
45
 *
46
 * For more details and usage information on Session, see the [guide article on sessions](guide:runtime-sessions-cookies).
47
 *
48
 * @property array $allFlashes Flash messages (key => message or key => [message1, message2]). This property
49
 * is read-only.
50
 * @property string $cacheLimiter Current cache limiter. This property is read-only.
51
 * @property array $cookieParams The session cookie parameters. This property is read-only.
52
 * @property int $count The number of session variables. This property is read-only.
53
 * @property string $flash The key identifying the flash message. Note that flash messages and normal session
54
 * variables share the same name space. If you have a normal session variable using the same name, its value will
55
 * be overwritten by this method. This property is write-only.
56
 * @property float $gCProbability The probability (percentage) that the GC (garbage collection) process is
57
 * started on every session initialization, defaults to 1 meaning 1% chance.
58
 * @property bool $hasSessionId Whether the current request has sent the session ID.
59
 * @property string $id The current session ID.
60
 * @property bool $isActive Whether the session has started. This property is read-only.
61
 * @property SessionIterator $iterator An iterator for traversing the session variables. This property is
62
 * read-only.
63
 * @property string $name The current session name.
64
 * @property string $savePath The current session save path, defaults to '/tmp'.
65
 * @property int $timeout The number of seconds after which data will be seen as 'garbage' and cleaned up. The
66
 * default value is 1440 seconds (or the value of "session.gc_maxlifetime" set in php.ini).
67
 * @property bool|null $useCookies The value indicating whether cookies should be used to store session IDs.
68
 * @property bool $useCustomStorage Whether to use custom storage. This property is read-only.
69
 * @property bool $useTransparentSessionID Whether transparent sid support is enabled or not, defaults to
70
 * false.
71
 *
72
 * @author Qiang Xue <[email protected]>
73
 * @since 2.0
74
 */
75
class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Countable
76
{
77
    /**
78
     * @var string the name of the session variable that stores the flash message data.
79
     */
80
    public $flashParam = '__flash';
81
    /**
82
     * @var \SessionHandlerInterface|array an object implementing the SessionHandlerInterface or a configuration array. If set, will be used to provide persistency instead of build-in methods.
83
     */
84
    public $handler;
85
86
    /**
87
     * @var array parameter-value pairs to override default session cookie parameters that are used for session_set_cookie_params() function
88
     * Array may have the following possible keys: 'lifetime', 'path', 'domain', 'secure', 'httponly'
89
     * @see https://secure.php.net/manual/en/function.session-set-cookie-params.php
90
     */
91
    private $_cookieParams = ['httponly' => true];
92
    /**
93
     * @var $frozenSessionData array|null is used for saving session between recreations due to session parameters update.
0 ignored issues
show
Documentation Bug introduced by
The doc comment $frozenSessionData at position 0 could not be parsed: Unknown type name '$frozenSessionData' at position 0 in $frozenSessionData.
Loading history...
94
     */
95
    private $frozenSessionData;
96
97
98
    /**
99
     * Initializes the application component.
100
     * This method is required by IApplicationComponent and is invoked by application.
101
     */
102 102
    public function init()
103
    {
104 102
        parent::init();
105 102
        register_shutdown_function([$this, 'close']);
106 102
        if ($this->getIsActive()) {
107 3
            Yii::warning('Session is already started', __METHOD__);
108 3
            $this->updateFlashCounters();
109
        }
110 102
    }
111
112
    /**
113
     * Returns a value indicating whether to use custom session storage.
114
     * This method should be overridden to return true by child classes that implement custom session storage.
115
     * To implement custom session storage, override these methods: [[openSession()]], [[closeSession()]],
116
     * [[readSession()]], [[writeSession()]], [[destroySession()]] and [[gcSession()]].
117
     * @return bool whether to use custom storage.
118
     */
119 57
    public function getUseCustomStorage()
120
    {
121 57
        return false;
122
    }
123
124
    /**
125
     * Starts the session.
126
     */
127 61
    public function open()
128
    {
129 61
        if ($this->getIsActive()) {
130 61
            return;
131
        }
132
133 61
        $this->registerSessionHandler();
134
135 61
        $this->setCookieParamsInternal();
136
137 61
        YII_DEBUG ? session_start() : @session_start();
138
139 61
        if ($this->getIsActive()) {
140 61
            Yii::info('Session started', __METHOD__);
141 61
            $this->updateFlashCounters();
142
        } else {
143
            $error = error_get_last();
144
            $message = isset($error['message']) ? $error['message'] : 'Failed to start session.';
145
            Yii::error($message, __METHOD__);
146
        }
147 61
    }
148
149
    /**
150
     * Registers session handler.
151
     * @throws \yii\base\InvalidConfigException
152
     */
153 61
    protected function registerSessionHandler()
154
    {
155 61
        if ($this->handler !== null) {
156
            if (!is_object($this->handler)) {
157
                $this->handler = Yii::createObject($this->handler);
158
            }
159
            if (!$this->handler instanceof \SessionHandlerInterface) {
160
                throw new InvalidConfigException('"' . get_class($this) . '::handler" must implement the SessionHandlerInterface.');
161
            }
162
            YII_DEBUG ? session_set_save_handler($this->handler, false) : @session_set_save_handler($this->handler, false);
163 61
        } elseif ($this->getUseCustomStorage()) {
164 4
            if (YII_DEBUG) {
165 4
                session_set_save_handler(
166 4
                    [$this, 'openSession'],
167 4
                    [$this, 'closeSession'],
168 4
                    [$this, 'readSession'],
169 4
                    [$this, 'writeSession'],
170 4
                    [$this, 'destroySession'],
171 4
                    [$this, 'gcSession']
172
                );
173
            } else {
174
                @session_set_save_handler(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for session_set_save_handler(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

174
                /** @scrutinizer ignore-unhandled */ @session_set_save_handler(

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
175
                    [$this, 'openSession'],
176
                    [$this, 'closeSession'],
177
                    [$this, 'readSession'],
178
                    [$this, 'writeSession'],
179
                    [$this, 'destroySession'],
180
                    [$this, 'gcSession']
181
                );
182
            }
183
        }
184 61
    }
185
186
    /**
187
     * Ends the current session and store session data.
188
     */
189 78
    public function close()
190
    {
191 78
        if ($this->getIsActive()) {
192 57
            YII_DEBUG ? session_write_close() : @session_write_close();
0 ignored issues
show
Bug introduced by
Are you sure the usage of session_write_close() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
193
        }
194 78
    }
195
196
    /**
197
     * Frees all session variables and destroys all data registered to a session.
198
     *
199
     * This method has no effect when session is not [[getIsActive()|active]].
200
     * Make sure to call [[open()]] before calling it.
201
     * @see open()
202
     * @see isActive
203
     */
204 7
    public function destroy()
205
    {
206 7
        if ($this->getIsActive()) {
207 7
            $sessionId = session_id();
208 7
            $this->close();
209 7
            $this->setId($sessionId);
210 7
            $this->open();
211 7
            session_unset();
212 7
            session_destroy();
213 7
            $this->setId($sessionId);
214
        }
215 7
    }
216
217
    /**
218
     * @return bool whether the session has started
219
     */
220 102
    public function getIsActive()
221
    {
222 102
        return session_status() === PHP_SESSION_ACTIVE;
223
    }
224
225
    private $_hasSessionId;
226
227
    /**
228
     * Returns a value indicating whether the current request has sent the session ID.
229
     * The default implementation will check cookie and $_GET using the session name.
230
     * If you send session ID via other ways, you may need to override this method
231
     * or call [[setHasSessionId()]] to explicitly set whether the session ID is sent.
232
     * @return bool whether the current request has sent the session ID.
233
     */
234 28
    public function getHasSessionId()
235
    {
236 28
        if ($this->_hasSessionId === null) {
237 28
            $name = $this->getName();
238 28
            $request = Yii::$app->getRequest();
239 28
            if (!empty($_COOKIE[$name]) && ini_get('session.use_cookies')) {
240
                $this->_hasSessionId = true;
241 28
            } elseif (!ini_get('session.use_only_cookies') && ini_get('session.use_trans_sid')) {
242
                $this->_hasSessionId = $request->get($name) != '';
0 ignored issues
show
Bug introduced by
The method get() does not exist on yii\console\Request. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

242
                $this->_hasSessionId = $request->/** @scrutinizer ignore-call */ get($name) != '';
Loading history...
243
            } else {
244 28
                $this->_hasSessionId = false;
245
            }
246
        }
247
248 28
        return $this->_hasSessionId;
249
    }
250
251
    /**
252
     * Sets the value indicating whether the current request has sent the session ID.
253
     * This method is provided so that you can override the default way of determining
254
     * whether the session ID is sent.
255
     * @param bool $value whether the current request has sent the session ID.
256
     */
257
    public function setHasSessionId($value)
258
    {
259
        $this->_hasSessionId = $value;
260
    }
261
262
    /**
263
     * Gets the session ID.
264
     * This is a wrapper for [PHP session_id()](https://secure.php.net/manual/en/function.session-id.php).
265
     * @return string the current session ID
266
     */
267 1
    public function getId()
268
    {
269 1
        return session_id();
270
    }
271
272
    /**
273
     * Sets the session ID.
274
     * This is a wrapper for [PHP session_id()](https://secure.php.net/manual/en/function.session-id.php).
275
     * @param string $value the session ID for the current session
276
     */
277 7
    public function setId($value)
278
    {
279 7
        session_id($value);
280 7
    }
281
282
    /**
283
     * Updates the current session ID with a newly generated one.
284
     *
285
     * Please refer to <https://secure.php.net/session_regenerate_id> for more details.
286
     *
287
     * This method has no effect when session is not [[getIsActive()|active]].
288
     * Make sure to call [[open()]] before calling it.
289
     *
290
     * @param bool $deleteOldSession Whether to delete the old associated session file or not.
291
     * @see open()
292
     * @see isActive
293
     */
294
    public function regenerateID($deleteOldSession = false)
295
    {
296
        if ($this->getIsActive()) {
297
            // add @ to inhibit possible warning due to race condition
298
            // https://github.com/yiisoft/yii2/pull/1812
299
            if (YII_DEBUG && !headers_sent()) {
300
                session_regenerate_id($deleteOldSession);
301
            } else {
302
                @session_regenerate_id($deleteOldSession);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for session_regenerate_id(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

302
                /** @scrutinizer ignore-unhandled */ @session_regenerate_id($deleteOldSession);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
303
            }
304
        }
305
    }
306
307
    /**
308
     * Gets the name of the current session.
309
     * This is a wrapper for [PHP session_name()](https://secure.php.net/manual/en/function.session-name.php).
310
     * @return string the current session name
311
     */
312 29
    public function getName()
313
    {
314 29
        return session_name();
315
    }
316
317
    /**
318
     * Sets the name for the current session.
319
     * This is a wrapper for [PHP session_name()](https://secure.php.net/manual/en/function.session-name.php).
320
     * @param string $value the session name for the current session, must be an alphanumeric string.
321
     * It defaults to "PHPSESSID".
322
     */
323 1
    public function setName($value)
324
    {
325 1
        $this->freeze();
326 1
        session_name($value);
327 1
        $this->unfreeze();
328 1
    }
329
330
    /**
331
     * Gets the current session save path.
332
     * This is a wrapper for [PHP session_save_path()](https://secure.php.net/manual/en/function.session-save-path.php).
333
     * @return string the current session save path, defaults to '/tmp'.
334
     */
335
    public function getSavePath()
336
    {
337
        return session_save_path();
338
    }
339
340
    /**
341
     * Sets the current session save path.
342
     * This is a wrapper for [PHP session_save_path()](https://secure.php.net/manual/en/function.session-save-path.php).
343
     * @param string $value the current session save path. This can be either a directory name or a [path alias](guide:concept-aliases).
344
     * @throws InvalidArgumentException if the path is not a valid directory
345
     */
346
    public function setSavePath($value)
347
    {
348
        $path = Yii::getAlias($value);
349
        if (is_dir($path)) {
350
            session_save_path($path);
351
        } else {
352
            throw new InvalidArgumentException("Session save path is not a valid directory: $value");
353
        }
354
    }
355
356
    /**
357
     * @return array the session cookie parameters.
358
     * @see https://secure.php.net/manual/en/function.session-get-cookie-params.php
359
     */
360 61
    public function getCookieParams()
361
    {
362 61
        return array_merge(session_get_cookie_params(), array_change_key_case($this->_cookieParams));
363
    }
364
365
    /**
366
     * Sets the session cookie parameters.
367
     * The cookie parameters passed to this method will be merged with the result
368
     * of `session_get_cookie_params()`.
369
     * @param array $value cookie parameters, valid keys include: `lifetime`, `path`, `domain`, `secure` and `httponly`.
370
     * @throws InvalidArgumentException if the parameters are incomplete.
371
     * @see https://secure.php.net/manual/en/function.session-set-cookie-params.php
372
     */
373
    public function setCookieParams(array $value)
374
    {
375
        $this->_cookieParams = $value;
376
    }
377
378
    /**
379
     * Sets the session cookie parameters.
380
     * This method is called by [[open()]] when it is about to open the session.
381
     * @throws InvalidArgumentException if the parameters are incomplete.
382
     * @see https://secure.php.net/manual/en/function.session-set-cookie-params.php
383
     */
384 61
    private function setCookieParamsInternal()
385
    {
386 61
        $data = $this->getCookieParams();
387 61
        if (isset($data['lifetime'], $data['path'], $data['domain'], $data['secure'], $data['httponly'])) {
388 61
            session_set_cookie_params($data['lifetime'], $data['path'], $data['domain'], $data['secure'], $data['httponly']);
389
        } else {
390
            throw new InvalidArgumentException('Please make sure cookieParams contains these elements: lifetime, path, domain, secure and httponly.');
391
        }
392 61
    }
393
394
    /**
395
     * Returns the value indicating whether cookies should be used to store session IDs.
396
     * @return bool|null the value indicating whether cookies should be used to store session IDs.
397
     * @see setUseCookies()
398
     */
399 1
    public function getUseCookies()
400
    {
401 1
        if (ini_get('session.use_cookies') === '0') {
402 1
            return false;
403 1
        } elseif (ini_get('session.use_only_cookies') === '1') {
404 1
            return true;
405
        }
406
407
        return null;
408
    }
409
410
    /**
411
     * Sets the value indicating whether cookies should be used to store session IDs.
412
     *
413
     * Three states are possible:
414
     *
415
     * - true: cookies and only cookies will be used to store session IDs.
416
     * - false: cookies will not be used to store session IDs.
417
     * - null: if possible, cookies will be used to store session IDs; if not, other mechanisms will be used (e.g. GET parameter)
418
     *
419
     * @param bool|null $value the value indicating whether cookies should be used to store session IDs.
420
     */
421 4
    public function setUseCookies($value)
422
    {
423 4
        $this->freeze();
424 4
        if ($value === false) {
425 1
            ini_set('session.use_cookies', '0');
426 1
            ini_set('session.use_only_cookies', '0');
427 3
        } elseif ($value === true) {
0 ignored issues
show
introduced by
The condition $value === true is always true.
Loading history...
428 3
            ini_set('session.use_cookies', '1');
429 3
            ini_set('session.use_only_cookies', '1');
430
        } else {
431
            ini_set('session.use_cookies', '1');
432
            ini_set('session.use_only_cookies', '0');
433
        }
434 4
        $this->unfreeze();
435 4
    }
436
437
    /**
438
     * @return float the probability (percentage) that the GC (garbage collection) process is started on every session initialization, defaults to 1 meaning 1% chance.
439
     */
440 1
    public function getGCProbability()
441
    {
442 1
        return (float) (ini_get('session.gc_probability') / ini_get('session.gc_divisor') * 100);
443
    }
444
445
    /**
446
     * @param float $value the probability (percentage) that the GC (garbage collection) process is started on every session initialization.
447
     * @throws InvalidArgumentException if the value is not between 0 and 100.
448
     */
449 1
    public function setGCProbability($value)
450
    {
451 1
        $this->freeze();
452 1
        if ($value >= 0 && $value <= 100) {
453
            // percent * 21474837 / 2147483647 ≈ percent * 0.01
454 1
            ini_set('session.gc_probability', floor($value * 21474836.47));
455 1
            ini_set('session.gc_divisor', 2147483647);
456
        } else {
457
            throw new InvalidArgumentException('GCProbability must be a value between 0 and 100.');
458
        }
459 1
        $this->unfreeze();
460 1
    }
461
462
    /**
463
     * @return bool whether transparent sid support is enabled or not, defaults to false.
464
     */
465 1
    public function getUseTransparentSessionID()
466
    {
467 1
        return ini_get('session.use_trans_sid') == 1;
468
    }
469
470
    /**
471
     * @param bool $value whether transparent sid support is enabled or not.
472
     */
473 1
    public function setUseTransparentSessionID($value)
474
    {
475 1
        $this->freeze();
476 1
        ini_set('session.use_trans_sid', $value ? '1' : '0');
477 1
        $this->unfreeze();
478 1
    }
479
480
    /**
481
     * @return int the number of seconds after which data will be seen as 'garbage' and cleaned up.
482
     * The default value is 1440 seconds (or the value of "session.gc_maxlifetime" set in php.ini).
483
     */
484 25
    public function getTimeout()
485
    {
486 25
        return (int) ini_get('session.gc_maxlifetime');
487
    }
488
489
    /**
490
     * @param int $value the number of seconds after which data will be seen as 'garbage' and cleaned up
491
     */
492 4
    public function setTimeout($value)
493
    {
494 4
        $this->freeze();
495 4
        ini_set('session.gc_maxlifetime', $value);
496 4
        $this->unfreeze();
497 4
    }
498
499
    /**
500
     * Session open handler.
501
     * This method should be overridden if [[useCustomStorage]] returns true.
502
     * @internal Do not call this method directly.
503
     * @param string $savePath session save path
504
     * @param string $sessionName session name
505
     * @return bool whether session is opened successfully
506
     */
507 7
    public function openSession($savePath, $sessionName)
0 ignored issues
show
Unused Code introduced by
The parameter $sessionName is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

507
    public function openSession($savePath, /** @scrutinizer ignore-unused */ $sessionName)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $savePath is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

507
    public function openSession(/** @scrutinizer ignore-unused */ $savePath, $sessionName)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
508
    {
509 7
        return true;
510
    }
511
512
    /**
513
     * Session close handler.
514
     * This method should be overridden if [[useCustomStorage]] returns true.
515
     * @internal Do not call this method directly.
516
     * @return bool whether session is closed successfully
517
     */
518 6
    public function closeSession()
519
    {
520 6
        return true;
521
    }
522
523
    /**
524
     * Session read handler.
525
     * This method should be overridden if [[useCustomStorage]] returns true.
526
     * @internal Do not call this method directly.
527
     * @param string $id session ID
528
     * @return string the session data
529
     */
530
    public function readSession($id)
0 ignored issues
show
Unused Code introduced by
The parameter $id is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

530
    public function readSession(/** @scrutinizer ignore-unused */ $id)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
531
    {
532
        return '';
533
    }
534
535
    /**
536
     * Session write handler.
537
     * This method should be overridden if [[useCustomStorage]] returns true.
538
     * @internal Do not call this method directly.
539
     * @param string $id session ID
540
     * @param string $data session data
541
     * @return bool whether session write is successful
542
     */
543
    public function writeSession($id, $data)
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

543
    public function writeSession($id, /** @scrutinizer ignore-unused */ $data)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $id is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

543
    public function writeSession(/** @scrutinizer ignore-unused */ $id, $data)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
544
    {
545
        return true;
546
    }
547
548
    /**
549
     * Session destroy handler.
550
     * This method should be overridden if [[useCustomStorage]] returns true.
551
     * @internal Do not call this method directly.
552
     * @param string $id session ID
553
     * @return bool whether session is destroyed successfully
554
     */
555
    public function destroySession($id)
0 ignored issues
show
Unused Code introduced by
The parameter $id is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

555
    public function destroySession(/** @scrutinizer ignore-unused */ $id)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
556
    {
557
        return true;
558
    }
559
560
    /**
561
     * Session GC (garbage collection) handler.
562
     * This method should be overridden if [[useCustomStorage]] returns true.
563
     * @internal Do not call this method directly.
564
     * @param int $maxLifetime the number of seconds after which data will be seen as 'garbage' and cleaned up.
565
     * @return bool whether session is GCed successfully
566
     */
567 2
    public function gcSession($maxLifetime)
0 ignored issues
show
Unused Code introduced by
The parameter $maxLifetime is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

567
    public function gcSession(/** @scrutinizer ignore-unused */ $maxLifetime)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
568
    {
569 2
        return true;
570
    }
571
572
    /**
573
     * Returns an iterator for traversing the session variables.
574
     * This method is required by the interface [[\IteratorAggregate]].
575
     * @return SessionIterator an iterator for traversing the session variables.
576
     */
577
    public function getIterator()
578
    {
579
        $this->open();
580
        return new SessionIterator();
581
    }
582
583
    /**
584
     * Returns the number of items in the session.
585
     * @return int the number of session variables
586
     */
587
    public function getCount()
588
    {
589
        $this->open();
590
        return count($_SESSION);
591
    }
592
593
    /**
594
     * Returns the number of items in the session.
595
     * This method is required by [[\Countable]] interface.
596
     * @return int number of items in the session.
597
     */
598
    public function count()
599
    {
600
        return $this->getCount();
601
    }
602
603
    /**
604
     * Returns the session variable value with the session variable name.
605
     * If the session variable does not exist, the `$defaultValue` will be returned.
606
     * @param string $key the session variable name
607
     * @param mixed $defaultValue the default value to be returned when the session variable does not exist.
608
     * @return mixed the session variable value, or $defaultValue if the session variable does not exist.
609
     */
610 61
    public function get($key, $defaultValue = null)
611
    {
612 61
        $this->open();
613 61
        return isset($_SESSION[$key]) ? $_SESSION[$key] : $defaultValue;
614
    }
615
616
    /**
617
     * Adds a session variable.
618
     * If the specified name already exists, the old value will be overwritten.
619
     * @param string $key session variable name
620
     * @param mixed $value session variable value
621
     */
622 45
    public function set($key, $value)
623
    {
624 45
        $this->open();
625 45
        $_SESSION[$key] = $value;
626 45
    }
627
628
    /**
629
     * Removes a session variable.
630
     * @param string $key the name of the session variable to be removed
631
     * @return mixed the removed value, null if no such session variable.
632
     */
633 36
    public function remove($key)
634
    {
635 36
        $this->open();
636 36
        if (isset($_SESSION[$key])) {
637 32
            $value = $_SESSION[$key];
638 32
            unset($_SESSION[$key]);
639
640 32
            return $value;
641
        }
642
643 36
        return null;
644
    }
645
646
    /**
647
     * Removes all session variables.
648
     */
649 15
    public function removeAll()
650
    {
651 15
        $this->open();
652 15
        foreach (array_keys($_SESSION) as $key) {
653 15
            unset($_SESSION[$key]);
654
        }
655 15
    }
656
657
    /**
658
     * @param mixed $key session variable name
659
     * @return bool whether there is the named session variable
660
     */
661
    public function has($key)
662
    {
663
        $this->open();
664
        return isset($_SESSION[$key]);
665
    }
666
667
    /**
668
     * Updates the counters for flash messages and removes outdated flash messages.
669
     * This method should only be called once in [[init()]].
670
     */
671 61
    protected function updateFlashCounters()
672
    {
673 61
        $counters = $this->get($this->flashParam, []);
674 61
        if (is_array($counters)) {
675 61
            foreach ($counters as $key => $count) {
676
                if ($count > 0) {
677
                    unset($counters[$key], $_SESSION[$key]);
678
                } elseif ($count == 0) {
679
                    $counters[$key]++;
680
                }
681
            }
682 61
            $_SESSION[$this->flashParam] = $counters;
683
        } else {
684
            // fix the unexpected problem that flashParam doesn't return an array
685
            unset($_SESSION[$this->flashParam]);
686
        }
687 61
    }
688
689
    /**
690
     * Returns a flash message.
691
     * @param string $key the key identifying the flash message
692
     * @param mixed $defaultValue value to be returned if the flash message does not exist.
693
     * @param bool $delete whether to delete this flash message right after this method is called.
694
     * If false, the flash message will be automatically deleted in the next request.
695
     * @return mixed the flash message or an array of messages if addFlash was used
696
     * @see setFlash()
697
     * @see addFlash()
698
     * @see hasFlash()
699
     * @see getAllFlashes()
700
     * @see removeFlash()
701
     */
702
    public function getFlash($key, $defaultValue = null, $delete = false)
703
    {
704
        $counters = $this->get($this->flashParam, []);
705
        if (isset($counters[$key])) {
706
            $value = $this->get($key, $defaultValue);
707
            if ($delete) {
708
                $this->removeFlash($key);
709
            } elseif ($counters[$key] < 0) {
710
                // mark for deletion in the next request
711
                $counters[$key] = 1;
712
                $_SESSION[$this->flashParam] = $counters;
713
            }
714
715
            return $value;
716
        }
717
718
        return $defaultValue;
719
    }
720
721
    /**
722
     * Returns all flash messages.
723
     *
724
     * You may use this method to display all the flash messages in a view file:
725
     *
726
     * ```php
727
     * <?php
728
     * foreach (Yii::$app->session->getAllFlashes() as $key => $message) {
729
     *     echo '<div class="alert alert-' . $key . '">' . $message . '</div>';
730
     * } ?>
731
     * ```
732
     *
733
     * With the above code you can use the [bootstrap alert][] classes such as `success`, `info`, `danger`
734
     * as the flash message key to influence the color of the div.
735
     *
736
     * Note that if you use [[addFlash()]], `$message` will be an array, and you will have to adjust the above code.
737
     *
738
     * [bootstrap alert]: http://getbootstrap.com/components/#alerts
739
     *
740
     * @param bool $delete whether to delete the flash messages right after this method is called.
741
     * If false, the flash messages will be automatically deleted in the next request.
742
     * @return array flash messages (key => message or key => [message1, message2]).
743
     * @see setFlash()
744
     * @see addFlash()
745
     * @see getFlash()
746
     * @see hasFlash()
747
     * @see removeFlash()
748
     */
749
    public function getAllFlashes($delete = false)
750
    {
751
        $counters = $this->get($this->flashParam, []);
752
        $flashes = [];
753
        foreach (array_keys($counters) as $key) {
754
            if (array_key_exists($key, $_SESSION)) {
755
                $flashes[$key] = $_SESSION[$key];
756
                if ($delete) {
757
                    unset($counters[$key], $_SESSION[$key]);
758
                } elseif ($counters[$key] < 0) {
759
                    // mark for deletion in the next request
760
                    $counters[$key] = 1;
761
                }
762
            } else {
763
                unset($counters[$key]);
764
            }
765
        }
766
767
        $_SESSION[$this->flashParam] = $counters;
768
769
        return $flashes;
770
    }
771
772
    /**
773
     * Sets a flash message.
774
     * A flash message will be automatically deleted after it is accessed in a request and the deletion will happen
775
     * in the next request.
776
     * If there is already an existing flash message with the same key, it will be overwritten by the new one.
777
     * @param string $key the key identifying the flash message. Note that flash messages
778
     * and normal session variables share the same name space. If you have a normal
779
     * session variable using the same name, its value will be overwritten by this method.
780
     * @param mixed $value flash message
781
     * @param bool $removeAfterAccess whether the flash message should be automatically removed only if
782
     * it is accessed. If false, the flash message will be automatically removed after the next request,
783
     * regardless if it is accessed or not. If true (default value), the flash message will remain until after
784
     * it is accessed.
785
     * @see getFlash()
786
     * @see addFlash()
787
     * @see removeFlash()
788
     */
789
    public function setFlash($key, $value = true, $removeAfterAccess = true)
790
    {
791
        $counters = $this->get($this->flashParam, []);
792
        $counters[$key] = $removeAfterAccess ? -1 : 0;
793
        $_SESSION[$key] = $value;
794
        $_SESSION[$this->flashParam] = $counters;
795
    }
796
797
    /**
798
     * Adds a flash message.
799
     * If there are existing flash messages with the same key, the new one will be appended to the existing message array.
800
     * @param string $key the key identifying the flash message.
801
     * @param mixed $value flash message
802
     * @param bool $removeAfterAccess whether the flash message should be automatically removed only if
803
     * it is accessed. If false, the flash message will be automatically removed after the next request,
804
     * regardless if it is accessed or not. If true (default value), the flash message will remain until after
805
     * it is accessed.
806
     * @see getFlash()
807
     * @see setFlash()
808
     * @see removeFlash()
809
     */
810
    public function addFlash($key, $value = true, $removeAfterAccess = true)
811
    {
812
        $counters = $this->get($this->flashParam, []);
813
        $counters[$key] = $removeAfterAccess ? -1 : 0;
814
        $_SESSION[$this->flashParam] = $counters;
815
        if (empty($_SESSION[$key])) {
816
            $_SESSION[$key] = [$value];
817
        } elseif (is_array($_SESSION[$key])) {
818
            $_SESSION[$key][] = $value;
819
        } else {
820
            $_SESSION[$key] = [$_SESSION[$key], $value];
821
        }
822
    }
823
824
    /**
825
     * Removes a flash message.
826
     * @param string $key the key identifying the flash message. Note that flash messages
827
     * and normal session variables share the same name space.  If you have a normal
828
     * session variable using the same name, it will be removed by this method.
829
     * @return mixed the removed flash message. Null if the flash message does not exist.
830
     * @see getFlash()
831
     * @see setFlash()
832
     * @see addFlash()
833
     * @see removeAllFlashes()
834
     */
835
    public function removeFlash($key)
836
    {
837
        $counters = $this->get($this->flashParam, []);
838
        $value = isset($_SESSION[$key], $counters[$key]) ? $_SESSION[$key] : null;
839
        unset($counters[$key], $_SESSION[$key]);
840
        $_SESSION[$this->flashParam] = $counters;
841
842
        return $value;
843
    }
844
845
    /**
846
     * Removes all flash messages.
847
     * Note that flash messages and normal session variables share the same name space.
848
     * If you have a normal session variable using the same name, it will be removed
849
     * by this method.
850
     * @see getFlash()
851
     * @see setFlash()
852
     * @see addFlash()
853
     * @see removeFlash()
854
     */
855
    public function removeAllFlashes()
856
    {
857
        $counters = $this->get($this->flashParam, []);
858
        foreach (array_keys($counters) as $key) {
859
            unset($_SESSION[$key]);
860
        }
861
        unset($_SESSION[$this->flashParam]);
862
    }
863
864
    /**
865
     * Returns a value indicating whether there are flash messages associated with the specified key.
866
     * @param string $key key identifying the flash message type
867
     * @return bool whether any flash messages exist under specified key
868
     */
869
    public function hasFlash($key)
870
    {
871
        return $this->getFlash($key) !== null;
872
    }
873
874
    /**
875
     * This method is required by the interface [[\ArrayAccess]].
876
     * @param mixed $offset the offset to check on
877
     * @return bool
878
     */
879 3
    public function offsetExists($offset)
880
    {
881 3
        $this->open();
882
883 3
        return isset($_SESSION[$offset]);
884
    }
885
886
    /**
887
     * This method is required by the interface [[\ArrayAccess]].
888
     * @param int $offset the offset to retrieve element.
889
     * @return mixed the element at the offset, null if no element is found at the offset
890
     */
891 3
    public function offsetGet($offset)
892
    {
893 3
        $this->open();
894
895 3
        return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
896
    }
897
898
    /**
899
     * This method is required by the interface [[\ArrayAccess]].
900
     * @param int $offset the offset to set element
901
     * @param mixed $item the element value
902
     */
903
    public function offsetSet($offset, $item)
904
    {
905
        $this->open();
906
        $_SESSION[$offset] = $item;
907
    }
908
909
    /**
910
     * This method is required by the interface [[\ArrayAccess]].
911
     * @param mixed $offset the offset to unset element
912
     */
913
    public function offsetUnset($offset)
914
    {
915
        $this->open();
916
        unset($_SESSION[$offset]);
917
    }
918
919
    /**
920
     * If session is started it's not possible to edit session ini settings. In PHP7.2+ it throws exception.
921
     * This function saves session data to temporary variable and stop session.
922
     * @since 2.0.14
923
     */
924 9
    protected function freeze()
925
    {
926 9
        if ($this->getIsActive()) {
927 2
            if (isset($_SESSION)) {
928 2
                $this->frozenSessionData = $_SESSION;
929
            }
930 2
            $this->close();
931 2
            Yii::info('Session frozen', __METHOD__);
932
        }
933 9
    }
934
935
    /**
936
     * Starts session and restores data from temporary variable
937
     * @since 2.0.14
938
     */
939 9
    protected function unfreeze()
940
    {
941 9
        if (null !== $this->frozenSessionData) {
942
943 2
            YII_DEBUG ? session_start() : @session_start();
944
945 2
            if ($this->getIsActive()) {
946 2
                Yii::info('Session unfrozen', __METHOD__);
947
            } else {
948
                $error = error_get_last();
949
                $message = isset($error['message']) ? $error['message'] : 'Failed to unfreeze session.';
950
                Yii::error($message, __METHOD__);
951
            }
952
953 2
            $_SESSION = $this->frozenSessionData;
954 2
            $this->frozenSessionData = null;
955
        }
956 9
    }
957
958
    /**
959
     * Set cache limiter
960
     *
961
     * @param string $cacheLimiter
962
     * @since 2.0.14
963
     */
964 1
    public function setCacheLimiter($cacheLimiter)
965
    {
966 1
        $this->freeze();
967 1
        session_cache_limiter($cacheLimiter);
968 1
        $this->unfreeze();
969 1
    }
970
971
    /**
972
     * Returns current cache limiter
973
     *
974
     * @return string current cache limiter
975
     * @since 2.0.14
976
     */
977
    public function getCacheLimiter()
978
    {
979
        return session_cache_limiter();
980
    }
981
}
982