Completed
Push — master ( 8c6f59...89dfde )
by smiley
02:58
created

SessionHandlerAbstract::active()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 2
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 * Class SessionHandlerAbstract
4
 *
5
 * @filesource   SessionHandlerAbstract.php
6
 * @created      06.03.2017
7
 * @package      chillerlan\Session
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2017 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\Session;
14
15
use chillerlan\Logger\Output\NullLogger;
16
use chillerlan\Settings\SettingsContainerInterface;
17
use Psr\Log\{LoggerAwareInterface, LoggerAwareTrait, LoggerInterface};
18
19
abstract class SessionHandlerAbstract implements SessionInterface, LoggerAwareInterface{
20
	use LoggerAwareTrait;
21
22
	/**
23
	 * @var bool
24
	 */
25
	protected $started = false;
26
27
	/**
28
	 * @var \chillerlan\Session\SessionHandlerOptions
29
	 */
30
	protected $options;
31
32
	/**
33
	 * SessionHandlerAbstract constructor.
34
	 *
35
	 * @param \chillerlan\Settings\SettingsContainerInterface $options
36
	 * @param \Psr\Log\LoggerInterface|null                  $logger
37
	 */
38
	public function __construct(SettingsContainerInterface $options = null, LoggerInterface $logger = null){
39
		$this->options = $options ?? new SessionHandlerOptions;
40
		$this->logger  = $logger ?? new NullLogger;
0 ignored issues
show
Documentation Bug introduced by
It seems like $logger ?? new chillerla...ger\Output\NullLogger() can also be of type chillerlan\Logger\Output\NullLogger. However, the property $logger is declared as type Psr\Log\LoggerInterface. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
41
42
		$this->setOptions($options);
0 ignored issues
show
Bug introduced by
It seems like $options can also be of type null; however, parameter $options of chillerlan\Session\Sessi...rAbstract::setOptions() does only seem to accept chillerlan\Settings\SettingsContainerInterface, maybe add an additional type check? ( Ignorable by Annotation )

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

42
		$this->setOptions(/** @scrutinizer ignore-type */ $options);
Loading history...
43
44
		session_set_save_handler($this, true);
45
	}
46
47
	/** @inheritdoc */
48
	public function start():SessionInterface{
49
		$cookie_params = session_get_cookie_params();
50
51
		session_start();
52
		session_regenerate_id(true);
53
54
		setcookie(
55
			session_name(),
56
			session_id(),
57
			time()+$this->options->cookie_lifetime,
58
			$this->options->cookie_path,
59
			$cookie_params['domain']
60
		);
61
62
		return $this;
63
	}
64
65
	/** @inheritdoc */
66
	public function end():SessionInterface{
67
		session_regenerate_id(true);
68
		setcookie(session_name(), '', 0, $this->options->cookie_path);
69
		session_unset();
70
		session_destroy();
71
		session_write_close();
72
73
		return $this;
74
	}
75
76
	/** @inheritdoc */
77
	public function active():bool{
78
		return session_status() === PHP_SESSION_ACTIVE;
79
	}
80
81
	/** @inheritdoc */
82
	public function get(string $name){
83
		return $_SESSION[$name] ?? null;
84
	}
85
86
	/** @inheritdoc */
87
	public function set(string $name, $value):SessionInterface{
88
		$_SESSION[$name] = $value;
89
90
		return $this;
91
	}
92
93
	/** @inheritdoc */
94
	public function unset(string $name):SessionInterface{
95
		unset($_SESSION[$name]);
96
97
		return $this;
98
	}
99
100
	/** @inheritdoc */
101
	public function isset(string $name):bool{
102
		return isset($_SESSION[$name]);
103
	}
104
105
	/**
106
	 * @param string $data
107
	 *
108
	 * @return string
109
	 * @throws \chillerlan\Session\SessionHandlerException
110
	 */
111
	protected function encrypt(string &$data):string {
112
113
		if(function_exists('sodium_crypto_secretbox')){
114
			$box = sodium_crypto_secretbox($data, $this::SESSION_NONCE, sodium_hex2bin($this->options->sessionCryptoKey));
115
116
			sodium_memzero($data);
0 ignored issues
show
Bug introduced by
The call to sodium_memzero() has too few arguments starting with length. ( Ignorable by Annotation )

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

116
			/** @scrutinizer ignore-call */ 
117
   sodium_memzero($data);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
117
118
			return sodium_bin2hex($box);
119
		}
120
121
		throw new SessionHandlerException('sodium not installed'); // @codeCoverageIgnore
122
	}
123
124
	/**
125
	 * @param string $box
126
	 *
127
	 * @return string
128
	 * @throws \chillerlan\Session\SessionHandlerException
129
	 */
130
	protected function decrypt(string $box):string {
131
132
		if(function_exists('sodium_crypto_secretbox_open')){
133
			return sodium_crypto_secretbox_open(sodium_hex2bin($box), $this::SESSION_NONCE, sodium_hex2bin($this->options->sessionCryptoKey));
134
		}
135
136
		throw new SessionHandlerException('sodium not installed'); // @codeCoverageIgnore
137
	}
138
139
	/**
140
	 * @param \chillerlan\Settings\SettingsContainerInterface $options
141
	 *
142
	 * @return \chillerlan\Session\SessionInterface
143
	 */
144
	public function setOptions(SettingsContainerInterface $options):SessionInterface{
145
146
		// end an active session before setting new options
147
		if($this->active()){
148
			$this->end();
149
		}
150
151
		if(is_writable($options->save_path)){
152
			ini_set('session.save_path', $options->save_path);
153
		}
154
155
		// @todo http://php.net/manual/session.configuration.php
156
		ini_set('session.name', $options->session_name);
157
158
		ini_set('session.gc_maxlifetime', $options->gc_maxlifetime);
159
		ini_set('session.gc_probability', '1');
160
		ini_set('session.gc_divisor', '100');
161
162
		ini_set('session.use_strict_mode', 'true');
163
		ini_set('session.use_only_cookies', 'true');
164
		ini_set('session.cookie_secure', 'false'); // @todo
165
		ini_set('session.cookie_httponly', 'true');
166
		ini_set('session.cookie_lifetime', '0');
167
#		ini_set('session.referer_check', '');
168
169
		ini_set('session.sid_bits_per_character', '6');
170
		ini_set('session.sid_length', '128');
171
172
		return $this;
173
	}
174
175
}
176