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 ( 45459f...d2e4ef )
by Dan
18s queued 15s
created

AbstractSmrAccount::setHotkey()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
// Exception thrown when an account cannot be found in the database
4
class AccountNotFoundException extends Exception {}
5
6
abstract class AbstractSmrAccount {
7
	const USER_RANKINGS_EACH_STAT_POW = .9;
8
	const USER_RANKINGS_TOTAL_SCORE_POW = .3;
9
	const USER_RANKINGS_RANK_BOUNDARY = 5.2;
10
	protected const USER_RANKINGS_SCORE = array(
11
		// [Stat, a, b]
12
		// Used as: pow(Stat * a, USER_RANKINGS_EACH_STAT_POW) * b
13
		array(array('Trade', 'Experience', 'Total'), .1, 0.5),
14
		array(array('Trade', 'Money', 'Profit'), 0.00005, 0.5),
15
		array(array('Killing', 'Kills'), 1000, 1)
16
		);
17
18
	protected static $CACHE_ACCOUNTS = array();
19
	protected const DEFAULT_HOTKEYS = array(
20
		'MoveUp' => array('w', 'up'),
21
		'ScanUp' => array('shift+w', 'shift+up'),
22
		'MoveLeft' => array('a', 'left'),
23
		'ScanLeft' => array('shift+a', 'shift+left'),
24
		'MoveRight' => array('d', 'right'),
25
		'ScanRight' => array('shift+d', 'shift+right'),
26
		'MoveDown' => array('s', 'down'),
27
		'ScanDown' => array('shift+s', 'shift+down'),
28
		'MoveWarp' => array('e', '0'),
29
		'ScanWarp' => array('shift+e', 'shift+0'),
30
		'ScanCurrent' => array('shift+1'),
31
		'CurrentSector' => array('1'),
32
		'LocalMap' => array('2'),
33
		'PlotCourse' => array('3'),
34
		'CurrentPlayers' => array('4'),
35
		'EnterPort' => array('q'),
36
		'AttackTrader' => array('f')
37
	);
38
39
	protected $db;
40
41
	protected $account_id;
42
	protected $login;
43
	protected $passwordHash;
44
	protected $email;
45
	protected $validated;
46
	protected $validation_code;
47
	protected $last_login;
48
	protected $hofName;
49
	protected $discordId;
50
	protected $ircNick;
51
	protected $veteranForced;
52
	protected $logging;
53
	protected $offset;
54
	protected $images;
55
	protected $fontSize;
56
	protected $passwordReset;
57
	protected $points;
58
	protected $useAJAX;
59
	protected $mailBanned;
60
	protected $HOF;
61
	protected $individualScores;
62
	protected $score;
63
	protected $cssLink;
64
	protected $defaultCSSEnabled;
65
	protected $messageNotifications;
66
	protected $centerGalaxyMapOnPlayer;
67
	protected $oldAccountIDs = array();
68
	protected $maxRankAchieved;
69
	protected $referrerID;
70
	protected $credits; // SMR credits
71
	protected $rewardCredits; // SMR reward credits
72
	protected $dateShort;
73
	protected $timeShort;
74
	protected $template;
75
	protected $colourScheme;
76
	protected $hotkeys = array();
77
	protected $permissions;
78
	protected $friendlyColour;
79
	protected $neutralColour;
80
	protected $enemyColour;
81
	protected $SQL;
82
83
	protected $npc;
84
85
	protected $hasChanged;
86
87
	public static function getDefaultHotkeys() {
88
		return self::DEFAULT_HOTKEYS;
89
	}
90
91
	public static function getAccount($accountID, $forceUpdate = false) {
92
		if ($forceUpdate || !isset(self::$CACHE_ACCOUNTS[$accountID])) {
93
			self::$CACHE_ACCOUNTS[$accountID] = new SmrAccount($accountID);
94
		}
95
		return self::$CACHE_ACCOUNTS[$accountID];
96
	}
97
98
	public static function getAccountByName($login, $forceUpdate = false) {
99
		if (empty($login)) { return null; }
100
		$db = new SmrMySqlDatabase();
101
		$db->query('SELECT account_id FROM account WHERE login = ' . $db->escapeString($login) . ' LIMIT 1');
102
		if ($db->nextRecord()) {
103
			return self::getAccount($db->getInt('account_id'), $forceUpdate);
104
		}
105
		$return = null;
106
		return $return;
107
	}
108
109
	public static function getAccountByEmail($email, $forceUpdate = false) {
110
		if (empty($email)) { return null; }
111
		$db = new SmrMySqlDatabase();
112
		$db->query('SELECT account_id FROM account WHERE email = ' . $db->escapeString($email) . ' LIMIT 1');
113
		if ($db->nextRecord()) {
114
			return self::getAccount($db->getInt('account_id'), $forceUpdate);
115
		} else {
116
			return null;
117
		}
118
	}
119
120
	public static function getAccountByDiscordId($id, $forceUpdate = false) {
121
		if (empty($id)) { return null; }
122
		$db = new SmrMySqlDatabase();
123
		$db->query('SELECT account_id FROM account where discord_id = ' . $db->escapeString($id) . ' LIMIT 1');
124
		if ($db->nextRecord()) {
125
			return self::getAccount($db->getInt('account_id'), $forceUpdate);
126
		} else {
127
			return null;
128
		}
129
	}
130
131
	public static function getAccountByIrcNick($nick, $forceUpdate = false) {
132
		if (empty($nick)) { return null; }
133
		$db = new SmrMySqlDatabase();
134
		$db->query('SELECT account_id FROM account WHERE irc_nick = ' . $db->escapeString($nick) . ' LIMIT 1');
135
		if ($db->nextRecord()) {
136
			return self::getAccount($db->getInt('account_id'), $forceUpdate);
137
		} else {
138
			return null;
139
		}
140
	}
141
142
	public static function getAccountBySocialLogin(SocialLogin $social, $forceUpdate = false) {
143
		if (!$social->isValid()) { return null; }
144
		$db = new SmrMySqlDatabase();
145
		$db->query('SELECT account_id FROM account JOIN account_auth USING(account_id)
146
		            WHERE login_type = '.$db->escapeString($social->getLoginType()) . '
147
		              AND auth_key = '.$db->escapeString($social->getUserID()) . ' LIMIT 1');
148
		if ($db->nextRecord()) {
149
			return self::getAccount($db->getInt('account_id'), $forceUpdate);
150
		} else {
151
			return null;
152
		}
153
	}
154
155
	public static function createAccount($login, $password, $email, $timez, $referral) {
156
		if ($referral != 0) {
157
			// Will throw if referral account doesn't exist
158
			SmrAccount::getAccount($referral);
159
		}
160
		$db = new SmrMySqlDatabase();
161
		$passwordHash = password_hash($password, PASSWORD_DEFAULT);
162
		$db->query('INSERT INTO account (login, password, email, validation_code, last_login, offset,referral_id,hof_name) VALUES(' .
163
			$db->escapeString($login) . ', ' . $db->escapeString($passwordHash) . ', ' . $db->escapeString($email) . ', ' .
164
			$db->escapeString(random_string(10)) . ',' . $db->escapeNumber(TIME) . ',' . $db->escapeNumber($timez) . ',' . $db->escapeNumber($referral) . ',' . $db->escapeString($login) . ')');
165
		return self::getAccountByName($login);
166
	}
167
168
	public static function getUserScoreCaseStatement($db) {
169
		$userRankingTypes = array();
170
		$case = 'FLOOR(SUM(CASE type ';
171
		foreach (self::USER_RANKINGS_SCORE as $userRankingScore) {
172
			$userRankingType = $db->escapeArray($userRankingScore[0], false, false, ':', false);
173
			$userRankingTypes[] = $userRankingType;
174
			$case .= ' WHEN ' . $db->escapeString($userRankingType) . ' THEN POW(amount*' . $userRankingScore[1] . ',' . SmrAccount::USER_RANKINGS_EACH_STAT_POW . ')*' . $userRankingScore[2];
175
		}
176
		$case .= ' END))';
177
		return array('CASE'=>$case, 'IN'=>$db->escapeArray($userRankingTypes));
178
	}
179
180
	protected function __construct($accountID) {
181
		$this->db = new SmrMySqlDatabase();
182
		$this->SQL = 'account_id = ' . $this->db->escapeNumber($accountID);
183
		$this->db->query('SELECT * FROM account WHERE ' . $this->SQL . ' LIMIT 1');
184
185
		if ($this->db->nextRecord()) {
186
			$row = $this->db->getRow();
187
			$this->account_id = $row['account_id'];
188
189
			$this->login			= $row['login'];
190
			$this->passwordHash = $row['password'];
191
			$this->email			= $row['email'];
192
			$this->validated = $this->db->getBoolean('validated');
193
194
			$this->last_login = $row['last_login'];
195
			$this->validation_code = $row['validation_code'];
196
			$this->veteranForced = $this->db->getBoolean('veteran');
197
			$this->logging = $this->db->getBoolean('logging');
198
			$this->offset			= $row['offset'];
199
			$this->images			= $row['images'];
200
			$this->fontSize = $row['fontsize'];
201
202
			$this->passwordReset = $row['password_reset'];
203
			$this->useAJAX = $this->db->getBoolean('use_ajax');
204
			$this->mailBanned = (int)$row['mail_banned'];
205
			
206
			$this->friendlyColour = $row['friendly_colour'];
207
			$this->neutralColour = $row['neutral_colour'];
208
			$this->enemyColour = $row['enemy_colour'];
209
210
			$this->cssLink = $row['css_link'];
211
			$this->defaultCSSEnabled = $this->db->getBoolean('default_css_enabled');
212
			$this->centerGalaxyMapOnPlayer = $this->db->getBoolean('center_galaxy_map_on_player');
213
214
			$this->messageNotifications = $this->db->getObject('message_notifications');
215
			$this->hotkeys = $this->db->getObject('hotkeys');
216
			foreach (self::DEFAULT_HOTKEYS as $hotkey => $binding) {
217
				if (!isset($this->hotkeys[$hotkey])) {
218
					$this->hotkeys[$hotkey] = $binding;
219
				}
220
			}
221
222
			foreach (Globals::getHistoryDatabases() as $databaseName => $oldColumn) {
223
				$this->oldAccountIDs[$databaseName] = $row[$oldColumn];
224
			}
225
226
			$this->referrerID = $row['referral_id'];
227
			$this->maxRankAchieved = $row['max_rank_achieved'];
228
229
			$this->hofName			= $row['hof_name'];
230
			$this->discordId		= $row['discord_id'];
231
			$this->ircNick			= $row['irc_nick'];
232
233
			$this->dateShort		= $row['date_short'];
234
			$this->timeShort		= $row['time_short'];
235
236
			$this->template			= $row['template'];
237
			$this->colourScheme = $row['colour_scheme'];
238
239
			if (empty($this->hofName)) {
240
				$this->hofName = $this->login;
241
			}
242
		} else {
243
			throw new AccountNotFoundException('Account ID ' . $accountID . ' does not exist!');
244
		}
245
	}
246
247
	public function isDisabled() {
248
		$this->db->query('SELECT * FROM account_is_closed JOIN closing_reason USING(reason_id) ' .
249
			'WHERE ' . $this->SQL . ' LIMIT 1');
250
		if ($this->db->nextRecord()) {
251
			// get the expire time
252
			$expireTime = $this->db->getInt('expires');
253
254
			// are we over this time?
255
			if ($expireTime > 0 && $expireTime < TIME) {
256
				// get rid of the expire entry
257
				$this->unbanAccount();
258
				return false;
259
			}
260
			return array('Time' => $expireTime,
261
				'Reason' => $this->db->getField('reason'),
262
				'ReasonID' => $this->db->getInt('reason_id')
263
			);
264
		} else {
265
			return false;
266
		}
267
	}
268
269
	public function update() {
270
		$this->db->query('UPDATE account SET email = ' . $this->db->escapeString($this->email) .
271
			', validation_code = ' . $this->db->escapeString($this->validation_code) .
272
			', validated = ' . $this->db->escapeBoolean($this->validated) .
273
			', password = ' . $this->db->escapeString($this->passwordHash) .
274
			', images = ' . $this->db->escapeString($this->images) .
275
			', password_reset = ' . $this->db->escapeString($this->passwordReset) .
276
			', use_ajax=' . $this->db->escapeBoolean($this->useAJAX) .
277
			', mail_banned=' . $this->db->escapeNumber($this->mailBanned) .
278
			', max_rank_achieved=' . $this->db->escapeNumber($this->maxRankAchieved) .
279
			', default_css_enabled=' . $this->db->escapeBoolean($this->defaultCSSEnabled) .
280
			', center_galaxy_map_on_player=' . $this->db->escapeBoolean($this->centerGalaxyMapOnPlayer) .
281
			', message_notifications=' . $this->db->escapeObject($this->messageNotifications) .
282
			', hotkeys=' . $this->db->escapeObject($this->hotkeys) .
283
			', last_login = ' . $this->db->escapeNumber($this->last_login) .
284
			', logging = ' . $this->db->escapeBoolean($this->logging) .
285
			', time_short = ' . $this->db->escapeString($this->timeShort) .
286
			', date_short = ' . $this->db->escapeString($this->dateShort) .
287
			', discord_id = ' . $this->db->escapeString($this->discordId, true, true) .
288
			', irc_nick = ' . $this->db->escapeString($this->ircNick, true, true) .
289
			', hof_name = ' . $this->db->escapeString($this->hofName) .
290
			', template = ' . $this->db->escapeString($this->template) .
291
			', colour_scheme = ' . $this->db->escapeString($this->colourScheme) .
292
			', fontsize = ' . $this->db->escapeNumber($this->fontSize) .
293
			', css_link = ' . $this->db->escapeString($this->cssLink, true, true) .
294
			', friendly_colour = ' . $this->db->escapeString($this->friendlyColour, true, true) .
295
			', neutral_colour = ' . $this->db->escapeString($this->neutralColour, true, true) .
296
			', enemy_colour = ' . $this->db->escapeString($this->enemyColour, true, true) .
297
			' WHERE ' . $this->SQL . ' LIMIT 1');
298
		$this->hasChanged = false;
299
	}
300
301
	public function updateIP() {
302
		$curr_ip = getIpAddress();
303
		$this->log(LOG_TYPE_LOGIN, 'logged in from ' . $curr_ip);
304
305
		// more than 50 elements in it?
306
307
		$this->db->query('SELECT time,ip FROM account_has_ip WHERE ' . $this->SQL . ' ORDER BY time ASC');
308
		if ($this->db->getNumRows() > 50 && $this->db->nextRecord()) {
309
			$delete_time = $this->db->getInt('time');
310
			$delete_ip = $this->db->getField('ip');
311
312
			$this->db->query('DELETE FROM account_has_ip
313
				WHERE '.$this->SQL . ' AND
314
				time = '.$this->db->escapeNumber($delete_time) . ' AND
315
				ip = '.$this->db->escapeString($delete_ip));
316
		}
317
		list($fi, $se, $th, $fo) = preg_split('/[.\s,]/', $curr_ip, 4);
318
		if ($curr_ip != 'unknown' && $curr_ip != 'unknown...' && $curr_ip != 'unknown, unknown') {
319
			$curr_ip = $fi . '.' . $se . '.' . $th . '.' . $fo;
320
			$host = gethostbyaddr($curr_ip);
321
		} else {
322
			$host = 'unknown';
323
		}
324
325
		// save...first make sure there isn't one for these keys (someone could double click and get error)
326
		$this->db->query('REPLACE INTO account_has_ip (account_id, time, ip, host) VALUES (' . $this->db->escapeNumber($this->account_id) . ', ' . $this->db->escapeNumber(TIME) . ', ' . $this->db->escapeString($curr_ip) . ', ' . $this->db->escapeString($host) . ')');
327
	}
328
329
	public function updateLastLogin() {
330
		if ($this->last_login == TIME) {
331
			return;
332
		}
333
		$this->last_login = TIME;
334
		$this->hasChanged = true;
335
		$this->update();
336
	}
337
338
	public function getLastLogin() {
339
		return $this->last_login;
340
	}
341
342
	public function setLoggingEnabled($bool) {
343
		if ($this->logging == $bool) {
344
			return;
345
		}
346
		$this->logging = $bool;
347
		$this->hasChanged = true;
348
	}
349
350
	public function isLoggingEnabled() {
351
		return $this->logging;
352
	}
353
354
	public function isVeteranForced() {
355
		return $this->veteranForced;
356
	}
357
358
	public function isVeteran() {
359
		// Use maxRankAchieved to avoid a database call to get user stats.
360
		// This saves a lot of time on the CPL, Rankings, Rosters, etc.
361
		return $this->isVeteranForced() || $this->maxRankAchieved >= FLEDGLING;
362
	}
363
364
	public function isNPC() {
365
		if(!isset($this->npc)) {
366
			$this->db->query('SELECT login FROM npc_logins WHERE login = '.$this->db->escapeString($this->getLogin()).' LIMIT 1;');
367
			$this->npc = $this->db->nextRecord();
368
		}
369
		return $this->npc;
370
	}
371
372
	protected function getHOFData() {
373
		if(!isset($this->HOF)) {
374
			//Get Player HOF
375
			$this->db->query('SELECT type,sum(amount) as amount FROM player_hof WHERE ' . $this->SQL . ' AND game_id IN (SELECT game_id FROM game WHERE ignore_stats = \'FALSE\') GROUP BY type');
376
			$this->HOF = array();
377
			while($this->db->nextRecord()) {
378
				$hof =& $this->HOF;
379
				$typeList = explode(':',$this->db->getField('type'));
380
				foreach($typeList as $type) {
381
					if(!isset($hof[$type])) {
382
						$hof[$type] = array();
383
					}
384
					$hof =& $hof[$type];
385
				}
386
				$hof = $this->db->getFloat('amount');
387
			}
388
		}
389
	}
390
391
	public function getHOF(array $typeList = null) {
392
		$this->getHOFData();
393
		if ($typeList == null) {
394
			return $this->HOF;
395
		}
396
		$hof = $this->HOF;
397
		foreach ($typeList as $type) {
398
			if (!isset($hof[$type])) {
399
				return 0;
400
			}
401
			$hof = $hof[$type];
402
		}
403
		return $hof;
404
	}
405
406
	public function getRankName() {
407
		$rankings = Globals::getUserRanking();
408
		if (isset($rankings[$this->getRank()])) {
409
			return $rankings[$this->getRank()];
410
		} else {
411
			return end($rankings);
412
		}
413
	}
414
415
	public function getScore() {
416
		if (!isset($this->score)) {
417
			$score = 0;
418
			foreach ($this->getIndividualScores() as $each) {
419
				$score += $each['Score'];
420
			}
421
			$this->score = round($score);
422
		}
423
		return $this->score;
424
	}
425
426
	public function getIndividualScores(SmrPlayer $player = null) {
427
		$gameID = 0;
428
		if ($player != null) {
429
			$gameID = $player->getGameID();
430
		}
431
		if (!isset($this->individualScores[$gameID])) {
432
			$this->individualScores[$gameID] = array();
433
			foreach (self::USER_RANKINGS_SCORE as $statScore) {
434
				if ($player == null) {
435
					$stat = $this->getHOF($statScore[0]);
436
				} else {
437
					$stat = $player->getHOF($statScore[0]);
438
				}
439
				$this->individualScores[$gameID][] = array('Stat'=>$statScore[0], 'Score'=>pow($stat * $statScore[1], self::USER_RANKINGS_EACH_STAT_POW) * $statScore[2]);
440
			}
441
		}
442
		return $this->individualScores[$gameID];
443
	}
444
445
	public function getRank() : int {
446
		$rank = ICeil(pow($this->getScore(), self::USER_RANKINGS_TOTAL_SCORE_POW) / self::USER_RANKINGS_RANK_BOUNDARY);
447
		if ($rank < 1) {
448
			$rank = 1;
449
		}
450
		if ($rank > $this->maxRankAchieved) {
451
			$this->updateMaxRankAchieved($rank);
452
		}
453
		return $rank;
454
	}
455
456
	protected function updateMaxRankAchieved($rank) {
457
		if ($rank <= $this->maxRankAchieved) {
458
			throw new Exception('Trying to set max rank achieved to a lower value: ' . $rank);
459
		}
460
		$delta = $rank - $this->maxRankAchieved;
461
		if ($this->hasReferrer()) {
462
			$this->getReferrer()->increaseSmrRewardCredits($delta * CREDITS_PER_DOLLAR);
463
		}
464
		$this->maxRankAchieved += $delta;
465
		$this->hasChanged = true;
466
		$this->update();
467
	}
468
469
	public function getReferrerID() {
470
		return $this->referrerID;
471
	}
472
473
	public function hasReferrer() {
474
		return $this->referrerID > 0;
475
	}
476
477
	public function getReferrer() {
478
		return SmrAccount::getAccount($this->getReferrerID());
479
	}
480
481
	public function log($log_type_id, $msg, $sector_id = 0) {
482
		if ($this->isLoggingEnabled()) {
483
			$this->db->query('INSERT INTO account_has_logs ' .
484
				'(account_id, microtime, log_type_id, message, sector_id) ' .
485
				'VALUES(' . $this->db->escapeNumber($this->account_id) . ', ' . $this->db->escapeMicrotime(MICRO_TIME) . ', ' . $this->db->escapeNumber($log_type_id) . ', ' . $this->db->escapeString($msg) . ', ' . $this->db->escapeNumber($sector_id) . ')');
486
		}
487
	}
488
489
	protected function getSmrCreditsData() {
490
		if (!isset($this->credits) || !isset($this->rewardCredits)) {
491
			$this->credits = 0;
492
			$this->rewardCredits = 0;
493
			$this->db->query('SELECT * FROM account_has_credits WHERE ' . $this->SQL . ' LIMIT 1');
494
			if ($this->db->nextRecord()) {
495
				$this->credits = $this->db->getInt('credits_left');
496
				$this->rewardCredits = $this->db->getInt('reward_credits');
497
			}
498
		}
499
	}
500
501
	public function getTotalSmrCredits() {
502
		return $this->getSmrCredits() + $this->getSmrRewardCredits();
503
	}
504
505
	public function decreaseTotalSmrCredits($totalCredits) {
506
		if ($totalCredits == 0) {
507
			return;
508
		}
509
		if ($totalCredits < 0) {
510
			throw new Exception('You cannot use negative total credits');
511
		}
512
		if ($totalCredits > $this->getTotalSmrCredits()) {
513
			throw new Exception('You do not have that many credits in total to use');
514
		}
515
516
		$rewardCredits = $this->rewardCredits;
517
		$credits = $this->credits;
518
		$rewardCredits -= $totalCredits;
519
		if ($rewardCredits < 0) {
520
			$credits += $rewardCredits;
521
			$rewardCredits = 0;
522
		}
523
		if ($this->credits == 0 && $this->rewardCredits == 0) {
524
			$this->db->query('REPLACE INTO account_has_credits (account_id, credits_left, reward_credits) VALUES(' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber($credits) . ',' . $this->db->escapeNumber($rewardCredits) . ')');
525
		} else {
526
			$this->db->query('UPDATE account_has_credits SET credits_left=' . $this->db->escapeNumber($credits) . ', reward_credits=' . $this->db->escapeNumber($rewardCredits) . ' WHERE ' . $this->SQL . ' LIMIT 1');
527
		}
528
		$this->credits = $credits;
529
		$this->rewardCredits = $rewardCredits;
530
	}
531
532
	public function getSmrCredits() {
533
		$this->getSmrCreditsData();
534
		return $this->credits;
535
	}
536
537
	public function getSmrRewardCredits() {
538
		$this->getSmrCreditsData();
539
		return $this->rewardCredits;
540
	}
541
542
	public function setSmrCredits($credits) {
543
		if ($this->getSmrCredits() == $credits) {
544
			return;
545
		}
546
		if ($this->credits == 0 && $this->rewardCredits == 0) {
547
			$this->db->query('REPLACE INTO account_has_credits (account_id, credits_left) VALUES(' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber($credits) . ')');
548
		} else {
549
			$this->db->query('UPDATE account_has_credits SET credits_left=' . $this->db->escapeNumber($credits) . ' WHERE ' . $this->SQL . ' LIMIT 1');
550
		}
551
		$this->credits = $credits;
552
	}
553
554
	public function increaseSmrCredits($credits) {
555
		if ($credits == 0) {
556
			return;
557
		}
558
		if ($credits < 0) {
559
			throw new Exception('You cannot gain negative credits');
560
		}
561
		$this->setSmrCredits($this->getSmrCredits() + $credits);
562
	}
563
564
	public function decreaseSmrCredits($credits) {
565
		if ($credits == 0) {
566
			return;
567
		}
568
		if ($credits < 0) {
569
			throw new Exception('You cannot use negative credits');
570
		}
571
		if ($credits > $this->getSmrCredits()) {
572
			throw new Exception('You cannot use more credits than you have');
573
		}
574
		$this->setSmrCredits($this->getSmrCredits() - $credits);
575
	}
576
577
	public function setSmrRewardCredits($credits) {
578
		if ($this->getSmrRewardCredits() == $credits) {
579
			return;
580
		}
581
		if ($this->credits == 0 && $this->rewardCredits == 0) {
582
			$this->db->query('REPLACE INTO account_has_credits (account_id, reward_credits) VALUES(' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber($credits) . ')');
583
		} else {
584
			$this->db->query('UPDATE account_has_credits SET reward_credits=' . $this->db->escapeNumber($credits) . ' WHERE ' . $this->SQL . ' LIMIT 1');
585
		}
586
		$this->rewardCredits = $credits;
587
	}
588
589
	public function increaseSmrRewardCredits($credits) {
590
		if ($credits == 0) {
591
			return;
592
		}
593
		if ($credits < 0) {
594
			throw new Exception('You cannot gain negative reward credits');
595
		}
596
		$this->setSmrRewardCredits($this->getSmrRewardCredits() + $credits);
597
	}
598
599
	public function sendMessageToBox($boxTypeID, $message) {
600
		// send him the message
601
		self::doMessageSendingToBox($this->getAccountID(), $boxTypeID, $message);
602
	}
603
604
	public static function doMessageSendingToBox($senderID, $boxTypeID, $message, $gameID = 0) {
605
		$db = new SmrMySqlDatabase();
606
		// send him the message
607
		$db->query('INSERT INTO message_boxes
608
			(box_type_id,game_id,message_text,
609
			sender_id,send_time) VALUES (' .
610
			$db->escapeNumber($boxTypeID) . ',' .
611
			$db->escapeNumber($gameID) . ',' .
612
			$db->escapeString($message) . ',' .
613
			$db->escapeNumber($senderID) . ',' .
614
			$db->escapeNumber(TIME) . ')'
615
		);
616
	}
617
618
	public function getAccountID() {
619
		return $this->account_id;
620
	}
621
622
	public function getOldAccountIDs() {
623
		return $this->oldAccountIDs;
624
	}
625
626
	public function getOldAccountID($dbName) {
627
		return $this->oldAccountIDs[$dbName] ?? 0;
628
	}
629
630
	public function hasOldAccountID($dbName = false) {
631
		if ($dbName === false) {
632
			return count($this->getOldAccountIDs()) != 0;
633
		}
634
		return $this->getOldAccountID($dbName) != 0;
635
	}
636
637
	public function getLogin() {
638
		return $this->login;
639
	}
640
641
	public function getEmail() {
642
		return $this->email;
643
	}
644
645
	protected function setEmail($email) {
646
		if ($this->email == $email) {
647
			return;
648
		}
649
		$this->email = $email;
650
		$this->hasChanged = true;
651
	}
652
653
	/**
654
	 * Change e-mail address, unvalidate the account, and resend validation code
655
	 */
656
	public function changeEmail($email) {
657
		// get user and host for the provided address
658
		list($user, $host) = explode('@', $email);
659
660
		// check if the host got a MX or at least an A entry
661
		if (!checkdnsrr($host, 'MX') && !checkdnsrr($host, 'A')) {
662
			create_error('This is not a valid email address! The domain ' . $host . ' does not exist.');
663
		}
664
665
		if (strstr($email, ' ')) {
666
			create_error('The email is invalid! It cannot contain any spaces.');
667
		}
668
669
		$this->db->query('SELECT 1 FROM account WHERE email = ' . $this->db->escapeString($email) . ' and account_id != ' . $this->db->escapeNumber($this->getAccountID()) . ' LIMIT 1');
670
		if ($this->db->getNumRows() > 0) {
671
			create_error('This email address is already registered.');
672
		}
673
674
		$this->setEmail($email);
675
		$this->setValidationCode(random_string(10));
676
		$this->setValidated(false);
677
		$this->sendValidationEmail();
678
679
		// Remove an "Invalid email" ban (may or may not have one)
680
		if ($disabled = $this->isDisabled()) {
681
			if ($disabled['Reason'] == CLOSE_ACCOUNT_INVALID_EMAIL_REASON) {
682
				$this->unbanAccount($this);
683
			}
684
		}
685
	}
686
687
	public function sendValidationEmail() : void {
688
		// remember when we sent validation code
689
		$this->db->query('REPLACE INTO notification (notification_type, account_id, time)
690
				VALUES(\'validation_code\', '.$this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber(TIME) . ')');
691
692
		$emailMessage =
693
			'Your validation code is: ' . $this->getValidationCode() . EOL . EOL .
694
			'The Space Merchant Realms server is on the web at ' . URL;
695
696
		$mail = setupMailer();
697
		$mail->Subject = 'Space Merchant Realms Validation Code';
698
		$mail->setFrom('[email protected]', 'SMR Support');
699
		$mail->msgHTML(nl2br($emailMessage));
700
		$mail->addAddress($this->getEmail(), $this->getHofName());
701
		$mail->send();
702
	}
703
704
	public function getOffset() {
705
		return $this->offset;
706
	}
707
708
	public function getFontSize() {
709
		return $this->fontSize;
710
	}
711
712
	public function setFontSize($size) {
713
		if ($this->fontSize == $size) {
714
			return;
715
		}
716
		$this->fontSize = $size;
717
		$this->hasChanged = true;
718
	}
719
720
	// gets the extra CSS file linked in preferences
721
	public function getCssLink() {
722
		return $this->cssLink;
723
	}
724
725
	// sets the extra CSS file linked in preferences
726
	public function setCssLink($link) {
727
		if ($this->cssLink == $link) {
728
			return;
729
		}
730
		$this->cssLink = $link;
731
		$this->hasChanged = true;
732
	}
733
734
	public function getTemplate() {
735
		return $this->template;
736
	}
737
738
	public function setTemplate($template) {
739
		if ($this->template == $template) {
740
			return;
741
		}
742
		if (!in_array($template, Globals::getAvailableTemplates())) {
743
			throw new Exception('Template not allowed: ' . $template);
744
		}
745
		$this->template = $template;
746
		$this->hasChanged = true;
747
	}
748
749
	public function getColourScheme() {
750
		return $this->colourScheme;
751
	}
752
753
	public function setColourScheme($colourScheme) {
754
		if ($this->colourScheme == $colourScheme) {
755
			return;
756
		}
757
		if (!in_array($colourScheme, Globals::getAvailableColourSchemes($this->getTemplate()))) {
758
			throw new Exception('Colour scheme not allowed: ' . $colourScheme);
759
		}
760
		$this->colourScheme = $colourScheme;
761
		$this->hasChanged = true;
762
	}
763
764
	// gets the CSS URL based on the template name specified in preferences
765
	public function getCssUrl() {
766
		return CSS_URLS[$this->getTemplate()];
767
	}
768
769
	// gets the CSS_COLOUR URL based on the template and color scheme specified in preferences
770
	public function getCssColourUrl() {
771
		return CSS_COLOUR_URLS[$this->getTemplate()][$this->getColourScheme()];
772
	}
773
774
	/**
775
	 * The Hall Of Fame name is not html-escaped in the database, so to display
776
	 * it correctly we must escape html entities.
777
	 */
778
	public function getHofDisplayName($linked = false) {
779
		$hofDisplayName = htmlspecialchars($this->getHofName());
780
		if ($linked) {
781
			return '<a href="' . $this->getPersonalHofHREF() . '">' . $hofDisplayName . '</a>';
782
		} else {
783
			return $hofDisplayName;
784
		}
785
	}
786
787
	public function getHofName() {
788
		return $this->hofName;
789
	}
790
791
	public function setHofName($name) {
792
		if ($this->hofName == $name) {
793
			return;
794
		}
795
		$this->hofName = $name;
796
		$this->hasChanged = true;
797
	}
798
799
	public function getIrcNick() {
800
		return $this->ircNick;
801
	}
802
803
	public function setIrcNick($nick) {
804
		if ($this->ircNick == $nick) {
805
			return;
806
		}
807
		$this->ircNick = $nick;
808
		$this->hasChanged = true;
809
	}
810
811
	public function getDiscordId() {
812
		return $this->discordId;
813
	}
814
815
	public function setDiscordId($id) {
816
		if ($this->discordId == $id) {
817
			return;
818
		}
819
		$this->discordId = $id;
820
		$this->hasChanged = true;
821
	}
822
823
	public function getReferralLink() {
824
		return URL . '/login_create.php?ref=' . $this->getAccountID();
825
	}
826
827
	public function getShortDateFormat() {
828
		return $this->dateShort;
829
	}
830
831
	public function setShortDateFormat($format) {
832
		if ($this->dateShort == $format) {
833
			return;
834
		}
835
		$this->dateShort = $format;
836
		$this->hasChanged = true;
837
	}
838
839
	public function getShortTimeFormat() {
840
		return $this->timeShort;
841
	}
842
843
	public function setShortTimeFormat($format) {
844
		if ($this->timeShort == $format) {
845
			return;
846
		}
847
		$this->timeShort = $format;
848
		$this->hasChanged = true;
849
	}
850
851
	public function getValidationCode() {
852
		return $this->validation_code;
853
	}
854
855
	protected function setValidationCode($code) {
856
		if ($this->validation_code == $code) {
857
			return;
858
		}
859
		$this->validation_code = $code;
860
		$this->hasChanged = true;
861
	}
862
863
	public function setValidated($bool) {
864
		if ($this->validated == $bool) {
865
			return;
866
		}
867
		$this->validated = $bool;
868
		$this->hasChanged = true;
869
	}
870
871
	public function isValidated() {
872
		return $this->validated;
873
	}
874
875
	public function isLoggedIn() {
876
		$this->db->query('SELECT 1 FROM active_session WHERE account_id = ' . $this->db->escapeNumber($this->getAccountID()) . ' LIMIT 1');
877
		return $this->db->nextRecord();
878
	}
879
880
	/**
881
	 * Check if the given (plain-text) password is correct.
882
	 * Updates the password hash if necessary.
883
	 */
884
	public function checkPassword($password) {
885
		// New (safe) password hashes will start with a $, but accounts logging
886
		// in for the first time since the transition from md5 will still have
887
		// hex-only hashes.
888
		if (strpos($this->passwordHash, '$') === 0) {
889
			$result = password_verify($password, $this->passwordHash);
890
		} else {
891
			$result = $this->passwordHash === md5($password);
892
		}
893
894
		// If password is correct, but hash algorithm has changed, update the hash.
895
		// This will also update any obsolete md5 password hashes.
896
		if ($result && password_needs_rehash($this->passwordHash, PASSWORD_DEFAULT)) {
897
			$this->setPassword($password);
898
			$this->update();
899
		}
900
901
		return $result;
902
	}
903
904
	/**
905
	 * Set the (plain-text) password for this account.
906
	 */
907
	public function setPassword($password) {
908
		$hash = password_hash($password, PASSWORD_DEFAULT);
909
		if ($this->passwordHash === $hash) {
910
			return;
911
		}
912
		$this->passwordHash = $hash;
913
		$this->generatePasswordReset();
914
		$this->hasChanged = true;
915
	}
916
917
	public function addAuthMethod($loginType, $authKey) {
918
		$this->db->query('SELECT account_id FROM account_auth WHERE login_type=' . $this->db->escapeString($loginType) . ' AND auth_key = ' . $this->db->escapeString($authKey) . ';');
919
		if ($this->db->nextRecord()) {
920
			if ($this->db->getInt('account_id') != $this->getAccountID()) {
921
				throw new Exception('Another account already uses this form of auth.');
922
			}
923
			return true;
924
		}
925
		$this->db->query('INSERT INTO account_auth values (' . $this->db->escapeNumber($this->getAccountID()) . ',' . $this->db->escapeString($loginType) . ',' . $this->db->escapeString($authKey) . ');');
926
		return true;
927
	}
928
929
	public function generatePasswordReset() {
930
		$this->setPasswordReset(random_string(32));
931
	}
932
933
	public function getPasswordReset() {
934
		return $this->passwordReset;
935
	}
936
937
	protected function setPasswordReset($passwordReset) {
938
		if ($this->passwordReset == $passwordReset) {
939
			return;
940
		}
941
		$this->passwordReset = $passwordReset;
942
		$this->hasChanged = true;
943
	}
944
945
	public function isDisplayShipImages() {
946
		return $this->images == 'Yes';
947
	}
948
949
	public function setDisplayShipImages($yesNo) {
950
		if ($this->images == $yesNo) {
951
			return;
952
		}
953
		$this->images = $yesNo;
954
		$this->hasChanged = true;
955
	}
956
957
	public function isUseAJAX() {
958
		return $this->useAJAX;
959
	}
960
961
	public function setUseAJAX($bool) {
962
		if ($this->useAJAX == $bool) {
963
			return;
964
		}
965
		$this->useAJAX = $bool;
966
		$this->hasChanged = true;
967
	}
968
969
	public function isDefaultCSSEnabled() {
970
		return $this->defaultCSSEnabled;
971
	}
972
973
	public function setDefaultCSSEnabled($bool) {
974
		if ($this->defaultCSSEnabled == $bool) {
975
			return;
976
		}
977
		$this->defaultCSSEnabled = $bool;
978
		$this->hasChanged = true;
979
	}
980
981
	public function getHotkeys($hotkeyType = false) {
982
		if ($hotkeyType !== false) {
983
			if (isset($this->hotkeys[$hotkeyType])) {
984
				return $this->hotkeys[$hotkeyType];
985
			} else {
986
				return array();
987
			}
988
		}
989
		return $this->hotkeys;
990
	}
991
992
	public function setHotkey($hotkeyType, $binding) {
993
		if ($this->getHotkeys($hotkeyType) == $binding) {
994
			return;
995
		}
996
		$this->hotkeys[$hotkeyType] = $binding;
997
		$this->hasChanged = true;
998
	}
999
1000
	public function isReceivingMessageNotifications($messageTypeID) {
1001
		return $this->getMessageNotifications($messageTypeID) > 0;
1002
	}
1003
1004
	public function getMessageNotifications($messageTypeID) {
1005
		return $this->messageNotifications[$messageTypeID] ?? 0;
1006
	}
1007
1008
	public function setMessageNotifications($messageTypeID, $num) {
1009
		if ($this->getMessageNotifications($messageTypeID) == $num) {
1010
			return;
1011
		}
1012
		$this->messageNotifications[$messageTypeID] = $num;
1013
		$this->hasChanged = true;
1014
	}
1015
1016
	public function increaseMessageNotifications($messageTypeID, $num) {
1017
		if ($num == 0) {
1018
			return;
1019
		}
1020
		if ($num < 0) {
1021
			throw new Exception('You cannot increase by a negative amount');
1022
		}
1023
		$this->setMessageNotifications($messageTypeID, $this->getMessageNotifications($messageTypeID) + $num);
1024
	}
1025
1026
	public function decreaseMessageNotifications($messageTypeID, $num) {
1027
		if ($num == 0) {
1028
			return;
1029
		}
1030
		if ($num < 0) {
1031
			throw new Exception('You cannot decrease by a negative amount');
1032
		}
1033
		$this->setMessageNotifications($messageTypeID, $this->getMessageNotifications($messageTypeID) - $num);
1034
	}
1035
1036
	public function isCenterGalaxyMapOnPlayer() {
1037
		return $this->centerGalaxyMapOnPlayer;
1038
	}
1039
1040
	public function setCenterGalaxyMapOnPlayer($bool) {
1041
		if ($this->centerGalaxyMapOnPlayer == $bool) {
1042
			return;
1043
		}
1044
		$this->centerGalaxyMapOnPlayer = $bool;
1045
		$this->hasChanged = true;
1046
	}
1047
1048
	public function getMailBanned() {
1049
		return $this->mailBanned;
1050
	}
1051
1052
	public function isMailBanned() {
1053
		return $this->mailBanned > TIME;
1054
	}
1055
1056
	public function setMailBanned($time) {
1057
		if ($this->mailBanned == $time) {
1058
			return;
1059
		}
1060
		$this->mailBanned = $time;
1061
		$this->hasChanged = true;
1062
	}
1063
1064
	public function increaseMailBanned($increaseTime) {
1065
		$time = max(TIME, $this->getMailBanned());
1066
		$this->setMailBanned($time + $increaseTime);
1067
	}
1068
	
1069
	public function getPermissions() {
1070
		if (!isset($this->permissions)) {
1071
			$this->permissions = array();
1072
			$this->db->query('SELECT permission_id FROM account_has_permission WHERE ' . $this->SQL);
1073
			while ($this->db->nextRecord()) {
1074
				$this->permissions[$this->db->getInt('permission_id')] = true;
1075
			}
1076
		}
1077
		return $this->permissions;
1078
	}
1079
1080
	public function hasPermission($permissionID = false) {
1081
		$permissions = $this->getPermissions();
1082
		if ($permissionID === false) {
1083
			return count($permissions) > 0;
1084
		}
1085
		return $permissions[$permissionID] ?? false;
1086
	}
1087
1088
	public function getPoints() {
1089
		if (!isset($this->points)) {
1090
			$this->points = 0;
1091
			$this->db->lockTable('account_has_points');
1092
			$this->db->query('SELECT * FROM account_has_points WHERE ' . $this->SQL . ' LIMIT 1');
1093
			if ($this->db->nextRecord()) {
1094
				$this->points = $this->db->getInt('points');
1095
				$lastUpdate = $this->db->getInt('last_update');
1096
				//we are gonna check for reducing points...
1097
				if ($this->points > 0 && $lastUpdate < TIME - (7 * 86400)) {
1098
					$removePoints = 0;
1099
					while ($lastUpdate < TIME - (7 * 86400)) {
1100
						$removePoints++;
1101
						$lastUpdate += (7 * 86400);
1102
					}
1103
					$this->removePoints($removePoints, $lastUpdate);
1104
				}
1105
			}
1106
			$this->db->unlock();
1107
		}
1108
		return $this->points;
1109
	}
1110
1111
	public function setPoints($numPoints, $lastUpdate = false) {
1112
		$numPoints = max($numPoints, 0);
1113
		if ($this->getPoints() == $numPoints) {
1114
			return;
1115
		}
1116
		if ($this->points == 0) {
1117
			$this->db->query('INSERT INTO account_has_points (account_id, points, last_update) VALUES (' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber($numPoints) . ', ' . $this->db->escapeNumber($lastUpdate ? $lastUpdate : TIME) . ')');
1118
		} elseif ($numPoints <= 0) {
1119
			$this->db->query('DELETE FROM account_has_points WHERE ' . $this->SQL . ' LIMIT 1');
1120
		} else {
1121
			$this->db->query('UPDATE account_has_points SET points = ' . $this->db->escapeNumber($numPoints) . ($lastUpdate ? ', last_update = ' . $this->db->escapeNumber(TIME) : '') . ' WHERE ' . $this->SQL . ' LIMIT 1');
1122
		}
1123
		$this->points = $numPoints;
1124
	}
1125
1126
	public function removePoints($numPoints, $lastUpdate = false) {
1127
		if ($numPoints > 0) {
1128
			$this->setPoints($this->getPoints() - $numPoints, $lastUpdate);
1129
		}
1130
	}
1131
1132
	public function addPoints($numPoints, SmrAccount $admin, $reasonID, $suspicion) {
1133
		//do we have points
1134
		$this->setPoints($this->getPoints() + $numPoints, TIME);
1135
		$totalPoints = $this->getPoints();
1136
		if ($totalPoints < 10) {
1137
			return false; //leave scripts its only a warning
1138
		} elseif ($totalPoints < 20) {
1139
			$days = 2;
1140
		} elseif ($totalPoints < 30) {
1141
			$days = 4;
1142
		} elseif ($totalPoints < 50) {
1143
			$days = 7;
1144
		} elseif ($totalPoints < 75) {
1145
			$days = 15;
1146
		} elseif ($totalPoints < 100) {
1147
			$days = 30;
1148
		} elseif ($totalPoints < 125) {
1149
			$days = 60;
1150
		} elseif ($totalPoints < 150) {
1151
			$days = 120;
1152
		} elseif ($totalPoints < 175) {
1153
			$days = 240;
1154
		} elseif ($totalPoints < 200) {
1155
			$days = 480;
1156
		} else {
1157
			$days = 0; //Forever/indefinite
1158
		}
1159
1160
		if ($days == 0) {
1161
			$expireTime = 0;
1162
		} else {
1163
			$expireTime = TIME + $days * 86400;
1164
		}
1165
		$this->banAccount($expireTime, $admin, $reasonID, $suspicion);
1166
1167
		return $days;
1168
	}
1169
	
1170
	public function getFriendlyColour() {
1171
		return $this->friendlyColour;
1172
	}
1173
	public function setFriendlyColour($colour) {
1174
		$this->friendlyColour = $colour;
1175
		$this->hasChanged = true;
1176
	}
1177
	public function getNeutralColour() {
1178
		return $this->neutralColour;
1179
	}
1180
	public function setNeutralColour($colour) {
1181
		$this->neutralColour = $colour;
1182
		$this->hasChanged = true;
1183
	}
1184
	public function getEnemyColour() {
1185
		return $this->enemyColour;
1186
	}
1187
	public function setEnemyColour($colour) {
1188
		$this->enemyColour = $colour;
1189
		$this->hasChanged = true;
1190
	}
1191
1192
	public function banAccount($expireTime, SmrAccount $admin, $reasonID, $suspicion, $removeExceptions = false) {
1193
		$this->db->query('REPLACE INTO account_is_closed
1194
					(account_id, reason_id, suspicion, expires)
1195
					VALUES('.$this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber($reasonID) . ', ' . $this->db->escapeString($suspicion) . ', ' . $this->db->escapeNumber($expireTime) . ')');
1196
		$this->db->lockTable('active_session');
1197
		$this->db->query('DELETE FROM active_session WHERE ' . $this->SQL . ' LIMIT 1');
1198
		$this->db->unlock();
1199
1200
		$this->db->query('INSERT INTO account_has_closing_history
1201
						(account_id, time, admin_id, action)
1202
						VALUES(' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber(TIME) . ', ' . $this->db->escapeNumber($admin->getAccountID()) . ', ' . $this->db->escapeString('Closed') . ');');
1203
		$this->db->query('UPDATE player SET newbie_turns = 1
1204
						WHERE ' . $this->SQL . '
1205
						AND newbie_turns = 0
1206
						AND land_on_planet = ' . $this->db->escapeBoolean(false));
1207
1208
		$this->db->query('SELECT game_id FROM game JOIN player USING (game_id)
1209
						WHERE ' . $this->SQL . '
1210
						AND end_time >= ' . $this->db->escapeNumber(TIME));
1211
		while ($this->db->nextRecord()) {
1212
			$player = SmrPlayer::getPlayer($this->getAccountID(), $this->db->getInt('game_id'));
1213
			$player->updateTurns();
1214
			$player->update();
1215
		}
1216
		$this->log(LOG_TYPE_ACCOUNT_CHANGES, 'Account closed by ' . $admin->getLogin() . '.');
1217
		if ($removeExceptions !== false) {
1218
			$this->db->query('DELETE FROM account_exceptions WHERE ' . $this->SQL);
1219
		}
1220
	}
1221
1222
	public function unbanAccount(SmrAccount $admin = null, $currException = false) {
1223
		$adminID = 0;
1224
		if ($admin !== null) {
1225
			$adminID = $admin->getAccountID();
1226
		}
1227
		$this->db->query('DELETE FROM account_is_closed WHERE ' . $this->SQL . ' LIMIT 1');
1228
		$this->db->query('INSERT INTO account_has_closing_history
1229
						(account_id, time, admin_id, action)
1230
						VALUES(' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber(TIME) . ', ' . $this->db->escapeNumber($adminID) . ', ' . $this->db->escapeString('Opened') . ')');
1231
		$this->db->query('UPDATE player SET last_turn_update = GREATEST(' . $this->db->escapeNumber(TIME) . ', last_turn_update) WHERE ' . $this->SQL);
1232
		if ($admin !== null) {
1233
			$this->log(LOG_TYPE_ACCOUNT_CHANGES, 'Account reopened by ' . $admin->getLogin() . '.');
1234
		} else {
1235
			$this->log(LOG_TYPE_ACCOUNT_CHANGES, 'Account automatically reopened.');
1236
		}
1237
		if ($currException !== false) {
1238
			$this->db->query('REPLACE INTO account_exceptions (account_id, reason)
1239
							VALUES (' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeString($currException) . ')');
1240
		}
1241
	}
1242
1243
	public function getToggleAJAXHREF() {
1244
		global $var;
1245
		return SmrSession::getNewHREF(create_container('toggle_processing.php', '', array('toggle'=>'AJAX', 'referrer'=>$var['body'])));
1246
	}
1247
1248
	public function getUserRankingHREF() {
1249
		return SmrSession::getNewHREF(create_container('skeleton.php', 'rankings_view.php'));
1250
	}
1251
1252
	public function getPersonalHofHREF() {
1253
		return SmrSession::getNewHREF(create_container('skeleton.php', 'hall_of_fame_player_detail.php', array('account_id' => $this->getAccountID())));
1254
	}
1255
}
1256