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

Failed Conditions
Pull Request — master (#1038)
by Dan
11:47
created

create_link()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
cc 3
nc 4
nop 3
1
<?php declare(strict_types=1);
2
3
function htmliseMessage($message) {
4
	$message = htmlentities($message, ENT_COMPAT, 'utf-8');
5
	$message = str_replace('&lt;br /&gt;', '<br />', $message);
6
	return $message;
7
}
8
9
function parseBoolean($check) {
10
	// Only negative strings are not implicitly converted to the correct bool
11
	if (is_string($check) && (strcasecmp($check, 'NO') == 0 || strcasecmp($check, 'FALSE') == 0)) {
12
		return false;
13
	}
14
	return (bool)$check;
15
}
16
17
function linkCombatLog($logID) {
18
	$container = Page::create('combat_log_viewer_verify.php');
19
	$container['log_id'] = $logID;
20
	return '<a href="' . $container->href() . '"><img src="images/notify.gif" width="14" height="11" border="0" title="View the combat log" /></a>';
21
}
22
23
/**
24
 * Converts a BBCode tag into some other text depending on the tag and value.
25
 * This is called in two stages: first with action BBCODE_CHECK (where the
26
 * returned value must be a boolean) and second, if the first check passes,
27
 * with action BBCODE_OUTPUT.
28
 */
29
function smrBBCode($bbParser, $action, $tagName, $default, $tagParams, $tagContent) {
0 ignored issues
show
Unused Code introduced by
The parameter $bbParser is not used and could be removed. ( Ignorable by Annotation )

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

29
function smrBBCode(/** @scrutinizer ignore-unused */ $bbParser, $action, $tagName, $default, $tagParams, $tagContent) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
30
	global $overrideGameID, $disableBBLinks;
31
	$session = Smr\Session::getInstance();
32
	try {
33
		switch ($tagName) {
34
			case 'combatlog':
35
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
36
					return is_numeric($default);
37
				}
38
				$logID = (int)$default;
39
				return linkCombatLog($logID);
40
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
41
			case 'player':
42
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
43
					return is_numeric($default);
44
				}
45
				$playerID = (int)$default;
46
				$bbPlayer = SmrPlayer::getPlayerByPlayerID($playerID, $overrideGameID);
47
				$showAlliance = isset($tagParams['showalliance']) ? parseBoolean($tagParams['showalliance']) : false;
48
				if ($disableBBLinks === false && $overrideGameID == $session->getGameID()) {
49
					return $bbPlayer->getLinkedDisplayName($showAlliance);
50
				}
51
				return $bbPlayer->getDisplayName($showAlliance);
52
			break;
53
			case 'alliance':
54
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
55
					return is_numeric($default);
56
				}
57
				$allianceID = (int)$default;
58
				$alliance = SmrAlliance::getAlliance($allianceID, $overrideGameID);
59
				if ($disableBBLinks === false && $overrideGameID == $session->getGameID()) {
60
					$container = Page::create('skeleton.php');
61
					$container['alliance_id'] = $alliance->getAllianceID();
62
					if ($session->hasGame() && $alliance->getAllianceID() == $session->getPlayer()->getAllianceID()) {
63
						$container['body'] = 'alliance_mod.php';
64
					} else {
65
						$container['body'] = 'alliance_roster.php';
66
					}
67
					return create_link($container, $alliance->getAllianceDisplayName());
68
				}
69
				return $alliance->getAllianceDisplayName();
70
			break;
71
			case 'race':
72
				$raceNameID = $default;
73
				foreach (Globals::getRaces() as $raceID => $raceInfo) {
74
					if ((is_numeric($raceNameID) && $raceNameID == $raceID)
75
						|| $raceNameID == $raceInfo['Race Name']) {
76
						if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
77
							return true;
78
						}
79
						$linked = $disableBBLinks === false && $overrideGameID == $session->getGameID();
80
						$player = $session->hasGame() ? $session->getPlayer() : null;
81
						return AbstractSmrPlayer::getColouredRaceNameOrDefault($raceID, $player, $linked);
82
					}
83
				}
84
			break;
85
			case 'servertimetouser':
86
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
87
					return true;
88
				}
89
				$timeString = $default;
90
				if ($timeString != '' && ($time = strtotime($timeString)) !== false) {
91
					if ($session->hasAccount()) {
92
						$time += $session->getAccount()->getOffset() * 3600;
93
					}
94
					return date(DATE_FULL_SHORT, $time);
95
				}
96
			break;
97
			case 'chess':
98
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
99
					return is_numeric($default);
100
				}
101
				$chessGameID = (int)$default;
102
				$chessGame = ChessGame::getChessGame($chessGameID);
103
				return '<a href="' . $chessGame->getPlayGameHREF() . '">chess game (' . $chessGame->getChessGameID() . ')</a>';
104
			break;
105
106
			case 'sector':
107
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
108
					return is_numeric($default);
109
				}
110
111
				$sectorID = (int)$default;
112
				$sectorTag = '<span class="sectorColour">#' . $sectorID . '</span>';
113
114
				if ($disableBBLinks === false
115
					&& $session->hasGame()
116
					&& $session->getGameID() == $overrideGameID
117
					&& SmrSector::sectorExists($overrideGameID, $sectorID)) {
118
					return '<a href="' . Globals::getPlotCourseHREF($session->getPlayer()->getSectorID(), $sectorID) . '">' . $sectorTag . '</a>';
119
				}
120
121
				return $sectorTag;
122
			break;
123
			case 'join_alliance':
124
				if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
125
					return is_numeric($default);
126
				}
127
				$allianceID = (int)$default;
128
				$alliance = SmrAlliance::getAlliance($allianceID, $overrideGameID);
129
				$container = Page::create('alliance_invite_accept_processing.php');
130
				$container['alliance_id'] = $alliance->getAllianceID();
131
				return '<div class="buttonA"><a class="buttonA" href="' . $container->href() . '">Join ' . $alliance->getAllianceDisplayName() . '</a></div>';
132
			break;
133
		}
134
	} catch (Throwable $e) {
135
		// If there's an error, we will silently display the original text
136
	}
137
	if ($action == \Nbbc\BBCode::BBCODE_CHECK) {
138
		return false;
139
	}
140
	return htmlspecialchars($tagParams['_tag']) . $tagContent . htmlspecialchars($tagParams['_endtag']);
141
}
142
143
function xmlify($str) {
144
	$xml = htmlspecialchars($str, ENT_XML1, 'utf-8');
145
	return $xml;
146
}
147
148
function inify($text) {
149
	return str_replace(',', '', html_entity_decode($text));
150
}
151
152
function bbifyMessage($message, $noLinks = false) {
153
	static $bbParser;
154
	if (!isset($bbParser)) {
155
		$bbParser = new \Nbbc\BBCode();
156
		$bbParser->SetEnableSmileys(false);
157
		$bbParser->RemoveRule('wiki');
158
		$bbParser->RemoveRule('img');
159
		$bbParser->SetURLTarget('_blank');
160
		$bbParser->SetURLTargetable('override');
161
		$bbParser->setEscapeContent(false); // don't escape HTML, needed for News etc.
162
		$smrRule = array(
163
				'mode' => \Nbbc\BBCode::BBCODE_MODE_CALLBACK,
164
				'method' => 'smrBBCode',
165
				'class' => 'link',
166
				'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
167
				'end_tag' => \Nbbc\BBCode::BBCODE_PROHIBIT,
168
				'content' => \Nbbc\BBCode::BBCODE_PROHIBIT,
169
			);
170
		$bbParser->AddRule('combatlog', $smrRule);
171
		$bbParser->AddRule('player', $smrRule);
172
		$bbParser->AddRule('alliance', $smrRule);
173
		$bbParser->AddRule('race', $smrRule);
174
		$bbParser->AddRule('servertimetouser', $smrRule);
175
		$bbParser->AddRule('chess', $smrRule);
176
		$bbParser->AddRule('sector', $smrRule);
177
		$bbParser->addRule('join_alliance', $smrRule);
178
	}
179
	global $disableBBLinks;
180
	if ($noLinks === true) {
181
		$disableBBLinks = true;
182
	} else {
183
		$disableBBLinks = false;
184
	}
185
	if (strpos($message, '[') !== false) { //We have BBCode so let's do a full parse.
186
		$message = $bbParser->parse($message);
187
		$message = str_replace('&lt;br /&gt;', '<br />', $message);
188
	} else { //Otherwise just convert newlines
189
		$message = nl2br($message, true);
190
	}
191
	return $message;
192
}
193
194
function create_error($message) {
195
	$container = Page::create('skeleton.php', 'error.php');
196
	$container['message'] = $message;
197
	if (USING_AJAX) {
198
		// To avoid the page just not refreshing when an error is encountered
199
		// during ajax updates, use javascript to auto-redirect to the
200
		// appropriate error page.
201
		$errorHREF = $container->href();
202
		// json_encode the HREF as a safety precaution
203
		$template = Smr\Template::getInstance();
204
		$template->addJavascriptForAjax('EVAL', 'location.href = ' . json_encode($errorHREF));
205
	}
206
	$container->go();
207
}
208
209
function create_link(Page|string $container, $text, $class = null) {
210
	return '<a' . ($class == null ? '' : ' class="' . $class . '"') . ' href="' . (is_string($container) ? $container : $container->href()) . '">' . $text . '</a>';
211
}
212
213
function create_submit_link(Page $container, $text) {
214
	return '<a href="' . $container->href() . '" class="submitStyle">' . $text . '</a>';
215
}
216
217
function get_colored_text_range($value, $maxValue, $text = null, $minValue = 0, $type = 'Game', $return_type = 'Normal') {
218
	if ($text == null) {
219
		$text = number_format($value);
220
	}
221
	if ($maxValue - $minValue == 0) {
222
		return $text;
223
	} else {
224
		$normalisedValue = IRound(510 * max(0, min($maxValue, $value) - $minValue) / ($maxValue - $minValue)) - 255;
225
	}
226
	if ($type == 'Game') {
227
		if ($normalisedValue < 0) {
228
			$r_component = 'ff';
229
			$g_component = dechex(255 + $normalisedValue);
230
			if (strlen($g_component) == 1) {
231
				$g_component = '0' . $g_component;
232
			}
233
		} else if ($normalisedValue > 0) {
234
			$g_component = 'ff';
235
			$r_component = dechex(255 - $normalisedValue);
236
			if (strlen($r_component) == 1) {
237
				$r_component = '0' . $r_component;
238
			}
239
		} else {
240
			$r_component = 'ff';
241
			$g_component = 'ff';
242
		}
243
		$colour = $r_component . $g_component . '00';
244
		if ($return_type == 'Colour') {
245
			return $colour;
246
		}
247
		return '<span style="color:#' . $colour . '">' . $text . '</span>';
248
	} elseif ($type == 'IRC') {
249
		//IRC color codes
250
		if ($normalisedValue == 255) {
251
			$colour = '[k03]';
252
		} elseif ($normalisedValue == -255) {
253
			$colour = '[k04]';
254
		} else {
255
			$colour = '[k08]';
256
		}
257
		if ($return_type == 'Colour') {
258
			return $colour;
259
		}
260
		return $colour . $text;
261
	}
262
}
263
264
function get_colored_text($value, $text = null, $type = 'Game', $return_type = 'Normal') {
265
	return get_colored_text_range($value, 300, $text, -300, $type, $return_type);
266
}
267
268
function word_filter($string) {
269
	static $words;
270
271
	if (!is_array($words)) {
272
		$db = Smr\Database::getInstance();
273
		$db->query('SELECT word_value, word_replacement FROM word_filter');
274
		$words = array();
275
		while ($db->nextRecord()) {
276
			$row = $db->getRow();
277
			$words[] = array('word_value' => '/' . str_replace('/', '\/', $row['word_value']) . '/i', 'word_replacement'=> $row['word_replacement']);
278
		}
279
	}
280
281
	foreach ($words as $word) {
282
		$string = preg_replace($word['word_value'], $word['word_replacement'], $string);
283
	}
284
285
	return $string;
286
}
287
288
// choose correct pluralization based on amount
289
function pluralise($word, $count = 0) {
290
	if ($count == 1) {
291
		return $word;
292
	}
293
	if (strtolower($word) == 'is') {
294
		return 'are';
295
	}
296
	return $word . 's';
297
}
298
299
/**
300
 * This function is a hack around the old style http forward mechanism.
301
 * It is also responsible for setting most of the global variables
302
 * (see loader.php for the initialization of the globals).
303
 */
304
function do_voodoo() {
305
	global $lock;
306
307
	$session = Smr\Session::getInstance();
308
	$var = $session->getCurrentVar();
309
310
	if (!defined('AJAX_CONTAINER')) {
311
		define('AJAX_CONTAINER', isset($var['AJAX']) && $var['AJAX'] === true);
312
	}
313
314
	if (!AJAX_CONTAINER && USING_AJAX && $session->hasChangedSN()) {
315
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
316
	}
317
//	ob_clean();
318
319
	// create account object
320
	$account = $session->getAccount();
321
322
	if (!defined('DATE_DATE_SHORT')) {
323
		define('DATE_DATE_SHORT', $account->getShortDateFormat());
324
	}
325
	if (!defined('DATE_TIME_SHORT')) {
326
		define('DATE_TIME_SHORT', $account->getShortTimeFormat());
327
	}
328
	if (!defined('DATE_FULL_SHORT')) {
329
		define('DATE_FULL_SHORT', DATE_DATE_SHORT . ' ' . DATE_TIME_SHORT);
330
	}
331
	if (!defined('DATE_FULL_SHORT_SPLIT')) {
332
		define('DATE_FULL_SHORT_SPLIT', DATE_DATE_SHORT . '\<b\r /\>' . DATE_TIME_SHORT);
333
	}
334
335
	$db = Smr\Database::getInstance();
336
337
	if ($session->hasGame()) {
338
		if (SmrGame::getGame($session->getGameID())->hasEnded()) {
339
			Page::create('game_leave_processing.php', 'game_play.php', array('errorMsg' => 'The game has ended.'))->go();
340
		}
341
		// We need to acquire locks BEFORE getting the player information
342
		// Otherwise we could be working on stale information
343
		$db->query('SELECT sector_id FROM player WHERE account_id=' . $db->escapeNumber($account->getAccountID()) . ' AND game_id=' . $db->escapeNumber($session->getGameID()) . ' LIMIT 1');
344
		$db->requireRecord();
345
		$sector_id = $db->getInt('sector_id');
346
347
		global $locksFailed;
348
		if (!USING_AJAX //AJAX should never do anything that requires a lock.
349
//			&& !isset($var['url']) && ($var['body'] == 'current_sector.php' || $var['body'] == 'map_local.php') //Neither should CS or LM and they gets loaded a lot so should reduce lag issues with big groups.
350
			) {
351
			if (!$lock && !isset($locksFailed[$sector_id])) {
352
				if (!acquire_lock($sector_id)) {
353
					create_error('Failed to acquire sector lock');
354
				}
355
				//Refetch var info in case it changed between grabbing lock.
356
				$session->fetchVarInfo();
357
				if ($session->findCurrentVar() === false) {
358
					if (ENABLE_DEBUG) {
359
						$db->query('INSERT INTO debug VALUES (\'SPAM\',' . $db->escapeNumber($account->getAccountID()) . ',0,0)');
360
					}
361
					create_error('Please do not spam click!');
362
				}
363
			}
364
		}
365
366
		// Now that they've acquire a lock we can move on
367
		$player = $session->getPlayer();
368
369
		if ($player->isDead() && $var['url'] != 'death_processing.php' && !isset($var['override_death'])) {
370
			Page::create('death_processing.php')->go();
371
		}
372
373
		// update turns on that player
374
		$player->updateTurns();
375
376
		if (!$player->isDead() && $player->getNewbieTurns() <= NEWBIE_TURNS_WARNING_LIMIT &&
377
			$player->getNewbieWarning() &&
378
			$var['url'] != 'newbie_warning_processing.php')
379
			Page::create('newbie_warning_processing.php')->go();
380
	}
381
382
	// Initialize the template
383
	$template = Smr\Template::getInstance();
384
385
	// Execute the engine files.
386
	// This is where the majority of the page-specific work is performed.
387
	$var->process();
388
389
	if ($session->hasGame()) {
390
		$template->assign('UnderAttack', $player->removeUnderAttack());
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $player does not seem to be defined for all execution paths leading up to this point.
Loading history...
391
	}
392
393
	if ($lock) { //Only save if we have the lock.
394
		SmrSector::saveSectors();
395
		SmrShip::saveShips();
396
		SmrPlayer::savePlayers();
397
		SmrForce::saveForces();
398
		SmrPort::savePorts();
399
		SmrPlanet::savePlanets();
400
		if (class_exists('WeightedRandom', false)) {
401
			WeightedRandom::saveWeightedRandoms();
402
		}
403
		//Update session here to make sure current page $var is up to date before releasing lock.
404
		$session->update();
405
		release_lock();
406
	}
407
408
	//Nothing below this point should require the lock.
409
410
	$template->assign('TemplateBody', $var['body']);
411
	if ($session->hasGame()) {
412
		$template->assign('ThisSector', $player->getSector());
413
		$template->assign('ThisPlayer', $player);
414
		$template->assign('ThisShip', $player->getShip());
415
	}
416
	$template->assign('ThisAccount', $account);
417
	if ($account->getCssLink() != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $account->getCssLink() of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
418
		$template->assign('ExtraCSSLink', $account->getCssLink());
419
	}
420
	doSkeletonAssigns($template, $db);
421
422
	// Set ajax refresh time
423
	$ajaxRefresh = $var['AllowAjax'] ?? true; // hack for bar_gambling_processing.php
424
	if (!$account->isUseAJAX()) {
425
		$ajaxRefresh = false;
426
	}
427
	if ($ajaxRefresh) {
428
		// If we can refresh, specify the refresh interval in millisecs
429
		if ($session->hasGame() && $player->canFight()) {
430
			$ajaxRefresh = AJAX_UNPROTECTED_REFRESH_TIME;
431
		} else {
432
			$ajaxRefresh = AJAX_DEFAULT_REFRESH_TIME;
433
		}
434
	}
435
	$template->assign('AJAX_ENABLE_REFRESH', $ajaxRefresh);
436
437
	$template->display($var['url'], USING_AJAX || AJAX_CONTAINER);
438
439
	$session->update();
440
441
	exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
442
}
443
444
//xdebug_dump_function_profile(2);
445
446
// This is hackish, but without row level locking it's the best we can do
447
function acquire_lock($sector) {
448
	global $lock, $locksFailed;
449
450
	if ($lock) {
451
		return true;
452
	}
453
454
	// Insert ourselves into the queue.
455
	$session = Smr\Session::getInstance();
456
	$db = Smr\Database::getInstance();
457
	$db->query('INSERT INTO locks_queue (game_id,account_id,sector_id,timestamp) VALUES(' . $db->escapeNumber($session->getGameID()) . ',' . $db->escapeNumber($session->getAccountID()) . ',' . $db->escapeNumber($sector) . ',' . $db->escapeNumber(Smr\Epoch::time()) . ')');
458
	$lock = $db->getInsertID();
459
460
	for ($i = 0; $i < 250; ++$i) {
461
		if (time() - Smr\Epoch::time() >= LOCK_DURATION - LOCK_BUFFER) {
462
			break;
463
		}
464
		// If there is someone else before us in the queue we sleep for a while
465
		$db->query('SELECT COUNT(*) FROM locks_queue WHERE lock_id<' . $db->escapeNumber($lock) . ' AND sector_id=' . $db->escapeNumber($sector) . ' AND game_id=' . $db->escapeNumber($session->getGameID()) . ' AND timestamp > ' . $db->escapeNumber(Smr\Epoch::time() - LOCK_DURATION));
466
		$locksInQueue = -1;
0 ignored issues
show
Unused Code introduced by
The assignment to $locksInQueue is dead and can be removed.
Loading history...
467
		if ($db->nextRecord() && ($locksInQueue = $db->getInt('COUNT(*)')) > 0) {
468
			//usleep(100000 + mt_rand(0,50000));
469
470
			// We can only have one lock in the queue, anything more means someone is screwing around
471
			$db->query('SELECT COUNT(*) FROM locks_queue WHERE account_id=' . $db->escapeNumber($session->getAccountID()) . ' AND sector_id=' . $db->escapeNumber($sector) . ' AND timestamp > ' . $db->escapeNumber(Smr\Epoch::time() - LOCK_DURATION));
472
			if ($db->nextRecord() && $db->getInt('COUNT(*)') > 1) {
473
				release_lock();
474
				$locksFailed[$sector] = true;
475
				create_error('Multiple actions cannot be performed at the same time!');
476
			}
477
478
			usleep(25000 * $locksInQueue);
479
			continue;
480
		} else {
481
			return true;
482
		}
483
	}
484
485
	release_lock();
486
	$locksFailed[$sector] = true;
487
	return false;
488
}
489
490
function release_lock() {
491
	global $lock;
492
493
	if ($lock) {
494
		$db = Smr\Database::getInstance();
495
		$db->query('DELETE from locks_queue WHERE lock_id=' . $db->escapeNumber($lock) . ' OR timestamp<' . $db->escapeNumber(Smr\Epoch::time() - LOCK_DURATION));
496
	}
497
498
	$lock = false;
499
}
500
501
function doTickerAssigns($template, $player, $db) {
502
	//any ticker news?
503
	if ($player->hasTickers()) {
504
		$ticker = array();
505
		$max = Smr\Epoch::time() - 60;
506
		if ($player->hasTicker('NEWS')) {
507
			//get recent news (5 mins)
508
			$db->query('SELECT time,news_message FROM news WHERE game_id = ' . $db->escapeNumber($player->getGameID()) . ' AND time >= ' . $max . ' ORDER BY time DESC LIMIT 4');
509
			while ($db->nextRecord()) {
510
				$ticker[] = array('Time' => date(DATE_FULL_SHORT, $db->getInt('time')),
511
								'Message'=>$db->getField('news_message'));
512
			}
513
		}
514
		if ($player->hasTicker('SCOUT')) {
515
			$db->query('SELECT message_text,send_time FROM message
516
						WHERE account_id=' . $db->escapeNumber($player->getAccountID()) . '
517
						AND game_id=' . $db->escapeNumber($player->getGameID()) . '
518
						AND message_type_id=' . $db->escapeNumber(MSG_SCOUT) . '
519
						AND send_time>=' . $db->escapeNumber($max) . '
520
						AND sender_id NOT IN (SELECT account_id FROM player_has_ticker WHERE type='.$db->escapeString('BLOCK') . ' AND expires > ' . $db->escapeNumber(Smr\Epoch::time()) . ' AND game_id = ' . $db->escapeNumber($player->getGameID()) . ') AND receiver_delete = \'FALSE\'
521
						ORDER BY send_time DESC
522
						LIMIT 4');
523
			while ($db->nextRecord()) {
524
				$ticker[] = array('Time' => date(DATE_FULL_SHORT, $db->getInt('send_time')),
525
								'Message'=>$db->getField('message_text'));
526
			}
527
		}
528
		$template->assign('Ticker', $ticker);
529
	}
530
}
531
532
function doSkeletonAssigns($template, $db) {
533
	$session = Smr\Session::getInstance();
534
	$account = $session->getAccount();
535
536
	$template->assign('CSSLink', $account->getCssUrl());
537
	$template->assign('CSSColourLink', $account->getCssColourUrl());
538
539
	$template->assign('FontSize', $account->getFontSize() - 20);
540
	$template->assign('timeDisplay', date(DATE_FULL_SHORT_SPLIT, Smr\Epoch::time()));
541
542
	$container = Page::create('skeleton.php');
543
544
545
	if ($session->hasGame()) {
546
		$player = $session->getPlayer();
547
		$template->assign('GameName', SmrGame::getGame($session->getGameID())->getName());
548
		$template->assign('GameID', $session->getGameID());
549
550
		$template->assign('PlotCourseLink', Globals::getPlotCourseHREF());
551
552
		$template->assign('TraderLink', Globals::getTraderStatusHREF());
553
554
		$template->assign('PoliticsLink', Globals::getPoliticsHREF());
555
556
		$container['body'] = 'combat_log_list.php';
557
		$template->assign('CombatLogsLink', $container->href());
558
559
		$template->assign('PlanetLink', Globals::getPlanetListHREF($player->getAllianceID()));
560
561
		$container['body'] = 'forces_list.php';
562
		$template->assign('ForcesLink', $container->href());
563
564
		$template->assign('MessagesLink', Globals::getViewMessageBoxesHREF());
565
566
		$container['body'] = 'news_read_current.php';
567
		$template->assign('ReadNewsLink', $container->href());
568
569
		$container['body'] = 'galactic_post_current.php';
570
		$template->assign('GalacticPostLink', $container->href());
571
572
		$container['body'] = 'trader_search.php';
573
		$template->assign('SearchForTraderLink', $container->href());
574
575
		$container['body'] = 'rankings_player_experience.php';
576
		$template->assign('RankingsLink', $container->href());
577
578
		$container['body'] = 'hall_of_fame_new.php';
579
		$container['game_id'] = $player->getGameID();
580
		$template->assign('CurrentHallOfFameLink', $container->href());
581
	}
582
583
	$container = Page::create('skeleton.php', 'hall_of_fame_new.php');
584
	$template->assign('HallOfFameLink', $container->href());
585
586
	$template->assign('AccountID', $account->getAccountID());
587
	$template->assign('PlayGameLink', Page::create('game_leave_processing.php', 'game_play.php')->href());
588
589
	$template->assign('LogoutLink', Page::create('logoff.php')->href());
590
591
	$container = Page::create('game_leave_processing.php', 'admin_tools.php');
592
	$template->assign('AdminToolsLink', $container->href());
593
594
	$container = Page::create('skeleton.php', 'preferences.php');
595
	$template->assign('PreferencesLink', $container->href());
596
597
	$container['body'] = 'album_edit.php';
598
	$template->assign('EditPhotoLink', $container->href());
599
600
	$container['body'] = 'bug_report.php';
601
	$template->assign('ReportABugLink', $container->href());
602
603
	$container['body'] = 'contact.php';
604
	$template->assign('ContactFormLink', $container->href());
605
606
	$container['body'] = 'chat_rules.php';
607
	$template->assign('IRCLink', $container->href());
608
609
	$container['body'] = 'donation.php';
610
	$template->assign('DonateLink', $container->href());
611
612
613
614
	if ($session->hasGame()) {
615
		$db->query('SELECT message_type_id,COUNT(*) FROM player_has_unread_messages WHERE ' . $player->getSQL() . ' GROUP BY message_type_id');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $player does not seem to be defined for all execution paths leading up to this point.
Loading history...
616
617
		if ($db->getNumRows()) {
618
			$messages = array();
619
			while ($db->nextRecord()) {
620
				$messages[$db->getInt('message_type_id')] = $db->getInt('COUNT(*)');
621
			}
622
623
			$container = Page::create('skeleton.php', 'message_view.php');
624
625
			if (isset($messages[MSG_GLOBAL])) {
626
				$container['folder_id'] = MSG_GLOBAL;
627
				$template->assign('MessageGlobalLink', $container->href());
628
				$template->assign('MessageGlobalNum', $messages[MSG_GLOBAL]);
629
			}
630
631
			if (isset($messages[MSG_PLAYER])) {
632
				$container['folder_id'] = MSG_PLAYER;
633
				$template->assign('MessagePersonalLink', $container->href());
634
				$template->assign('MessagePersonalNum', $messages[MSG_PLAYER]);
635
			}
636
637
			if (isset($messages[MSG_SCOUT])) {
638
				$container['folder_id'] = MSG_SCOUT;
639
				$template->assign('MessageScoutLink', $container->href());
640
				$template->assign('MessageScoutNum', $messages[MSG_SCOUT]);
641
			}
642
643
			if (isset($messages[MSG_POLITICAL])) {
644
				$container['folder_id'] = MSG_POLITICAL;
645
				$template->assign('MessagePoliticalLink', $container->href());
646
				$template->assign('MessagePoliticalNum', $messages[MSG_POLITICAL]);
647
			}
648
649
			if (isset($messages[MSG_ALLIANCE])) {
650
				$container['folder_id'] = MSG_ALLIANCE;
651
				$template->assign('MessageAllianceLink', $container->href());
652
				$template->assign('MessageAllianceNum', $messages[MSG_ALLIANCE]);
653
			}
654
655
			if (isset($messages[MSG_ADMIN])) {
656
				$container['folder_id'] = MSG_ADMIN;
657
				$template->assign('MessageAdminLink', $container->href());
658
				$template->assign('MessageAdminNum', $messages[MSG_ADMIN]);
659
			}
660
661
			if (isset($messages[MSG_CASINO])) {
662
				$container['folder_id'] = MSG_CASINO;
663
				$template->assign('MessageCasinoLink', $container->href());
664
				$template->assign('MessageCasinoNum', $messages[MSG_CASINO]);
665
			}
666
667
			if (isset($messages[MSG_PLANET])) {
668
				$container = Page::create('planet_msg_processing.php');
669
				$template->assign('MessagePlanetLink', $container->href());
670
				$template->assign('MessagePlanetNum', $messages[MSG_PLANET]);
671
			}
672
		}
673
674
		$container = Page::create('skeleton.php', 'trader_search_result.php');
675
		$container['player_id'] = $player->getPlayerID();
676
		$template->assign('PlayerNameLink', $container->href());
677
678
		if (is_array(Globals::getHiddenPlayers()) && in_array($player->getAccountID(), Globals::getHiddenPlayers())) {
679
			$template->assign('PlayerInvisible', true);
680
		}
681
682
		// ******* Hardware *******
683
		$container = Page::create('skeleton.php', 'configure_hardware.php');
684
685
		$template->assign('HardwareLink', $container->href());
686
687
		// ******* Forces *******
688
		$template->assign('ForceDropLink', Page::create('skeleton.php', 'forces_drop.php')->href());
689
690
		$ship = $player->getShip();
691
		if ($ship->hasMines()) {
692
			$container = Page::create('forces_drop_processing.php');
693
			$container['owner_id'] = $player->getAccountID();
694
			$container['drop_mines'] = 1;
695
			$container->addVar('body', 'referrer');
696
			$template->assign('DropMineLink', $container->href());
697
		}
698
		if ($ship->hasCDs()) {
699
			$container = Page::create('forces_drop_processing.php');
700
			$container['owner_id'] = $player->getAccountID();
701
			$container['drop_combat_drones'] = 1;
702
			$container->addVar('body', 'referrer');
703
			$template->assign('DropCDLink', $container->href());
704
		}
705
706
		if ($ship->hasSDs()) {
707
			$container = Page::create('forces_drop_processing.php');
708
			$container['owner_id'] = $player->getAccountID();
709
			$container['drop_scout_drones'] = 1;
710
			$container->addVar('body', 'referrer');
711
			$template->assign('DropSDLink', $container->href());
712
		}
713
714
		$template->assign('CargoJettisonLink', Page::create('skeleton.php', 'cargo_dump.php')->href());
715
716
		$template->assign('WeaponReorderLink', Page::create('skeleton.php', 'weapon_reorder.php')->href());
717
718
	}
719
720
	// ------- VOTING --------
721
	$voteSites = array();
722
	foreach (VoteSite::getAllSites() as $site) {
723
		$voteSites[] = array(
724
			'img' => $site->getLinkImg($account->getAccountID(), $session->getGameID()),
725
			'url' => $site->getLinkUrl($account->getAccountID(), $session->getGameID()),
726
			'sn' => $site->getSN($account->getAccountID(), $session->getGameID()),
727
		);
728
	}
729
	$template->assign('VoteSites', $voteSites);
730
731
	// Determine the minimum time until the next vote across all sites
732
	$minVoteWait = VoteSite::getMinTimeUntilFreeTurns($account->getAccountID());
733
	if ($minVoteWait <= 0) {
734
		$template->assign('TimeToNextVote', 'now');
735
	} else {
736
		$template->assign('TimeToNextVote', 'in ' . format_time($minVoteWait, true));
737
	}
738
739
	// ------- VERSION --------
740
	$db->query('SELECT * FROM version ORDER BY went_live DESC LIMIT 1');
741
	$version = '';
742
	if ($db->nextRecord()) {
743
		$container = Page::create('skeleton.php', 'changelog_view.php');
744
		$version = create_link($container, 'v' . $db->getField('major_version') . '.' . $db->getField('minor_version') . '.' . $db->getField('patch_level'));
745
	}
746
747
	$template->assign('Version', $version);
748
	$template->assign('CurrentYear', date('Y', Smr\Epoch::time()));
749
}
750
751
/**
752
 * Convert an integer number of seconds into a human-readable time.
753
 * Seconds are omitted to avoid frequent and disruptive ajax updates.
754
 * Use short=true to use 1-letter units (e.g. "1h and 3m").
755
 * If seconds is negative, will append "ago" to the result.
756
 * If seconds is zero, will return only "now".
757
 * If seconds is <60, will prefix "less than" or "<" (HTML-safe).
758
 */
759
function format_time($seconds, $short = false) {
760
	if ($seconds == 0) {
761
		return "now";
762
	}
763
764
	if ($seconds < 0) {
765
		$past = true;
766
		$seconds = abs($seconds);
767
	} else {
768
		$past = false;
769
	}
770
771
	$minutes = ceil($seconds / 60);
772
	$hours = 0;
773
	$days = 0;
774
	$weeks = 0;
775
	if ($minutes >= 60) {
776
		$hours = floor($minutes / 60);
777
		$minutes = $minutes % 60;
778
	}
779
	if ($hours >= 24) {
780
		$days = floor($hours / 24);
781
		$hours = $hours % 24;
782
	}
783
	if ($days >= 7) {
784
		$weeks = floor($days / 7);
785
		$days = $days % 7;
786
	}
787
	$times = [
788
		'week' => $weeks,
789
		'day' => $days,
790
		'hour' => $hours,
791
		'minute' => $minutes,
792
	];
793
	$parts = [];
794
	foreach ($times as $unit => $amount) {
795
		if ($amount > 0) {
796
			if ($short) {
797
				$parts[] = $amount . $unit[0];
798
			} else {
799
				$parts[] = $amount . ' ' . pluralise($unit, $amount);
800
			}
801
		}
802
	}
803
804
	if (count($parts) == 1) {
805
		$result = $parts[0];
806
	} else {
807
		// e.g. 5h, 10m and 30s
808
		$result = join(', ', array_slice($parts, 0, -1)) . ' and ' . end($parts);
809
	}
810
811
	if ($seconds < 60) {
812
		$result = ($short ? '&lt;' : 'less than ') . $result;
813
	}
814
815
	if ($past) {
816
		$result .= ' ago';
817
	}
818
	return $result;
819
}
820
821
function number_colour_format($number, $justSign = false) {
822
	$formatted = '<span';
823
	if ($number > 0) {
824
		$formatted .= ' class="green">+';
825
	} else if ($number < 0) {
826
		$formatted .= ' class="red">-';
827
	} else {
828
		$formatted .= '>';
829
	}
830
	if ($justSign === false) {
831
		$decimalPlaces = 0;
832
		if (($pos = strpos((string)$number, '.')) !== false) {
833
			$decimalPlaces = strlen(substr((string)$number, $pos + 1));
834
		}
835
		$formatted .= number_format(abs($number), $decimalPlaces);
836
	}
837
	$formatted .= '</span>';
838
	return $formatted;
839
}
840
841
842
/**
843
 * Randomly choose an array key weighted by the array values.
844
 * Probabilities are relative to the total weight. For example:
845
 *
846
 * array(
847
 *    'A' => 1, // 10% chance
848
 *    'B' => 3, // 30% chance
849
 *    'C' => 6, // 60% chance
850
 * );
851
 */
852
function getWeightedRandom(array $choices) : string|int {
853
	// Normalize the weights so that their sum is much larger than 1.
854
	$maxWeight = max($choices);
855
	foreach ($choices as $key => $weight) {
856
		$choices[$key] = IRound($weight * 1000 / $maxWeight);
857
	}
858
859
	// Generate a random number that is lower than the sum of the weights.
860
	$rand = rand(1, array_sum($choices));
0 ignored issues
show
Bug introduced by
It seems like array_sum($choices) can also be of type double; however, parameter $max of rand() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

860
	$rand = rand(1, /** @scrutinizer ignore-type */ array_sum($choices));
Loading history...
861
862
	// Subtract weights from the random number until it is negative,
863
	// then return the key associated with that weight.
864
	foreach ($choices as $key => $weight) {
865
		$rand -= $weight;
866
		if ($rand <= 0) {
867
			return $key;
868
		}
869
	}
870
	throw new Exception('Internal error computing weights');
871
}
872