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
Push — live ( 05ca5f...631a24 )
by Dan
05:49
created

src/bootstrap.php (1 issue)

Labels
Severity
1
<?php declare(strict_types=1);
2
3
use Smr\Container\DiContainer;
4
use Smr\Exceptions\UserError;
5
use Smr\SectorLock;
6
use Smr\Session;
7
8
function logException(Throwable $e): void {
9
	$message = '';
10
	$delim = "\n\n-----------\n\n";
11
12
	$message .= 'Error Message: ' . $e . $delim;
13
14
	if (DiContainer::initialized(Session::class)) {
15
		$session = Session::getInstance();
16
17
		if ($session->hasAccount()) {
18
			$account = $session->getAccount();
19
			$message .= 'Login: ' . $account->getLogin() . "\n" .
20
				'E-Mail: ' . $account->getEmail() . "\n" .
21
				'Account ID: ' . $account->getAccountID();
22
			if ($session->hasGame()) {
23
				$message .= "\n" .
24
					'Game ID: ' . $session->getGameID() . "\n" .
25
					'Sector ID: ' . $session->getPlayer()->getSectorID();
26
			}
27
			$message .= $delim;
28
		}
29
30
		$var = $session->hasCurrentVar() ? $session->getCurrentVar() : null;
31
		$message .= '$var: ' . print_r($var, true) . $delim;
32
	}
33
34
	// Don't display passwords input by users in the log message!
35
	if (isset($_REQUEST['password'])) {
36
		$_REQUEST['password'] = '*****';
37
	}
38
	$message .= '$_REQUEST: ' . var_export($_REQUEST, true);
39
	$message .= $delim;
40
41
	$message .=
42
		'User IP: ' . getIpAddress() . "\n" .
43
		'User Agent: ' . ($_SERVER['HTTP_USER_AGENT'] ?? 'undefined') . "\n" .
44
		'USING_AJAX: ' . (defined('USING_AJAX') ? var_export(USING_AJAX, true) : 'undefined') . "\n" .
45
		'URL: ' . (defined('URL') ? URL : 'undefined');
46
47
	// Try to release lock so they can carry on normally
48
	if (DiContainer::initialized(SectorLock::class)) {
49
		try {
50
			SectorLock::getInstance()->release();
51
		} catch (Throwable $ee) {
52
			$message .= $delim .
53
					'Releasing Lock Failed' . "\n" .
54
					'Message: ' . $ee . "\n";
55
		}
56
	}
57
58
	if (defined('SCRIPT_ID')) {
59
		$message = 'Script: ' . SCRIPT_ID . $delim . $message . "\n\n";
60
	}
61
62
	// Unconditionally send error message to the log
63
	error_log($message);
64
65
	if (ENABLE_DEBUG) {
66
		// Display error message on the page (redundant with error_log for CLI)
67
		if (PHP_SAPI !== 'cli') {
68
			echo '<pre>' . $message . '</pre>';
69
		}
70
		// Skip remaining log methods (too disruptive during development)
71
		return;
72
	}
73
74
	// Send error message to the in-game auto bugs mailbox
75
	if (isset($session) && $session->hasGame()) {
76
		$session->getPlayer()->sendMessageToBox(BOX_BUGS_AUTO, $message);
77
	} elseif (isset($session) && $session->hasAccount()) {
78
		// Will be logged without a game_id
79
		$session->getAccount()->sendMessageToBox(BOX_BUGS_AUTO, $message);
80
	} else {
81
		// Will be logged without a game_id or sender_id
82
		SmrAccount::doMessageSendingToBox(0, BOX_BUGS_AUTO, $message, 0);
83
	}
84
85
	// Send error message to e-mail so that we have a permanent record
86
	if (!empty(BUG_REPORT_TO_ADDRESSES)) {
87
		$mail = setupMailer();
88
		$mail->Subject = (defined('PAGE_PREFIX') ? PAGE_PREFIX : '??? ') .
89
		                 'Automatic Bug Report';
90
		$mail->setFrom('[email protected]');
91
		$mail->Body = $message;
92
		foreach (BUG_REPORT_TO_ADDRESSES as $toAddress) {
93
			$mail->addAddress($toAddress);
94
		}
95
		$mail->send();
96
	}
97
}
98
99
/**
100
 * Handles all user-facing exceptions.
101
 *
102
 * If the error is fatal, the exception is logged and the player is redirected
103
 * to an appropriate error page.
104
 *
105
 * If the error is just informational (e.g. the user input an invalid value),
106
 * then the message is displayed on the page without being logged.
107
 */
108
function handleException(Throwable $e): void {
109
	// The real error message may display sensitive information, so we
110
	// need to catch any exceptions that are thrown while logging the error.
111
	try {
112
		if ($e instanceof UserError) {
113
			handleUserError($e->getMessage());
114
		}
115
		logException($e);
116
		$errorType = 'Unexpected Error!';
117
	} catch (Throwable $e2) {
118
		error_log('Original exception: ' . $e);
119
		error_log('Exception during logException: ' . $e2);
120
		$errorType = 'This error cannot be automatically reported. Please notify an admin!';
121
	}
122
123
	// If this is an ajax update, we don't really have a way to redirect
124
	// to an error page at this time.
125
	if (!ENABLE_DEBUG && (!defined('USING_AJAX') || !USING_AJAX)) {
126
		header('location: /error.php?msg=' . urlencode($errorType));
127
	}
128
}
129
130
/**
131
 * Can be used to convert any type of notice into an exception.
132
 */
133
function exception_error_handler(int $errno, string $errstr, string $errfile, int $errline): bool {
134
	if (!(error_reporting() & $errno)) {
135
		return false; // error is suppressed
136
	}
137
	throw new ErrorException($errstr, $errno, E_ERROR, $errfile, $errline);
138
}
139
140
function setupMailer(): \PHPMailer\PHPMailer\PHPMailer {
141
	$mail = new \PHPMailer\PHPMailer\PHPMailer(true);
142
	if (!empty(SMTP_HOSTNAME)) {
143
		$mail->isSMTP();
144
		$mail->Host = SMTP_HOSTNAME;
145
	}
146
	return $mail;
147
}
148
149
function getIpAddress(): string {
150
	foreach (['HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR'] as $key) {
151
		if (array_key_exists($key, $_SERVER) === true) {
152
			foreach (explode(',', $_SERVER[$key]) as $ip) {
153
				if (filter_var($ip, FILTER_VALIDATE_IP) !== false) {
154
					return $ip;
155
				}
156
			}
157
		}
158
	}
159
	return 'unknown';
160
}
161
162
/**
163
 * Wrapper around the floor() builtin for returning an integer type.
164
 */
165
function IFloor(float $val): int {
166
	return (int)floor($val);
167
}
168
169
/**
170
 * Wrapper around the ceil() builtin for returning an integer type.
171
 */
172
function ICeil(float $val): int {
173
	return (int)ceil($val);
174
}
175
176
/**
177
 * Wrapper around the round() builtin for returning an integer type.
178
 */
179
function IRound(float $val): int {
180
	return (int)round($val);
181
}
182
183
/**
184
 * Convert a numeric string to an int with input validation.
185
 */
186
function str2int(string $val): int {
187
	$result = filter_var($val, FILTER_VALIDATE_INT);
188
	if ($result === false) {
189
		throw new Exception('Input value is not an integer: ' . $val);
190
	}
191
	return $result;
192
}
193
194
/**
195
 * Generate a cryptographically strong random hexadecimal string.
196
 * The requested length must be a multiple of 2.
197
 */
198
function random_string(int $length): string {
199
	if ($length % 2 != 0) {
200
		throw new Exception('Length must be a multiple of 2!');
201
	}
202
	return bin2hex(random_bytes($length / 2));
203
}
204
205
/**
206
 * Generate a (non-cryptographic) random alphabetic string.
207
 * This is slower for longer strings.
208
 */
209
function random_alphabetic_string(int $length): string {
210
	$result = '';
211
	for ($i = 0; $i < $length; ++$i) {
212
		$result .= chr(rand(ord('a'), ord('z')));
213
	}
214
	return $result;
215
}
216
217
/**
218
 * Return the value of a random key from an array.
219
 *
220
 * @template T
221
 * @param array<T> $arr
222
 * @return T
223
 */
224
function array_rand_value(array $arr): mixed {
225
	if (empty($arr)) {
226
		throw new Exception('Cannot pick random value from empty array!');
227
	}
228
	return $arr[array_rand($arr)];
229
}
230
231
// Defines all constants
232
require_once('config.php');
233
234
// Set up vendor and class autoloaders
235
require_once(ROOT . 'vendor/autoload.php');
236
require_once(LIB . 'autoload.inc.php');
237
spl_autoload_register(get_class_loc(...));
0 ignored issues
show
A parse error occurred: Syntax error, unexpected ')' on line 237 at column 39
Loading history...
238
239
// Load common functions
240
require_once(LIB . 'Default/smr.inc.php');
241
242
// Set up dependency injection container
243
DiContainer::initialize(getenv('DISABLE_PHPDI_COMPILATION') !== 'true');
244