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

Passed
Pull Request — master (#916)
by Dan
03:31
created

AbstractSmrAccount::getToggleAJAXHREF()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 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
	/**
623
	 * Return the ID associated with this account in the given history database.
624
	 */
625
	public function getOldAccountID($dbName) {
626
		return $this->oldAccountIDs[$dbName] ?? 0;
627
	}
628
629
	public function getLogin() {
630
		return $this->login;
631
	}
632
633
	public function getEmail() {
634
		return $this->email;
635
	}
636
637
	protected function setEmail($email) {
638
		if ($this->email == $email) {
639
			return;
640
		}
641
		$this->email = $email;
642
		$this->hasChanged = true;
643
	}
644
645
	/**
646
	 * Change e-mail address, unvalidate the account, and resend validation code
647
	 */
648
	public function changeEmail($email) {
649
		// get user and host for the provided address
650
		list($user, $host) = explode('@', $email);
651
652
		// check if the host got a MX or at least an A entry
653
		if (!checkdnsrr($host, 'MX') && !checkdnsrr($host, 'A')) {
654
			create_error('This is not a valid email address! The domain ' . $host . ' does not exist.');
655
		}
656
657
		if (strstr($email, ' ')) {
658
			create_error('The email is invalid! It cannot contain any spaces.');
659
		}
660
661
		$this->db->query('SELECT 1 FROM account WHERE email = ' . $this->db->escapeString($email) . ' and account_id != ' . $this->db->escapeNumber($this->getAccountID()) . ' LIMIT 1');
662
		if ($this->db->getNumRows() > 0) {
663
			create_error('This email address is already registered.');
664
		}
665
666
		$this->setEmail($email);
667
		$this->setValidationCode(random_string(10));
668
		$this->setValidated(false);
669
		$this->sendValidationEmail();
670
671
		// Remove an "Invalid email" ban (may or may not have one)
672
		if ($disabled = $this->isDisabled()) {
673
			if ($disabled['Reason'] == CLOSE_ACCOUNT_INVALID_EMAIL_REASON) {
674
				$this->unbanAccount($this);
675
			}
676
		}
677
	}
678
679
	public function sendValidationEmail() : void {
680
		// remember when we sent validation code
681
		$this->db->query('REPLACE INTO notification (notification_type, account_id, time)
682
				VALUES(\'validation_code\', '.$this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber(TIME) . ')');
683
684
		$emailMessage =
685
			'Your validation code is: ' . $this->getValidationCode() . EOL . EOL .
686
			'The Space Merchant Realms server is on the web at ' . URL;
687
688
		$mail = setupMailer();
689
		$mail->Subject = 'Space Merchant Realms Validation Code';
690
		$mail->setFrom('[email protected]', 'SMR Support');
691
		$mail->msgHTML(nl2br($emailMessage));
692
		$mail->addAddress($this->getEmail(), $this->getHofName());
693
		$mail->send();
694
	}
695
696
	public function getOffset() {
697
		return $this->offset;
698
	}
699
700
	public function getFontSize() {
701
		return $this->fontSize;
702
	}
703
704
	public function setFontSize($size) {
705
		if ($this->fontSize == $size) {
706
			return;
707
		}
708
		$this->fontSize = $size;
709
		$this->hasChanged = true;
710
	}
711
712
	// gets the extra CSS file linked in preferences
713
	public function getCssLink() {
714
		return $this->cssLink;
715
	}
716
717
	// sets the extra CSS file linked in preferences
718
	public function setCssLink($link) {
719
		if ($this->cssLink == $link) {
720
			return;
721
		}
722
		$this->cssLink = $link;
723
		$this->hasChanged = true;
724
	}
725
726
	public function getTemplate() {
727
		return $this->template;
728
	}
729
730
	public function setTemplate($template) {
731
		if ($this->template == $template) {
732
			return;
733
		}
734
		if (!in_array($template, Globals::getAvailableTemplates())) {
735
			throw new Exception('Template not allowed: ' . $template);
736
		}
737
		$this->template = $template;
738
		$this->hasChanged = true;
739
	}
740
741
	public function getColourScheme() {
742
		return $this->colourScheme;
743
	}
744
745
	public function setColourScheme($colourScheme) {
746
		if ($this->colourScheme == $colourScheme) {
747
			return;
748
		}
749
		if (!in_array($colourScheme, Globals::getAvailableColourSchemes($this->getTemplate()))) {
750
			throw new Exception('Colour scheme not allowed: ' . $colourScheme);
751
		}
752
		$this->colourScheme = $colourScheme;
753
		$this->hasChanged = true;
754
	}
755
756
	// gets the CSS URL based on the template name specified in preferences
757
	public function getCssUrl() {
758
		return CSS_URLS[$this->getTemplate()];
759
	}
760
761
	// gets the CSS_COLOUR URL based on the template and color scheme specified in preferences
762
	public function getCssColourUrl() {
763
		return CSS_COLOUR_URLS[$this->getTemplate()][$this->getColourScheme()];
764
	}
765
766
	/**
767
	 * The Hall Of Fame name is not html-escaped in the database, so to display
768
	 * it correctly we must escape html entities.
769
	 */
770
	public function getHofDisplayName($linked = false) {
771
		$hofDisplayName = htmlspecialchars($this->getHofName());
772
		if ($linked) {
773
			return '<a href="' . $this->getPersonalHofHREF() . '">' . $hofDisplayName . '</a>';
774
		} else {
775
			return $hofDisplayName;
776
		}
777
	}
778
779
	public function getHofName() {
780
		return $this->hofName;
781
	}
782
783
	public function setHofName($name) {
784
		if ($this->hofName == $name) {
785
			return;
786
		}
787
		$this->hofName = $name;
788
		$this->hasChanged = true;
789
	}
790
791
	public function getIrcNick() {
792
		return $this->ircNick;
793
	}
794
795
	public function setIrcNick($nick) {
796
		if ($this->ircNick == $nick) {
797
			return;
798
		}
799
		$this->ircNick = $nick;
800
		$this->hasChanged = true;
801
	}
802
803
	public function getDiscordId() {
804
		return $this->discordId;
805
	}
806
807
	public function setDiscordId($id) {
808
		if ($this->discordId == $id) {
809
			return;
810
		}
811
		$this->discordId = $id;
812
		$this->hasChanged = true;
813
	}
814
815
	public function getReferralLink() {
816
		return URL . '/login_create.php?ref=' . $this->getAccountID();
817
	}
818
819
	public function getShortDateFormat() {
820
		return $this->dateShort;
821
	}
822
823
	public function setShortDateFormat($format) {
824
		if ($this->dateShort == $format) {
825
			return;
826
		}
827
		$this->dateShort = $format;
828
		$this->hasChanged = true;
829
	}
830
831
	public function getShortTimeFormat() {
832
		return $this->timeShort;
833
	}
834
835
	public function setShortTimeFormat($format) {
836
		if ($this->timeShort == $format) {
837
			return;
838
		}
839
		$this->timeShort = $format;
840
		$this->hasChanged = true;
841
	}
842
843
	public function getValidationCode() {
844
		return $this->validation_code;
845
	}
846
847
	protected function setValidationCode($code) {
848
		if ($this->validation_code == $code) {
849
			return;
850
		}
851
		$this->validation_code = $code;
852
		$this->hasChanged = true;
853
	}
854
855
	public function setValidated($bool) {
856
		if ($this->validated == $bool) {
857
			return;
858
		}
859
		$this->validated = $bool;
860
		$this->hasChanged = true;
861
	}
862
863
	public function isValidated() {
864
		return $this->validated;
865
	}
866
867
	public function isLoggedIn() {
868
		$this->db->query('SELECT 1 FROM active_session WHERE account_id = ' . $this->db->escapeNumber($this->getAccountID()) . ' LIMIT 1');
869
		return $this->db->nextRecord();
870
	}
871
872
	/**
873
	 * Check if the given (plain-text) password is correct.
874
	 * Updates the password hash if necessary.
875
	 */
876
	public function checkPassword($password) {
877
		// New (safe) password hashes will start with a $, but accounts logging
878
		// in for the first time since the transition from md5 will still have
879
		// hex-only hashes.
880
		if (strpos($this->passwordHash, '$') === 0) {
881
			$result = password_verify($password, $this->passwordHash);
882
		} else {
883
			$result = $this->passwordHash === md5($password);
884
		}
885
886
		// If password is correct, but hash algorithm has changed, update the hash.
887
		// This will also update any obsolete md5 password hashes.
888
		if ($result && password_needs_rehash($this->passwordHash, PASSWORD_DEFAULT)) {
889
			$this->setPassword($password);
890
			$this->update();
891
		}
892
893
		return $result;
894
	}
895
896
	/**
897
	 * Set the (plain-text) password for this account.
898
	 */
899
	public function setPassword($password) {
900
		$hash = password_hash($password, PASSWORD_DEFAULT);
901
		if ($this->passwordHash === $hash) {
902
			return;
903
		}
904
		$this->passwordHash = $hash;
905
		$this->generatePasswordReset();
906
		$this->hasChanged = true;
907
	}
908
909
	public function addAuthMethod($loginType, $authKey) {
910
		$this->db->query('SELECT account_id FROM account_auth WHERE login_type=' . $this->db->escapeString($loginType) . ' AND auth_key = ' . $this->db->escapeString($authKey) . ';');
911
		if ($this->db->nextRecord()) {
912
			if ($this->db->getInt('account_id') != $this->getAccountID()) {
913
				throw new Exception('Another account already uses this form of auth.');
914
			}
915
			return true;
916
		}
917
		$this->db->query('INSERT INTO account_auth values (' . $this->db->escapeNumber($this->getAccountID()) . ',' . $this->db->escapeString($loginType) . ',' . $this->db->escapeString($authKey) . ');');
918
		return true;
919
	}
920
921
	public function generatePasswordReset() {
922
		$this->setPasswordReset(random_string(32));
923
	}
924
925
	public function getPasswordReset() {
926
		return $this->passwordReset;
927
	}
928
929
	protected function setPasswordReset($passwordReset) {
930
		if ($this->passwordReset == $passwordReset) {
931
			return;
932
		}
933
		$this->passwordReset = $passwordReset;
934
		$this->hasChanged = true;
935
	}
936
937
	public function isDisplayShipImages() {
938
		return $this->images == 'Yes';
939
	}
940
941
	public function setDisplayShipImages($yesNo) {
942
		if ($this->images == $yesNo) {
943
			return;
944
		}
945
		$this->images = $yesNo;
946
		$this->hasChanged = true;
947
	}
948
949
	public function isUseAJAX() {
950
		return $this->useAJAX;
951
	}
952
953
	public function setUseAJAX($bool) {
954
		if ($this->useAJAX == $bool) {
955
			return;
956
		}
957
		$this->useAJAX = $bool;
958
		$this->hasChanged = true;
959
	}
960
961
	public function isDefaultCSSEnabled() {
962
		return $this->defaultCSSEnabled;
963
	}
964
965
	public function setDefaultCSSEnabled($bool) {
966
		if ($this->defaultCSSEnabled == $bool) {
967
			return;
968
		}
969
		$this->defaultCSSEnabled = $bool;
970
		$this->hasChanged = true;
971
	}
972
973
	public function getHotkeys($hotkeyType = false) {
974
		if ($hotkeyType !== false) {
975
			if (isset($this->hotkeys[$hotkeyType])) {
976
				return $this->hotkeys[$hotkeyType];
977
			} else {
978
				return array();
979
			}
980
		}
981
		return $this->hotkeys;
982
	}
983
984
	public function setHotkey($hotkeyType, $binding) {
985
		if ($this->getHotkeys($hotkeyType) == $binding) {
986
			return;
987
		}
988
		$this->hotkeys[$hotkeyType] = $binding;
989
		$this->hasChanged = true;
990
	}
991
992
	public function isReceivingMessageNotifications($messageTypeID) {
993
		return $this->getMessageNotifications($messageTypeID) > 0;
994
	}
995
996
	public function getMessageNotifications($messageTypeID) {
997
		return $this->messageNotifications[$messageTypeID] ?? 0;
998
	}
999
1000
	public function setMessageNotifications($messageTypeID, $num) {
1001
		if ($this->getMessageNotifications($messageTypeID) == $num) {
1002
			return;
1003
		}
1004
		$this->messageNotifications[$messageTypeID] = $num;
1005
		$this->hasChanged = true;
1006
	}
1007
1008
	public function increaseMessageNotifications($messageTypeID, $num) {
1009
		if ($num == 0) {
1010
			return;
1011
		}
1012
		if ($num < 0) {
1013
			throw new Exception('You cannot increase by a negative amount');
1014
		}
1015
		$this->setMessageNotifications($messageTypeID, $this->getMessageNotifications($messageTypeID) + $num);
1016
	}
1017
1018
	public function decreaseMessageNotifications($messageTypeID, $num) {
1019
		if ($num == 0) {
1020
			return;
1021
		}
1022
		if ($num < 0) {
1023
			throw new Exception('You cannot decrease by a negative amount');
1024
		}
1025
		$this->setMessageNotifications($messageTypeID, $this->getMessageNotifications($messageTypeID) - $num);
1026
	}
1027
1028
	public function isCenterGalaxyMapOnPlayer() {
1029
		return $this->centerGalaxyMapOnPlayer;
1030
	}
1031
1032
	public function setCenterGalaxyMapOnPlayer($bool) {
1033
		if ($this->centerGalaxyMapOnPlayer == $bool) {
1034
			return;
1035
		}
1036
		$this->centerGalaxyMapOnPlayer = $bool;
1037
		$this->hasChanged = true;
1038
	}
1039
1040
	public function getMailBanned() {
1041
		return $this->mailBanned;
1042
	}
1043
1044
	public function isMailBanned() {
1045
		return $this->mailBanned > TIME;
1046
	}
1047
1048
	public function setMailBanned($time) {
1049
		if ($this->mailBanned == $time) {
1050
			return;
1051
		}
1052
		$this->mailBanned = $time;
1053
		$this->hasChanged = true;
1054
	}
1055
1056
	public function increaseMailBanned($increaseTime) {
1057
		$time = max(TIME, $this->getMailBanned());
1058
		$this->setMailBanned($time + $increaseTime);
1059
	}
1060
	
1061
	public function getPermissions() {
1062
		if (!isset($this->permissions)) {
1063
			$this->permissions = array();
1064
			$this->db->query('SELECT permission_id FROM account_has_permission WHERE ' . $this->SQL);
1065
			while ($this->db->nextRecord()) {
1066
				$this->permissions[$this->db->getInt('permission_id')] = true;
1067
			}
1068
		}
1069
		return $this->permissions;
1070
	}
1071
1072
	public function hasPermission($permissionID = false) {
1073
		$permissions = $this->getPermissions();
1074
		if ($permissionID === false) {
1075
			return count($permissions) > 0;
1076
		}
1077
		return $permissions[$permissionID] ?? false;
1078
	}
1079
1080
	public function getPoints() {
1081
		if (!isset($this->points)) {
1082
			$this->points = 0;
1083
			$this->db->lockTable('account_has_points');
1084
			$this->db->query('SELECT * FROM account_has_points WHERE ' . $this->SQL . ' LIMIT 1');
1085
			if ($this->db->nextRecord()) {
1086
				$this->points = $this->db->getInt('points');
1087
				$lastUpdate = $this->db->getInt('last_update');
1088
				//we are gonna check for reducing points...
1089
				if ($this->points > 0 && $lastUpdate < TIME - (7 * 86400)) {
1090
					$removePoints = 0;
1091
					while ($lastUpdate < TIME - (7 * 86400)) {
1092
						$removePoints++;
1093
						$lastUpdate += (7 * 86400);
1094
					}
1095
					$this->removePoints($removePoints, $lastUpdate);
1096
				}
1097
			}
1098
			$this->db->unlock();
1099
		}
1100
		return $this->points;
1101
	}
1102
1103
	public function setPoints($numPoints, $lastUpdate = false) {
1104
		$numPoints = max($numPoints, 0);
1105
		if ($this->getPoints() == $numPoints) {
1106
			return;
1107
		}
1108
		if ($this->points == 0) {
1109
			$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) . ')');
1110
		} elseif ($numPoints <= 0) {
1111
			$this->db->query('DELETE FROM account_has_points WHERE ' . $this->SQL . ' LIMIT 1');
1112
		} else {
1113
			$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');
1114
		}
1115
		$this->points = $numPoints;
1116
	}
1117
1118
	public function removePoints($numPoints, $lastUpdate = false) {
1119
		if ($numPoints > 0) {
1120
			$this->setPoints($this->getPoints() - $numPoints, $lastUpdate);
1121
		}
1122
	}
1123
1124
	public function addPoints($numPoints, SmrAccount $admin, $reasonID, $suspicion) {
1125
		//do we have points
1126
		$this->setPoints($this->getPoints() + $numPoints, TIME);
1127
		$totalPoints = $this->getPoints();
1128
		if ($totalPoints < 10) {
1129
			return false; //leave scripts its only a warning
1130
		} elseif ($totalPoints < 20) {
1131
			$days = 2;
1132
		} elseif ($totalPoints < 30) {
1133
			$days = 4;
1134
		} elseif ($totalPoints < 50) {
1135
			$days = 7;
1136
		} elseif ($totalPoints < 75) {
1137
			$days = 15;
1138
		} elseif ($totalPoints < 100) {
1139
			$days = 30;
1140
		} elseif ($totalPoints < 125) {
1141
			$days = 60;
1142
		} elseif ($totalPoints < 150) {
1143
			$days = 120;
1144
		} elseif ($totalPoints < 175) {
1145
			$days = 240;
1146
		} elseif ($totalPoints < 200) {
1147
			$days = 480;
1148
		} else {
1149
			$days = 0; //Forever/indefinite
1150
		}
1151
1152
		if ($days == 0) {
1153
			$expireTime = 0;
1154
		} else {
1155
			$expireTime = TIME + $days * 86400;
1156
		}
1157
		$this->banAccount($expireTime, $admin, $reasonID, $suspicion);
1158
1159
		return $days;
1160
	}
1161
	
1162
	public function getFriendlyColour() {
1163
		return $this->friendlyColour;
1164
	}
1165
	public function setFriendlyColour($colour) {
1166
		$this->friendlyColour = $colour;
1167
		$this->hasChanged = true;
1168
	}
1169
	public function getNeutralColour() {
1170
		return $this->neutralColour;
1171
	}
1172
	public function setNeutralColour($colour) {
1173
		$this->neutralColour = $colour;
1174
		$this->hasChanged = true;
1175
	}
1176
	public function getEnemyColour() {
1177
		return $this->enemyColour;
1178
	}
1179
	public function setEnemyColour($colour) {
1180
		$this->enemyColour = $colour;
1181
		$this->hasChanged = true;
1182
	}
1183
1184
	public function banAccount($expireTime, SmrAccount $admin, $reasonID, $suspicion, $removeExceptions = false) {
1185
		$this->db->query('REPLACE INTO account_is_closed
1186
					(account_id, reason_id, suspicion, expires)
1187
					VALUES('.$this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber($reasonID) . ', ' . $this->db->escapeString($suspicion) . ', ' . $this->db->escapeNumber($expireTime) . ')');
1188
		$this->db->lockTable('active_session');
1189
		$this->db->query('DELETE FROM active_session WHERE ' . $this->SQL . ' LIMIT 1');
1190
		$this->db->unlock();
1191
1192
		$this->db->query('INSERT INTO account_has_closing_history
1193
						(account_id, time, admin_id, action)
1194
						VALUES(' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber(TIME) . ', ' . $this->db->escapeNumber($admin->getAccountID()) . ', ' . $this->db->escapeString('Closed') . ');');
1195
		$this->db->query('UPDATE player SET newbie_turns = 1
1196
						WHERE ' . $this->SQL . '
1197
						AND newbie_turns = 0
1198
						AND land_on_planet = ' . $this->db->escapeBoolean(false));
1199
1200
		$this->db->query('SELECT game_id FROM game JOIN player USING (game_id)
1201
						WHERE ' . $this->SQL . '
1202
						AND end_time >= ' . $this->db->escapeNumber(TIME));
1203
		while ($this->db->nextRecord()) {
1204
			$player = SmrPlayer::getPlayer($this->getAccountID(), $this->db->getInt('game_id'));
1205
			$player->updateTurns();
1206
			$player->update();
1207
		}
1208
		$this->log(LOG_TYPE_ACCOUNT_CHANGES, 'Account closed by ' . $admin->getLogin() . '.');
1209
		if ($removeExceptions !== false) {
1210
			$this->db->query('DELETE FROM account_exceptions WHERE ' . $this->SQL);
1211
		}
1212
	}
1213
1214
	public function unbanAccount(SmrAccount $admin = null, $currException = false) {
1215
		$adminID = 0;
1216
		if ($admin !== null) {
1217
			$adminID = $admin->getAccountID();
1218
		}
1219
		$this->db->query('DELETE FROM account_is_closed WHERE ' . $this->SQL . ' LIMIT 1');
1220
		$this->db->query('INSERT INTO account_has_closing_history
1221
						(account_id, time, admin_id, action)
1222
						VALUES(' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeNumber(TIME) . ', ' . $this->db->escapeNumber($adminID) . ', ' . $this->db->escapeString('Opened') . ')');
1223
		$this->db->query('UPDATE player SET last_turn_update = GREATEST(' . $this->db->escapeNumber(TIME) . ', last_turn_update) WHERE ' . $this->SQL);
1224
		if ($admin !== null) {
1225
			$this->log(LOG_TYPE_ACCOUNT_CHANGES, 'Account reopened by ' . $admin->getLogin() . '.');
1226
		} else {
1227
			$this->log(LOG_TYPE_ACCOUNT_CHANGES, 'Account automatically reopened.');
1228
		}
1229
		if ($currException !== false) {
1230
			$this->db->query('REPLACE INTO account_exceptions (account_id, reason)
1231
							VALUES (' . $this->db->escapeNumber($this->getAccountID()) . ', ' . $this->db->escapeString($currException) . ')');
1232
		}
1233
	}
1234
1235
	public function getToggleAJAXHREF() {
1236
		global $var;
1237
		return SmrSession::getNewHREF(create_container('toggle_processing.php', '', array('toggle'=>'AJAX', 'referrer'=>$var['body'])));
1238
	}
1239
1240
	public function getUserRankingHREF() {
1241
		return SmrSession::getNewHREF(create_container('skeleton.php', 'rankings_view.php'));
1242
	}
1243
1244
	public function getPersonalHofHREF() {
1245
		return SmrSession::getNewHREF(create_container('skeleton.php', 'hall_of_fame_player_detail.php', array('account_id' => $this->getAccountID())));
1246
	}
1247
}
1248