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