Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Completed
Push — master ( 64adfe...7d96ad )
by Dan
34s queued 16s
created

SmrSession::hasChangedSN()   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
c 0
b 0
f 0
dl 0
loc 2
rs 10
cc 1
nc 1
nop 0
1
<?php declare(strict_types=1);
2
3
if (!defined('USING_AJAX')) {
4
	define('USING_AJAX', false);
5
}
6
7
class SmrSession {
8
9
	const TIME_BEFORE_EXPIRY = 3600;
10
11
	private const URL_LOAD_DELAY = array(
12
		'configure_hardware.php' => .4,
13
		'forces_drop.php' => .4,
14
		'forces_drop_processing.php' => .5,
15
		'forces_refresh_processing.php' => .4,
16
		'sector_jump_processing.php' => .4,
17
		'sector_move_processing.php' => .4,
18
		'sector_scan.php' => .4,
19
		'shop_goods_processing.php' => .4,
20
		'trader_attack_processing.php' => .75,
21
		'trader_examine.php' => .75
22
	);
23
24
	protected static MySqlDatabase $db;
25
26
	private static ?string $session_id;
27
	private static int $game_id;
28
	private static array $var;
29
	private static array $commonIDs = [];
30
	private static bool $generate;
31
	private static string $SN = '';
32
	private static string $lastSN;
33
	private static int $account_id;
34
	public static int $last_accessed;
35
36
	protected static ?array $previousAjaxReturns;
37
	protected static array $ajaxReturns = array();
38
39
	public static function init() : void {
40
		// Return immediately if the SmrSession is already initialized
41
		if (isset(self::$session_id)) {
42
			return;
43
		}
44
45
		// Initialize the db connector here, since `init` is always called
46
		self::$db = MySqlDatabase::getInstance();
47
48
		// now try the cookie
49
		if (isset($_COOKIE['session_id']) && strlen($_COOKIE['session_id']) === 32) {
50
			self::$session_id = $_COOKIE['session_id'];
51
		} else {
52
			// create a new session id
53
			do {
54
				self::$session_id = md5(uniqid(strval(rand())));
55
				self::$db->query('SELECT 1 FROM active_session WHERE session_id = ' . self::$db->escapeString(self::$session_id) . ' LIMIT 1');
56
			} while (self::$db->nextRecord()); //Make sure we haven't somehow clashed with someone else's session.
57
58
			// This is a minor hack to make sure that setcookie is not called
59
			// for CLI programs and tests (to avoid "headers already sent").
60
			if (headers_sent() === false) {
61
				setcookie('session_id', self::$session_id);
62
			}
63
		}
64
65
		// try to get current session
66
		self::$db->query('DELETE FROM active_session WHERE last_accessed < ' . self::$db->escapeNumber(time() - self::TIME_BEFORE_EXPIRY));
67
		self::fetchVarInfo();
68
69
		$sn = Request::get('sn', '');
70
		if (!USING_AJAX && !empty($sn) && !empty(self::$var[$sn])) {
71
			$var = self::$var[$sn];
72
			$currentPage = $var['url'] == 'skeleton.php' ? $var['body'] : $var['url'];
73
			$loadDelay = self::URL_LOAD_DELAY[$currentPage] ?? 0;
74
			$initialTimeBetweenLoads = microtime(true) - $var['PreviousRequestTime'];
75
			while (($timeBetweenLoads = microtime(true) - $var['PreviousRequestTime']) < $loadDelay) {
76
				$sleepTime = IRound(($loadDelay - $timeBetweenLoads) * 1000000);
77
			//	echo 'Sleeping for: ' . $sleepTime . 'us';
78
				usleep($sleepTime);
79
			}
80
			if (ENABLE_DEBUG) {
81
				self::$db->query('INSERT INTO debug VALUES (' . self::$db->escapeString('Delay: ' . $currentPage) . ',' . self::$db->escapeNumber(self::$account_id) . ',' . self::$db->escapeNumber($initialTimeBetweenLoads) . ',' . self::$db->escapeNumber($timeBetweenLoads) . ')');
82
			}
83
		}
84
	}
85
86
	public static function fetchVarInfo() : void {
87
		self::$db->query('SELECT * FROM active_session WHERE session_id = ' . self::$db->escapeString(self::$session_id) . ' LIMIT 1');
88
		if (self::$db->nextRecord()) {
89
			self::$generate = false;
90
			self::$session_id = self::$db->getField('session_id');
91
			self::$account_id = self::$db->getInt('account_id');
92
			self::$game_id = self::$db->getInt('game_id');
93
			self::$last_accessed = self::$db->getInt('last_accessed');
94
			self::$lastSN = self::$db->getField('last_sn');
95
			// We may not have ajax_returns if ajax was disabled
96
			self::$previousAjaxReturns = self::$db->getObject('ajax_returns', true, true);
97
98
			self::$var = self::$db->getObject('session_var', true);
99
100
			foreach (self::$var as $key => $value) {
101
				if ($value['Expires'] > 0 && $value['Expires'] <= Smr\Epoch::time()) { // Use 0 for infinity
102
					//This link is no longer valid
103
					unset(self::$var[$key]);
104
				} elseif ($value['RemainingPageLoads'] < 0) {
105
					//This link is no longer valid
106
					unset(self::$var[$key]);
107
				} else {
108
					--self::$var[$key]['RemainingPageLoads'];
109
					if (isset($value['CommonID'])) {
110
						self::$commonIDs[$value['CommonID']] = $key;
111
					}
112
				}
113
			}
114
		} else {
115
			self::$generate = true;
116
			self::$account_id = 0;
117
			self::$game_id = 0;
118
			self::$var = array();
119
		}
120
	}
121
122
	public static function update() : void {
123
		foreach (self::$var as $key => $value) {
124
			if ($value['RemainingPageLoads'] <= 0) {
125
				//This link was valid this load but will not be in the future, removing it now saves database space and data transfer.
126
				unset(self::$var[$key]);
127
			}
128
		}
129
		if (!self::$generate) {
130
			self::$db->query('UPDATE active_session SET account_id=' . self::$db->escapeNumber(self::$account_id) . ',game_id=' . self::$db->escapeNumber(self::$game_id) . (!USING_AJAX ? ',last_accessed=' . self::$db->escapeNumber(Smr\Epoch::time()) : '') . ',session_var=' . self::$db->escapeObject(self::$var, true) .
131
					',last_sn=' . self::$db->escapeString(self::$SN) .
132
					' WHERE session_id=' . self::$db->escapeString(self::$session_id) . (USING_AJAX ? ' AND last_sn=' . self::$db->escapeString(self::$lastSN) : '') . ' LIMIT 1');
133
		} else {
134
			self::$db->query('DELETE FROM active_session WHERE account_id = ' . self::$db->escapeNumber(self::$account_id) . ' AND game_id = ' . self::$db->escapeNumber(self::$game_id));
135
			self::$db->query('INSERT INTO active_session (session_id, account_id, game_id, last_accessed, session_var) VALUES(' . self::$db->escapeString(self::$session_id) . ',' . self::$db->escapeNumber(self::$account_id) . ',' . self::$db->escapeNumber(self::$game_id) . ',' . self::$db->escapeNumber(Smr\Epoch::time()) . ',' . self::$db->escapeObject(self::$var, true) . ')');
136
			self::$generate = false;
137
		}
138
	}
139
140
	/**
141
	 * Returns the Game ID associated with the session.
142
	 */
143
	public static function getGameID() : int {
144
		return self::$game_id;
145
	}
146
147
	/**
148
	 * Returns true if the session is inside a game, false otherwise.
149
	 */
150
	public static function hasGame() : bool {
151
		return self::$game_id != 0;
152
	}
153
154
	public static function hasAccount() : bool {
155
		return self::$account_id > 0;
156
	}
157
158
	public static function getAccountID() : int {
159
		return self::$account_id;
160
	}
161
162
	public static function getAccount() : SmrAccount {
163
		return SmrAccount::getAccount(self::$account_id);
164
	}
165
166
	/**
167
	 * Sets the `account_id` attribute of this session.
168
	 */
169
	public static function setAccount(AbstractSmrAccount $account) : void {
170
		self::$account_id = $account->getAccountID();
171
	}
172
173
	/**
174
	 * Updates the `game_id` attribute of the session and deletes any other
175
	 * active sessions in this game for this account.
176
	 */
177
	public static function updateGame(int $gameID) : void {
178
		if (self::$game_id == $gameID) {
179
			return;
180
		}
181
		self::$game_id = $gameID;
182
		self::$db->query('DELETE FROM active_session WHERE account_id = ' . self::$db->escapeNumber(self::$account_id) . ' AND game_id = ' . self::$game_id);
183
		self::$db->query('UPDATE active_session SET game_id=' . self::$db->escapeNumber(self::$game_id) . ' WHERE session_id=' . self::$db->escapeString(self::$session_id));
184
	}
185
186
	/**
187
	 * Returns true if the current SN is different than the previous SN.
188
	 */
189
	public static function hasChangedSN() : bool {
190
		return self::$SN != self::$lastSN;
191
	}
192
193
	private static function updateSN() : void {
194
		if (!USING_AJAX) {
195
			self::$db->query('UPDATE active_session SET last_sn=' . self::$db->escapeString(self::$SN) .
196
				' WHERE session_id=' . self::$db->escapeString(self::$session_id) . ' LIMIT 1');
197
		}
198
	}
199
200
	public static function destroy() : void {
201
		self::$db->query('DELETE FROM active_session WHERE session_id = ' . self::$db->escapeString(self::$session_id));
202
		self::$session_id = null;
203
		self::$account_id = 0;
204
		self::$game_id = 0;
205
	}
206
207
	/**
208
	 * Retrieve the session var for the page given by $sn.
209
	 * If $sn is not specified, use the current page (i.e. self::$SN).
210
	 */
211
	public static function retrieveVar(string $sn = null) : Page|false {
212
		if (is_null($sn)) {
213
			$sn = self::$SN;
214
		}
215
		if (empty(self::$var[$sn])) {
216
			return false;
217
		}
218
		self::$SN = $sn;
219
		SmrSession::updateSN();
220
		if (isset(self::$var[$sn]['body']) && isset(self::$var[$sn]['CommonID'])) {
221
//			if(preg_match('/processing/',self::$var[$sn]['body']))
222
			unset(self::$commonIDs[self::$var[$sn]['CommonID']]); //Do not store common id for current page
223
			unset(self::$var[$sn]['CommonID']);
224
		}
225
226
		self::$var[$sn]['RemainingPageLoads'] += 1; // Allow refreshing
227
		self::$var[$sn]['Expires'] = 0; // Allow refreshing forever
228
		return self::$var[$sn];
229
	}
230
231
	/**
232
	 * Gets a var from $var, $_REQUEST, or $default. Then stores it in the
233
	 * session so that it can still be retrieved when the page auto-refreshes.
234
	 * This is the recommended way to get $_REQUEST data for display pages.
235
	 * For processing pages, see the Request class.
236
	 */
237
	public static function getRequestVar(string $varName, string $default = null) : string {
238
		$result = Request::getVar($varName, $default);
239
		self::updateVar($varName, $result);
240
		return $result;
241
	}
242
243
	public static function getRequestVarInt(string $varName, int $default = null) : int {
244
		$result = Request::getVarInt($varName, $default);
245
		self::updateVar($varName, $result);
246
		return $result;
247
	}
248
249
	public static function getRequestVarIntArray(string $varName, array $default = null) : array {
250
		$result = Request::getVarIntArray($varName, $default);
251
		self::updateVar($varName, $result);
252
		return $result;
253
	}
254
255
	public static function resetLink(Page $container, string $sn) : string {
256
		//Do not allow sharing SN, useful for forwarding.
257
		global $lock;
258
		if (isset(self::$var[$sn]['CommonID'])) {
259
			unset(self::$commonIDs[self::$var[$sn]['CommonID']]); //Do not store common id for reset page, to allow refreshing to always give the same page in response
260
		}
261
		self::$SN = $sn;
262
		if (!isset($container['Expires'])) {
263
			$container['Expires'] = 0; // Lasts forever
264
		}
265
		if (!isset($container['RemainingPageLoads'])) {
266
			$container['RemainingPageLoads'] = 1; // Allow refreshing
267
		}
268
		if (!isset($container['PreviousRequestTime'])) {
269
			if (isset(self::$var[$sn]['PreviousRequestTime'])) {
270
				$container['PreviousRequestTime'] = self::$var[$sn]['PreviousRequestTime']; // Copy across the previous request time if not explicitly set.
271
			}
272
		}
273
274
		self::$var[$sn] = $container;
275
		if (!$lock && !USING_AJAX) {
276
			self::update();
277
		}
278
		return $sn;
279
	}
280
281
	public static function updateVar(string $key, mixed $value) : void {
282
		global $var;
283
		if ($value === null) {
284
			if (isset($var[$key])) {
285
				unset($var[$key]);
286
			}
287
			if (isset($var[self::$SN][$key])) {
288
				unset(self::$var[self::$SN][$key]);
289
			}
290
		} else {
291
			$var[$key] = $value;
292
			self::$var[self::$SN][$key] = $value;
293
		}
294
	}
295
296
	public static function clearLinks() : void {
297
		self::$var = array(self::$SN => self::$var[self::$SN]);
298
		self::$commonIDs = array();
299
	}
300
301
	public static function addLink(Page $container) : string {
302
		$sn = self::generateSN($container);
303
		self::$var[$sn] = $container;
304
		return $sn;
305
	}
306
307
	protected static function generateSN(Page $container) : string {
308
		if (isset(self::$commonIDs[$container['CommonID']])) {
309
			$sn = self::$commonIDs[$container['CommonID']];
310
			$container['PreviousRequestTime'] = isset(self::$var[$sn]) ? self::$var[$sn]['PreviousRequestTime'] : Smr\Epoch::microtime();
311
		} else {
312
			do {
313
				$sn = random_alphabetic_string(6);
314
			} while (isset(self::$var[$sn]));
315
			$container['PreviousRequestTime'] = Smr\Epoch::microtime();
316
		}
317
		self::$commonIDs[$container['CommonID']] = $sn;
318
		return $sn;
319
	}
320
321
	public static function addAjaxReturns(string $element, string $contents) : bool {
322
		self::$ajaxReturns[$element] = $contents;
323
		return isset(self::$previousAjaxReturns[$element]) && self::$previousAjaxReturns[$element] == $contents;
324
	}
325
326
	public static function saveAjaxReturns() : void {
327
		if (empty(self::$ajaxReturns)) {
328
			return;
329
		}
330
		self::$db->query('UPDATE active_session SET ajax_returns=' . self::$db->escapeObject(self::$ajaxReturns, true) .
331
				' WHERE session_id=' . self::$db->escapeString(self::$session_id) . ' LIMIT 1');
332
	}
333
}
334
335
SmrSession::init();
336