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