Passed
Push — master ( 999d23...fe5b90 )
by Paul
04:24
created

Session::getSessionId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules;
4
5
use GeminiLabs\SiteReviews\Database\SqlQueries;
6
use PasswordHash;
7
8
/**
9
 * @see WP Session Manager (1.2.0)
10
 */
11
class Session
12
{
13
	const SESSION_COOKIE = '_glsr_session';
14
15
	/**
16
	 * @var int
17
	 */
18
	protected $expiryTimestamp;
19
20
	/**
21
	 * @var int
22
	 */
23
	protected $expiryTimestampReset;
24
25
	/**
26
	 * @var array
27
	 */
28
	protected $sessionData;
29
30
	/**
31
	 * @var string
32
	 */
33
	protected $sessionId;
34
35
	public function __construct()
36
	{
37
		if( $cookieId = filter_input( INPUT_COOKIE, static::SESSION_COOKIE )) {
38
			$cookie = explode( '||', stripslashes( $cookieId ));
39
			$this->sessionId = preg_replace( '/[^A-Za-z0-9_]/', '', $cookie[0] );
40
			$this->expiryTimestamp = absint( $cookie[1] );
41
			$this->expiryTimestampReset = absint( $cookie[2] );
42
			if( time() > $this->expiryTimestampReset ) {
43
				$this->setCookieExpiration();
44
			}
45
		}
46
		else {
47
			$this->sessionId = $this->generateSessionId();
48
			$this->setCookieExpiration();
49
		}
50
		$this->getSessionData();
51
		$this->setCookie();
52
	}
53
54
	/**
55
	 * @return void
56
	 */
57 1
	public function clear()
58
	{
59 1
		$this->setCookieExpiration();
60 1
		$this->regenerateSessionId( 'and delete session!' );
61 1
	}
62
63
	/**
64
	 * @return int|false
65
	 */
66
	public function deleteAllSessions()
67
	{
68
		return glsr( SqlQueries::class )->deleteAllSessions( static::SESSION_COOKIE );
69
	}
70
71
	/**
72
	 * @param int $limit
73
	 * @return void
74
	 */
75
	public function deleteExpiredSessions( $limit = 1000 )
76
	{
77
		if( $expiredSessions = implode( "','", $this->getExpiredSessions( $limit ))) {
78
			glsr( SqlQueries::class )->deleteExpiredSessions( $expiredSessions );
79
		}
80
	}
81
82
	/**
83
	 * @param string $key
84
	 * @param string|array $fallback
85
	 * @param bool|string $unset
86
	 * @return string|array
87
	 */
88 1
	public function get( $key, $fallback = '', $unset = false )
89
	{
90 1
		$key = sanitize_key( $key );
91 1
		$value = isset( $this->sessionData[$key] )
92 1
			? maybe_unserialize( $this->sessionData[$key] )
93 1
			: $fallback;
94 1
		if( isset( $this->sessionData[$key] ) && $unset ) {
95 1
			unset( $this->sessionData[$key] );
96 1
			$this->updateSession();
97
		}
98 1
		return $value;
99
	}
100
101
	/**
102
	 * @param string $key
103
	 * @param mixed $value
104
	 * @return mixed
105
	 */
106 1
	public function set( $key, $value )
107
	{
108 1
		$key = sanitize_key( $key );
109 1
		$this->sessionData[$key] = maybe_serialize( $value );
110 1
		$this->updateSession();
111 1
		return $this->sessionData[$key];
112
	}
113
114
	/**
115
	 * @return void
116
	 */
117 1
	protected function createSession()
118
	{
119 1
		add_option( $this->getSessionId(), $this->sessionData, '', false );
120 1
		add_option( $this->getSessionId( 'expires' ), $this->expiryTimestamp, '', false );
121 1
	}
122
123
	/**
124
	 * @return void
125
	 */
126 1
	protected function deleteSession()
127
	{
128 1
		delete_option( $this->getSessionId() );
129 1
		delete_option( $this->getSessionId( 'expires' ));
130 1
	}
131
132
	/**
133
	 * @return string
134
	 */
135 1
	protected function generateSessionId()
136
	{
137 1
		return md5(( new PasswordHash( 8, false ))->get_random_bytes( 32 ));
138
	}
139
140
	/**
141
	 * @param int $limit
142
	 * @return array
143
	 */
144
	protected function getExpiredSessions( $limit )
145
	{
146
		$expiredSessions = [];
147
		$sessions = glsr( SqlQueries::class )->getExpiredSessions( static::SESSION_COOKIE, absint( $limit ));
148
		if( !empty( $sessions )) {
149
			$now = time();
150
			foreach( $sessions as $session ) {
151
				if( $now <= $session->expiration )continue;
152
				$expiredSessions[] = $session->name;
153
				$expiredSessions[] = str_replace( '_expires_', '_', $session->name );
154
			}
155
		}
156
		return $expiredSessions;
157
	}
158
159
	/**
160
	 * @param string $separator
161
	 * @return string
162
	 */
163 1
	protected function getSessionId( $separator = '' )
164
	{
165 1
		return implode( '_', array_filter( [static::SESSION_COOKIE, $separator, $this->sessionId] ));
166
	}
167
168
	/**
169
	 * @return array
170
	 */
171
	protected function getSessionData()
172
	{
173
		return $this->sessionData = (array)get_option( $this->getSessionId(), [] );
174
	}
175
176
	/**
177
	 * @param bool|string $deleteOld
178
	 * @return void
179
	 */
180 1
	protected function regenerateSessionId( $deleteOld = false )
181
	{
182 1
		if( $deleteOld ) {
183 1
			$this->deleteSession();
184
		}
185 1
		$this->sessionId = $this->generateSessionId();
186 1
		$this->setCookie();
187 1
	}
188
189
	/**
190
	 * @return void
191
	 */
192 1
	protected function setCookie()
193
	{
194 1
		if( headers_sent() )return;
195
		$cookie = $this->sessionId.'||'.$this->expiryTimestamp.'||'.$this->expiryTimestampReset;
196
		$cookiePath = preg_replace( '|https?://[^/]+|i', '', trailingslashit( (string)get_option( 'home' )));
197
		setcookie( static::SESSION_COOKIE, $cookie, $this->expiryTimestamp, $cookiePath );
198
	}
199
200
	/**
201
	 * @return void
202
	 */
203 1
	protected function setCookieExpiration()
204
	{
205 1
		$this->expiryTimestampReset = time() + (24 * 60); // 24 minutes
206 1
		$this->expiryTimestamp = time() + (30 * 60); // 30 minutes
207 1
	}
208
209
	/**
210
	 * @return void
211
	 */
212 1
	protected function updateSession()
213
	{
214 1
		if( false === get_option( $this->getSessionId() )) {
215 1
			return $this->createSession();
216
		}
217 1
		update_option( $this->getSessionId(), $this->sessionData, false );
218 1
	}
219
}
220