Completed
Pull Request — release-2.1 (#4069)
by Jeremy
08:58
created

install.php ➔ updateSettingsFile()   F

Complexity

Conditions 33
Paths 19492

Size

Total Lines 77
Code Lines 66

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 33
eloc 66
nc 19492
nop 1
dl 0
loc 77
rs 2.5035
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Simple Machines Forum (SMF)
5
 *
6
 * @package SMF
7
 * @author Simple Machines http://www.simplemachines.org
8
 * @copyright 2017 Simple Machines and individual contributors
9
 * @license http://www.simplemachines.org/about/smf/license.php BSD
10
 *
11
 * @version 2.1 Beta 3
12
 */
13
14
$GLOBALS['current_smf_version'] = '2.1 Beta 3';
15
$GLOBALS['db_script_version'] = '2-1';
16
17
$GLOBALS['required_php_version'] = '5.4.45';
18
19
// Don't have PHP support, do you?
20
// ><html dir="ltr"><head><title>Error!</title></head><body>Sorry, this installer requires PHP!<div style="display: none;">
21
22
// Let's pull in useful classes
23
if (!defined('SMF'))
24
	define('SMF', 1);
25
26
require_once('Sources/Class-Package.php');
27
28
// Database info.
29
$databases = array(
30
	'mysql' => array(
31
		'name' => 'MySQL',
32
		'version' => '5.0.3',
33
		'version_check' => 'return min(mysqli_get_server_info($db_connection), mysqli_get_client_info());',
34
		'supported' => function_exists('mysqli_connect'),
35
		'default_user' => 'mysql.default_user',
36
		'default_password' => 'mysql.default_password',
37
		'default_host' => 'mysql.default_host',
38
		'default_port' => 'mysql.default_port',
39
		'utf8_support' => function() {
40
			return true;
41
		},
42
		'utf8_version' => '5.0.3',
43
		'utf8_version_check' => 'return mysqli_get_server_info($db_connection);',
44
		'utf8_default' => true,
45
		'utf8_required' => true,
46
		'alter_support' => true,
47
		'validate_prefix' => function(&$value) {
48
			$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
49
			return true;
50
		},
51
	),
52
	'postgresql' => array(
53
		'name' => 'PostgreSQL',
54
		'version' => '9.1',
55
		'function_check' => 'pg_connect',
56
		'version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
57
		'supported' => function_exists('pg_connect'),
58
		'always_has_db' => true,
59
		'utf8_default' => true,
60
		'utf8_required' => true,
61
		'utf8_support' => function() {
62
			$request = pg_query('SHOW SERVER_ENCODING');
63
64
			list ($charcode) = pg_fetch_row($request);
65
66
			if ($charcode == 'UTF8')
67
				return true;
68
			else
69
				return false;
70
		},
71
		'utf8_version' => '8.0',
72
		'utf8_version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
73
		'validate_prefix' => function(&$value) {
74
			global $txt;
75
76
			$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
77
78
			// Is it reserved?
79
			if ($value == 'pg_')
80
				return $txt['error_db_prefix_reserved'];
81
82
			// Is the prefix numeric?
83
			if (preg_match('~^\d~', $value))
84
				return $txt['error_db_prefix_numeric'];
85
86
			return true;
87
		},
88
	),
89
);
90
91
global $txt;
92
93
// Initialize everything and load the language files.
94
initialize_inputs();
95
load_lang_file();
96
97
// This is what we are.
98
$installurl = $_SERVER['PHP_SELF'];
99
100
// All the steps in detail.
101
// Number,Name,Function,Progress Weight.
102
$incontext['steps'] = array(
103
	0 => array(1, $txt['install_step_welcome'], 'Welcome', 0),
104
	1 => array(2, $txt['install_step_writable'], 'CheckFilesWritable', 10),
105
	2 => array(3, $txt['install_step_databaseset'], 'DatabaseSettings', 15),
106
	3 => array(4, $txt['install_step_forum'], 'ForumSettings', 40),
107
	4 => array(5, $txt['install_step_databasechange'], 'DatabasePopulation', 15),
108
	5 => array(6, $txt['install_step_admin'], 'AdminAccount', 20),
109
	6 => array(7, $txt['install_step_delete'], 'DeleteInstall', 0),
110
);
111
112
// Default title...
113
$incontext['page_title'] = $txt['smf_installer'];
114
115
// What step are we on?
116
$incontext['current_step'] = isset($_GET['step']) ? (int) $_GET['step'] : 0;
117
118
// Loop through all the steps doing each one as required.
119
$incontext['overall_percent'] = 0;
120
121
foreach ($incontext['steps'] as $num => $step)
122
{
123
	if ($num >= $incontext['current_step'])
124
	{
125
		// The current weight of this step in terms of overall progress.
126
		$incontext['step_weight'] = $step[3];
127
		// Make sure we reset the skip button.
128
		$incontext['skip'] = false;
129
130
		// Call the step and if it returns false that means pause!
131
		if (function_exists($step[2]) && $step[2]() === false)
132
			break;
133
		elseif (function_exists($step[2]))
134
			$incontext['current_step']++;
135
136
		// No warnings pass on.
137
		$incontext['warning'] = '';
138
	}
139
	$incontext['overall_percent'] += $step[3];
140
}
141
142
// Actually do the template stuff.
143
installExit();
144
145
function initialize_inputs()
146
{
147
	global $databases;
148
149
	// Just so people using older versions of PHP aren't left in the cold.
150
	if (!isset($_SERVER['PHP_SELF']))
151
		$_SERVER['PHP_SELF'] = isset($GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']) ? $GLOBALS['HTTP_SERVER_VARS']['PHP_SELF'] : 'install.php';
152
153
	// Enable error reporting.
154
	error_reporting(E_ALL);
155
156
	// Fun.  Low PHP version...
157
	if (!isset($_GET))
158
	{
159
		$GLOBALS['_GET']['step'] = 0;
160
		return;
161
	}
162
163
	if (!isset($_GET['obgz']))
164
	{
165
		ob_start();
166
167
		if (ini_get('session.save_handler') == 'user')
168
			@ini_set('session.save_handler', 'files');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
169
		if (function_exists('session_start'))
170
			@session_start();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
171
	}
172
	else
173
	{
174
		ob_start('ob_gzhandler');
175
176
		if (ini_get('session.save_handler') == 'user')
177
			@ini_set('session.save_handler', 'files');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
178
		session_start();
179
180
		if (!headers_sent())
181
			echo '<!DOCTYPE html>
182
<html>
183
	<head>
184
		<title>', htmlspecialchars($_GET['pass_string']), '</title>
185
	</head>
186
	<body style="background-color: #d4d4d4; margin-top: 16%; text-align: center; font-size: 16pt;">
187
		<strong>', htmlspecialchars($_GET['pass_string']), '</strong>
188
	</body>
189
</html>';
190
		exit;
191
	}
192
193
	// Add slashes, as long as they aren't already being added.
194
	if (!function_exists('get_magic_quotes_gpc') || @get_magic_quotes_gpc() == 0)
195
		foreach ($_POST as $k => $v)
196
			if (strpos($k, 'password') === false && strpos($k, 'db_passwd') === false)
197
				$_POST[$k] = addslashes($v);
198
199
	// This is really quite simple; if ?delete is on the URL, delete the installer...
200
	if (isset($_GET['delete']))
201
	{
202
		if (isset($_SESSION['installer_temp_ftp']))
203
		{
204
			$ftp = new ftp_connection($_SESSION['installer_temp_ftp']['server'], $_SESSION['installer_temp_ftp']['port'], $_SESSION['installer_temp_ftp']['username'], $_SESSION['installer_temp_ftp']['password']);
205
			$ftp->chdir($_SESSION['installer_temp_ftp']['path']);
206
207
			$ftp->unlink('install.php');
208
209
			foreach ($databases as $key => $dummy)
210
			{
211
				$type = ($key == 'mysqli') ? 'mysql' : $key;
212
				$ftp->unlink('install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
213
			}
214
215
			$ftp->close();
216
217
			unset($_SESSION['installer_temp_ftp']);
218
		}
219
		else
220
		{
221
			@unlink(__FILE__);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
222
223
			foreach ($databases as $key => $dummy)
224
			{
225
				$type = ($key == 'mysqli') ? 'mysql' : $key;
226
				@unlink(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
227
			}
228
		}
229
230
		// Now just redirect to a blank.png...
231
		header('Location: http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png');
0 ignored issues
show
Security Response Splitting introduced by
'Location: http' . (!emp...fault/images/blank.png' can contain request data and is used in response header context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Fetching key HTTP_HOST from $_SERVER
    in other/install.php on line 231

Response Splitting Attacks

Allowing an attacker to set a response header, opens your application to response splitting attacks; effectively allowing an attacker to send any response, he would like.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
232
		exit;
233
	}
234
235
	// PHP 5 might cry if we don't do this now.
236
	if (function_exists('date_default_timezone_set'))
237
	{
238
		// Get PHP's default timezone, if set
239
		$ini_tz = ini_get('date.timezone');
240
		if (!empty($ini_tz))
241
			$timezone_id = $ini_tz;
242
		else
243
			$timezone_id = '';
244
245
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
246 View Code Duplication
		if (!in_array($timezone_id, timezone_identifiers_list()))
247
		{
248
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
249
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
250
		}
251
252
		date_default_timezone_set($timezone_id);
253
	}
254
255
	// Force an integer step, defaulting to 0.
256
	$_GET['step'] = (int) @$_GET['step'];
257
}
258
259
// Load the list of language files, and the current language file.
260
function load_lang_file()
261
{
262
	global $incontext;
263
264
	$incontext['detected_languages'] = array();
265
266
	// Make sure the languages directory actually exists.
267
	if (file_exists(dirname(__FILE__) . '/Themes/default/languages'))
268
	{
269
		// Find all the "Install" language files in the directory.
270
		$dir = dir(dirname(__FILE__) . '/Themes/default/languages');
271
		while ($entry = $dir->read())
272
		{
273
			if (substr($entry, 0, 8) == 'Install.' && substr($entry, -4) == '.php')
274
				$incontext['detected_languages'][$entry] = ucfirst(substr($entry, 8, strlen($entry) - 12));
275
		}
276
		$dir->close();
277
	}
278
279
	// Didn't find any, show an error message!
280
	if (empty($incontext['detected_languages']))
281
	{
282
		// Let's not cache this message, eh?
283
		header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
284
		header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
285
		header('Cache-Control: no-cache');
286
287
		echo '<!DOCTYPE html>
288
<html>
289
	<head>
290
		<title>SMF Installer: Error!</title>
291
	</head>
292
	<body style="font-family: sans-serif;"><div style="width: 600px;">
293
		<h1 style="font-size: 14pt;">A critical error has occurred.</h1>
294
295
		<p>This installer was unable to find the installer\'s language file or files.  They should be found under:</p>
296
297
		<div style="margin: 1ex; font-family: monospace; font-weight: bold;">', dirname($_SERVER['PHP_SELF']) != '/' ? dirname($_SERVER['PHP_SELF']) : '', '/Themes/default/languages</div>
0 ignored issues
show
Security Cross-Site Scripting introduced by
dirname($_SERVER['PHP_SE...ERVER['PHP_SELF']) : '' can contain request data and is used in output context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Fetching key PHP_SELF from $_SERVER, and $_SERVER['PHP_SELF'] is passed through dirname()
    in other/install.php on line 297

Preventing Cross-Site-Scripting Attacks

Cross-Site-Scripting allows an attacker to inject malicious code into your website - in particular Javascript code, and have that code executed with the privileges of a visiting user. This can be used to obtain data, or perform actions on behalf of that visiting user.

In order to prevent this, make sure to escape all user-provided data:

// for HTML
$sanitized = htmlentities($tainted, ENT_QUOTES);

// for URLs
$sanitized = urlencode($tainted);

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
298
299
		<p>In some cases, FTP clients do not properly upload files with this many folders.  Please double check to make sure you <span style="font-weight: 600;">have uploaded all the files in the distribution</span>.</p>
300
		<p>If that doesn\'t help, please make sure this install.php file is in the same place as the Themes folder.</p>
301
302
		<p>If you continue to get this error message, feel free to <a href="https://support.simplemachines.org/">look to us for support</a>.</p>
303
	</div></body>
304
</html>';
305
		die;
306
	}
307
308
	// Override the language file?
309
	if (isset($_GET['lang_file']))
310
		$_SESSION['installer_temp_lang'] = $_GET['lang_file'];
311
	elseif (isset($GLOBALS['HTTP_GET_VARS']['lang_file']))
312
		$_SESSION['installer_temp_lang'] = $GLOBALS['HTTP_GET_VARS']['lang_file'];
313
314
	// Make sure it exists, if it doesn't reset it.
315
	if (!isset($_SESSION['installer_temp_lang']) || preg_match('~[^\\w_\\-.]~', $_SESSION['installer_temp_lang']) === 1 || !file_exists(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']))
316
	{
317
		// Use the first one...
318
		list ($_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
319
320
		// If we have english and some other language, use the other language.  We Americans hate english :P.
321
		if ($_SESSION['installer_temp_lang'] == 'Install.english.php' && count($incontext['detected_languages']) > 1)
322
			list (, $_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
323
	}
324
325
	// And now include the actual language file itself.
326
	require_once(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']);
327
}
328
329
// This handy function loads some settings and the like.
330
function load_database()
331
{
332
	global $db_prefix, $db_connection, $sourcedir, $smcFunc, $modSettings;
333
	global $db_server, $db_passwd, $db_type, $db_name, $db_user, $db_persist;
334
335
	if (empty($sourcedir))
336
		$sourcedir = dirname(__FILE__) . '/Sources';
337
338
	// Need this to check whether we need the database password.
339
	require(dirname(__FILE__) . '/Settings.php');
340
	if (!defined('SMF'))
341
		define('SMF', 1);
342
	if (empty($smcFunc))
343
		$smcFunc = array();
344
345
	$modSettings['disableQueryCheck'] = true;
346
347
	// Connect the database.
348
	if (!$db_connection)
349
	{
350
		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
351
		if (version_compare(PHP_VERSION, '5', '<'))
352
			require_once($sourcedir . '/Subs-Compat.php');
353
354
		$db_options = array('persist' => $db_persist);
355
		$port = '';
356
357
		// Figure out the port...
358
		if (!empty($_POST['db_port']))
359
		{
360
			if ($db_type == 'mysql')
361
			{
362
				$port = ((int) $_POST['db_port'] == ini_get($db_type . 'default_port')) ? '' : (int) $_POST['db_port'];
363
			}
364 View Code Duplication
			elseif ($db_type == 'postgresql')
365
			{
366
				// PostgreSQL doesn't have a default port setting in php.ini, so just check against the default
367
				$port = ((int) $_POST['db_port'] == 5432) ? '' : (int) $_POST['db_port'];
368
			}
369
		}
370
371
		if (!empty($port))
372
			$db_options['port'] = $port;
373
374
		if (!$db_connection)
375
			$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options);
376
	}
377
}
378
379
// This is called upon exiting the installer, for template etc.
380
function installExit($fallThrough = false)
381
{
382
	global $incontext, $installurl, $txt;
383
384
	// Send character set.
385
	header('Content-Type: text/html; charset=' . (isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8'));
386
387
	// We usually dump our templates out.
388
	if (!$fallThrough)
389
	{
390
		// The top install bit.
391
		template_install_above();
392
393
		// Call the template.
394
		if (isset($incontext['sub_template']))
395
		{
396
			$incontext['form_url'] = $installurl . '?step=' . $incontext['current_step'];
397
398
			call_user_func('template_' . $incontext['sub_template']);
399
		}
400
		// @todo REMOVE THIS!!
401
		else
402
		{
403
			if (function_exists('doStep' . $_GET['step']))
404
				call_user_func('doStep' . $_GET['step']);
0 ignored issues
show
Security Code Execution introduced by
'doStep' . $_GET['step'] can contain request data and is used in code execution context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_GET
    in other/install.php on line 404

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
405
		}
406
		// Show the footer.
407
		template_install_below();
408
	}
409
410
	// Bang - gone!
411
	die();
412
}
413
414
function Welcome()
415
{
416
	global $incontext, $txt, $databases, $installurl;
417
418
	$incontext['page_title'] = $txt['install_welcome'];
419
	$incontext['sub_template'] = 'welcome_message';
420
421
	// Done the submission?
422
	if (isset($_POST['contbutt']))
423
		return true;
424
425
	// See if we think they have already installed it?
426
	if (is_readable(dirname(__FILE__) . '/Settings.php'))
427
	{
428
		$probably_installed = 0;
429
		foreach (file(dirname(__FILE__) . '/Settings.php') as $line)
430
		{
431
			if (preg_match('~^\$db_passwd\s=\s\'([^\']+)\';$~', $line))
432
				$probably_installed++;
433
			if (preg_match('~^\$boardurl\s=\s\'([^\']+)\';~', $line) && !preg_match('~^\$boardurl\s=\s\'http://127\.0\.0\.1/smf\';~', $line))
434
				$probably_installed++;
435
		}
436
437
		if ($probably_installed == 2)
438
			$incontext['warning'] = $txt['error_already_installed'];
439
	}
440
441
	// Is some database support even compiled in?
442
	$incontext['supported_databases'] = array();
443
	foreach ($databases as $key => $db)
444
	{
445
		if ($db['supported'])
446
		{
447
			$type = ($key == 'mysqli') ? 'mysql' : $key;
448
			if (!file_exists(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql'))
449
			{
450
				$databases[$key]['supported'] = false;
451
				$notFoundSQLFile = true;
452
				$txt['error_db_script_missing'] = sprintf($txt['error_db_script_missing'], 'install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
453
			}
454
			else
455
				$incontext['supported_databases'][] = $db;
456
		}
457
	}
458
459
	// Check the PHP version.
460
	if ((!function_exists('version_compare') || version_compare($GLOBALS['required_php_version'], PHP_VERSION, '>')))
461
		$error = 'error_php_too_low';
462
	// Make sure we have a supported database
463
	elseif (empty($incontext['supported_databases']))
464
		$error = empty($notFoundSQLFile) ? 'error_db_missing' : 'error_db_script_missing';
465
	// How about session support?  Some crazy sysadmin remove it?
466
	elseif (!function_exists('session_start'))
467
		$error = 'error_session_missing';
468
	// Make sure they uploaded all the files.
469
	elseif (!file_exists(dirname(__FILE__) . '/index.php'))
470
		$error = 'error_missing_files';
471
	// Very simple check on the session.save_path for Windows.
472
	// @todo Move this down later if they don't use database-driven sessions?
473
	elseif (@ini_get('session.save_path') == '/tmp' && substr(__FILE__, 1, 2) == ':\\')
474
		$error = 'error_session_save_path';
475
476
	// Since each of the three messages would look the same, anyway...
477
	if (isset($error))
478
		$incontext['error'] = $txt[$error];
479
480
	// Mod_security blocks everything that smells funny. Let SMF handle security.
481
	if (!fixModSecurity() && !isset($_GET['overmodsecurity']))
482
		$incontext['error'] = $txt['error_mod_security'] . '<br><br><a href="' . $installurl . '?overmodsecurity=true">' . $txt['error_message_click'] . '</a> ' . $txt['error_message_bad_try_again'];
483
484
	return false;
485
}
486
487
function CheckFilesWritable()
488
{
489
	global $txt, $incontext;
490
491
	$incontext['page_title'] = $txt['ftp_checking_writable'];
492
	$incontext['sub_template'] = 'chmod_files';
493
494
	$writable_files = array(
495
		'attachments',
496
		'avatars',
497
		'custom_avatar',
498
		'cache',
499
		'Packages',
500
		'Smileys',
501
		'Themes',
502
		'agreement.txt',
503
		'Settings.php',
504
		'Settings_bak.php',
505
		'db_last_error.php',
506
	);
507
508
	foreach ($incontext['detected_languages'] as $lang => $temp)
509
		$extra_files[] = 'Themes/default/languages/' . $lang;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$extra_files was never initialized. Although not strictly required by PHP, it is generally a good practice to add $extra_files = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
510
511
	// With mod_security installed, we could attempt to fix it with .htaccess.
512
	if (function_exists('apache_get_modules') && in_array('mod_security', apache_get_modules()))
513
		$writable_files[] = file_exists(dirname(__FILE__) . '/.htaccess') ? '.htaccess' : '.';
514
515
	$failed_files = array();
516
517
	// On linux, it's easy - just use is_writable!
518
	if (substr(__FILE__, 1, 2) != ':\\')
519
	{
520
		$incontext['systemos'] = 'linux';
521
522
		foreach ($writable_files as $file)
523
		{
524
			if (!is_writable(dirname(__FILE__) . '/' . $file))
525
			{
526
				@chmod(dirname(__FILE__) . '/' . $file, 0755);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
527
528
				// Well, 755 hopefully worked... if not, try 777.
529
				if (!is_writable(dirname(__FILE__) . '/' . $file) && !@chmod(dirname(__FILE__) . '/' . $file, 0777))
530
					$failed_files[] = $file;
531
			}
532
		}
533 View Code Duplication
		foreach ($extra_files as $file)
0 ignored issues
show
Bug introduced by
The variable $extra_files does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
534
			@chmod(dirname(__FILE__) . (empty($file) ? '' : '/' . $file), 0777);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
535
	}
536
	// Windows is trickier.  Let's try opening for r+...
537
	else
538
	{
539
		$incontext['systemos'] = 'windows';
540
541
		foreach ($writable_files as $file)
542
		{
543
			// Folders can't be opened for write... but the index.php in them can ;)
544
			if (is_dir(dirname(__FILE__) . '/' . $file))
545
				$file .= '/index.php';
546
547
			// Funny enough, chmod actually does do something on windows - it removes the read only attribute.
548
			@chmod(dirname(__FILE__) . '/' . $file, 0777);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
549
			$fp = @fopen(dirname(__FILE__) . '/' . $file, 'r+');
550
551
			// Hmm, okay, try just for write in that case...
552
			if (!is_resource($fp))
553
				$fp = @fopen(dirname(__FILE__) . '/' . $file, 'w');
554
555
			if (!is_resource($fp))
556
				$failed_files[] = $file;
557
558
			@fclose($fp);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
559
		}
560 View Code Duplication
		foreach ($extra_files as $file)
561
			@chmod(dirname(__FILE__) . (empty($file) ? '' : '/' . $file), 0777);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
562
	}
563
564
	$failure = count($failed_files) >= 1;
565
566
	if (!isset($_SERVER))
567
		return !$failure;
568
569
	// Put the list into context.
570
	$incontext['failed_files'] = $failed_files;
571
572
	// It's not going to be possible to use FTP on windows to solve the problem...
573
	if ($failure && substr(__FILE__, 1, 2) == ':\\')
574
	{
575
		$incontext['error'] = $txt['error_windows_chmod'] . '
576
					<ul style="margin: 2.5ex; font-family: monospace;">
577
						<li>' . implode('</li>
578
						<li>', $failed_files) . '</li>
579
					</ul>';
580
581
		return false;
582
	}
583
	// We're going to have to use... FTP!
584
	elseif ($failure)
585
	{
586
		// Load any session data we might have...
587
		if (!isset($_POST['ftp_username']) && isset($_SESSION['installer_temp_ftp']))
588
		{
589
			$_POST['ftp_server'] = $_SESSION['installer_temp_ftp']['server'];
590
			$_POST['ftp_port'] = $_SESSION['installer_temp_ftp']['port'];
591
			$_POST['ftp_username'] = $_SESSION['installer_temp_ftp']['username'];
592
			$_POST['ftp_password'] = $_SESSION['installer_temp_ftp']['password'];
593
			$_POST['ftp_path'] = $_SESSION['installer_temp_ftp']['path'];
594
		}
595
596
		$incontext['ftp_errors'] = array();
597
		require_once('Sources/Class-Package.php');
598 View Code Duplication
		if (isset($_POST['ftp_username']))
599
		{
600
			$ftp = new ftp_connection($_POST['ftp_server'], $_POST['ftp_port'], $_POST['ftp_username'], $_POST['ftp_password']);
601
602
			if ($ftp->error === false)
603
			{
604
				// Try it without /home/abc just in case they messed up.
605
				if (!$ftp->chdir($_POST['ftp_path']))
606
				{
607
					$incontext['ftp_errors'][] = $ftp->last_message;
608
					$ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $_POST['ftp_path']));
609
				}
610
			}
611
		}
612
613
		if (!isset($ftp) || $ftp->error !== false)
614
		{
615
			if (!isset($ftp))
616
				$ftp = new ftp_connection(null);
617
			// Save the error so we can mess with listing...
618
			elseif ($ftp->error !== false && empty($incontext['ftp_errors']) && !empty($ftp->last_message))
619
				$incontext['ftp_errors'][] = $ftp->last_message;
620
621
			list ($username, $detect_path, $found_path) = $ftp->detect_path(dirname(__FILE__));
622
623
			if (empty($_POST['ftp_path']) && $found_path)
624
				$_POST['ftp_path'] = $detect_path;
625
626
			if (!isset($_POST['ftp_username']))
627
				$_POST['ftp_username'] = $username;
628
629
			// Set the username etc, into context.
630
			$incontext['ftp'] = array(
631
				'server' => isset($_POST['ftp_server']) ? $_POST['ftp_server'] : 'localhost',
632
				'port' => isset($_POST['ftp_port']) ? $_POST['ftp_port'] : '21',
633
				'username' => isset($_POST['ftp_username']) ? $_POST['ftp_username'] : '',
634
				'path' => isset($_POST['ftp_path']) ? $_POST['ftp_path'] : '/',
635
				'path_msg' => !empty($found_path) ? $txt['ftp_path_found_info'] : $txt['ftp_path_info'],
636
			);
637
638
			return false;
639
		}
640
		else
641
		{
642
			$_SESSION['installer_temp_ftp'] = array(
643
				'server' => $_POST['ftp_server'],
644
				'port' => $_POST['ftp_port'],
645
				'username' => $_POST['ftp_username'],
646
				'password' => $_POST['ftp_password'],
647
				'path' => $_POST['ftp_path']
648
			);
649
650
			$failed_files_updated = array();
651
652
			foreach ($failed_files as $file)
653
			{
654
				if (!is_writable(dirname(__FILE__) . '/' . $file))
655
					$ftp->chmod($file, 0755);
656
				if (!is_writable(dirname(__FILE__) . '/' . $file))
657
					$ftp->chmod($file, 0777);
658
				if (!is_writable(dirname(__FILE__) . '/' . $file))
659
				{
660
					$failed_files_updated[] = $file;
661
					$incontext['ftp_errors'][] = rtrim($ftp->last_message) . ' -> ' . $file . "\n";
662
				}
663
			}
664
665
			$ftp->close();
666
667
			// Are there any errors left?
668
			if (count($failed_files_updated) >= 1)
669
			{
670
				// Guess there are...
671
				$incontext['failed_files'] = $failed_files_updated;
672
673
				// Set the username etc, into context.
674
				$incontext['ftp'] = $_SESSION['installer_temp_ftp'] += array(
675
					'path_msg' => $txt['ftp_path_info'],
676
				);
677
678
				return false;
679
			}
680
		}
681
	}
682
683
	return true;
684
}
685
686
function DatabaseSettings()
687
{
688
	global $txt, $databases, $incontext, $smcFunc, $sourcedir;
689
	global $db_server, $db_name, $db_user, $db_passwd;
690
691
	$incontext['sub_template'] = 'database_settings';
692
	$incontext['page_title'] = $txt['db_settings'];
693
	$incontext['continue'] = 1;
694
695
	// Set up the defaults.
696
	$incontext['db']['server'] = 'localhost';
697
	$incontext['db']['user'] = '';
698
	$incontext['db']['name'] = '';
699
	$incontext['db']['pass'] = '';
700
	$incontext['db']['type'] = '';
701
	$incontext['supported_databases'] = array();
702
703
	$foundOne = false;
704
	foreach ($databases as $key => $db)
705
	{
706
		// Override with the defaults for this DB if appropriate.
707
		if ($db['supported'])
708
		{
709
			$incontext['supported_databases'][$key] = $db;
710
711
			if (!$foundOne)
712
			{
713
				if (isset($db['default_host']))
714
					$incontext['db']['server'] = ini_get($db['default_host']) or $incontext['db']['server'] = 'localhost';
715
				if (isset($db['default_user']))
716
				{
717
					$incontext['db']['user'] = ini_get($db['default_user']);
718
					$incontext['db']['name'] = ini_get($db['default_user']);
719
				}
720
				if (isset($db['default_password']))
721
					$incontext['db']['pass'] = ini_get($db['default_password']);
722
723
				// For simplicity and less confusion, leave the port blank by default
724
				$incontext['db']['port'] = '';
725
726
				$incontext['db']['type'] = $key;
727
				$foundOne = true;
728
			}
729
		}
730
	}
731
732
	// Override for repost.
733
	if (isset($_POST['db_user']))
734
	{
735
		$incontext['db']['user'] = $_POST['db_user'];
736
		$incontext['db']['name'] = $_POST['db_name'];
737
		$incontext['db']['server'] = $_POST['db_server'];
738
		$incontext['db']['prefix'] = $_POST['db_prefix'];
739
740
		if (!empty($_POST['db_port']))
741
			$incontext['db']['port'] = $_POST['db_port'];
742
	}
743
	else
744
	{
745
		$incontext['db']['prefix'] = 'smf_';
746
	}
747
748
	// Are we submitting?
749
	if (isset($_POST['db_type']))
750
	{
751
		// What type are they trying?
752
		$db_type = preg_replace('~[^A-Za-z0-9]~', '', $_POST['db_type']);
753
		$db_prefix = $_POST['db_prefix'];
754
		// Validate the prefix.
755
		$valid_prefix = $databases[$db_type]['validate_prefix']($db_prefix);
756
757
		if ($valid_prefix !== true)
758
		{
759
			$incontext['error'] = $valid_prefix;
760
			return false;
761
		}
762
763
		// Take care of these variables...
764
		$vars = array(
765
			'db_type' => $db_type,
766
			'db_name' => $_POST['db_name'],
767
			'db_user' => $_POST['db_user'],
768
			'db_passwd' => isset($_POST['db_passwd']) ? $_POST['db_passwd'] : '',
769
			'db_server' => $_POST['db_server'],
770
			'db_prefix' => $db_prefix,
771
			// The cookiename is special; we want it to be the same if it ever needs to be reinstalled with the same info.
772
			'cookiename' => 'SMFCookie' . abs(crc32($_POST['db_name'] . preg_replace('~[^A-Za-z0-9_$]~', '', $_POST['db_prefix'])) % 1000),
773
		);
774
775
		// Only set the port if we're not using the default
776
		if (!empty($_POST['db_port']))
777
		{
778
			// For MySQL, we can get the "default port" from PHP. PostgreSQL has no such option though.
779
			if (($db_type == 'mysql' || $db_type == 'mysqli') && $_POST['db_port'] != ini_get($db_type . '.default_port'))
780
				$vars['db_port'] = (int) $_POST['db_port'];
781 View Code Duplication
			elseif ($db_type == 'postgresql' && $_POST['db_port'] != 5432)
782
				$vars['db_port'] = (int) $_POST['db_port'];
783
		}
784
785
		// God I hope it saved!
786 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
787
		{
788
			$incontext['error'] = $txt['error_windows_chmod'];
789
			return false;
790
		}
791
792
		// Make sure it works.
793
		require(dirname(__FILE__) . '/Settings.php');
794
795
		if (empty($sourcedir))
796
			$sourcedir = dirname(__FILE__) . '/Sources';
797
798
		// Better find the database file!
799
		if (!file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php'))
800
		{
801
			$incontext['error'] = sprintf($txt['error_db_file'], 'Subs-Db-' . $db_type . '.php');
802
			return false;
803
		}
804
805
		// Now include it for database functions!
806
		if (!defined('SMF'))
807
			define('SMF', 1);
808
809
		$modSettings['disableQueryCheck'] = true;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$modSettings was never initialized. Although not strictly required by PHP, it is generally a good practice to add $modSettings = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
810
		if (empty($smcFunc))
811
			$smcFunc = array();
812
813
			require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
814
815
		// What - running PHP4? The shame!
816
		if (version_compare(PHP_VERSION, '5', '<'))
817
			require_once($sourcedir . '/Subs-Compat.php');
818
819
		// Attempt a connection.
820
		$needsDB = !empty($databases[$db_type]['always_has_db']);
821
		$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('non_fatal' => true, 'dont_select_db' => !$needsDB));
822
823
		// No dice?  Let's try adding the prefix they specified, just in case they misread the instructions ;)
824
		if ($db_connection == null)
825
		{
826
			$db_error = @$smcFunc['db_error']();
827
828
			$db_connection = smf_db_initiate($db_server, $db_name, $_POST['db_prefix'] . $db_user, $db_passwd, $db_prefix, array('non_fatal' => true, 'dont_select_db' => !$needsDB));
829
			if ($db_connection != null)
830
			{
831
				$db_user = $_POST['db_prefix'] . $db_user;
832
				updateSettingsFile(array('db_user' => $db_user));
833
			}
834
		}
835
836
		// Still no connection?  Big fat error message :P.
837
		if (!$db_connection)
838
		{
839
			$incontext['error'] = $txt['error_db_connect'] . '<div style="margin: 2.5ex; font-family: monospace;"><strong>' . $db_error . '</strong></div>';
0 ignored issues
show
Bug introduced by
The variable $db_error does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
840
			return false;
841
		}
842
843
		// Do they meet the install requirements?
844
		// @todo Old client, new server?
845
		if (version_compare($databases[$db_type]['version'], preg_replace('~^\D*|\-.+?$~', '', eval($databases[$db_type]['version_check']))) > 0)
0 ignored issues
show
Coding Style introduced by
The function DatabaseSettings() contains an eval expression.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
846
		{
847
			$incontext['error'] = $txt['error_db_too_low'];
848
			return false;
849
		}
850
851
		// Let's try that database on for size... assuming we haven't already lost the opportunity.
852
		if ($db_name != '' && !$needsDB)
853
		{
854
			$smcFunc['db_query']('', "
855
				CREATE DATABASE IF NOT EXISTS `$db_name`",
856
				array(
857
					'security_override' => true,
858
					'db_error_skip' => true,
859
				),
860
				$db_connection
861
			);
862
863
			// Okay, let's try the prefix if it didn't work...
864
			if (!$smcFunc['db_select_db']($db_name, $db_connection) && $db_name != '')
865
			{
866
				$smcFunc['db_query']('', "
867
					CREATE DATABASE IF NOT EXISTS `$_POST[db_prefix]$db_name`",
868
					array(
869
						'security_override' => true,
870
						'db_error_skip' => true,
871
					),
872
					$db_connection
873
				);
874
875
				if ($smcFunc['db_select_db']($_POST['db_prefix'] . $db_name, $db_connection))
876
				{
877
					$db_name = $_POST['db_prefix'] . $db_name;
878
					updateSettingsFile(array('db_name' => $db_name));
879
				}
880
			}
881
882
			// Okay, now let's try to connect...
883
			if (!$smcFunc['db_select_db']($db_name, $db_connection))
884
			{
885
				$incontext['error'] = sprintf($txt['error_db_database'], $db_name);
886
				return false;
887
			}
888
		}
889
890
		return true;
891
	}
892
893
	return false;
894
}
895
896
// Let's start with basic forum type settings.
897
function ForumSettings()
898
{
899
	global $txt, $incontext, $databases, $db_type;
900
901
	$incontext['sub_template'] = 'forum_settings';
902
	$incontext['page_title'] = $txt['install_settings'];
903
904
	// Let's see if we got the database type correct.
905
	if (isset($_POST['db_type'], $databases[$_POST['db_type']]))
906
		$db_type = $_POST['db_type'];
907
908
	// Else we'd better be able to get the connection.
909
	else
910
		load_database();
911
912
	$db_type = isset($_POST['db_type']) ? $_POST['db_type'] : $db_type;
913
914
	// What host and port are we on?
915
	$host = empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST'];
916
917
	// Now, to put what we've learned together... and add a path.
918
	$incontext['detected_url'] = 'http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . $host . substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
919
920
	// Check if the database sessions will even work.
921
	$incontext['test_dbsession'] = (ini_get('session.auto_start') != 1);
922
	$incontext['utf8_default'] = $databases[$db_type]['utf8_default'];
923
	$incontext['utf8_required'] = $databases[$db_type]['utf8_required'];
924
925
	$incontext['continue'] = 1;
926
927
	// Submitting?
928
	if (isset($_POST['boardurl']))
929
	{
930 View Code Duplication
		if (substr($_POST['boardurl'], -10) == '/index.php')
931
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -10);
932
		elseif (substr($_POST['boardurl'], -1) == '/')
933
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -1);
934 View Code Duplication
		if (substr($_POST['boardurl'], 0, 7) != 'http://' && substr($_POST['boardurl'], 0, 7) != 'file://' && substr($_POST['boardurl'], 0, 8) != 'https://')
935
			$_POST['boardurl'] = 'http://' . $_POST['boardurl'];
936
937
		// Save these variables.
938
		$vars = array(
939
			'boardurl' => $_POST['boardurl'],
940
			'boarddir' => addslashes(dirname(__FILE__)),
941
			'sourcedir' => addslashes(dirname(__FILE__)) . '/Sources',
942
			'cachedir' => addslashes(dirname(__FILE__)) . '/cache',
943
			'packagesdir' => addslashes(dirname(__FILE__)) . '/Packages',
944
			'tasksdir' => addslashes(dirname(__FILE__)) . '/Sources/tasks',
945
			'mbname' => strtr($_POST['mbname'], array('\"' => '"')),
946
			'language' => substr($_SESSION['installer_temp_lang'], 8, -4),
947
			'image_proxy_secret' => substr(sha1(mt_rand()), 0, 20),
948
			'image_proxy_enabled' => !empty($_POST['force_ssl']),
949
		);
950
951
		// Must save!
952 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
953
		{
954
			$incontext['error'] = $txt['error_windows_chmod'];
955
			return false;
956
		}
957
958
		// Make sure it works.
959
		require(dirname(__FILE__) . '/Settings.php');
960
961
		// UTF-8 requires a setting to override the language charset.
962
		if ((!empty($databases[$db_type]['utf8_support']) && !empty($databases[$db_type]['utf8_required'])) || (empty($databases[$db_type]['utf8_required']) && !empty($databases[$db_type]['utf8_support']) && isset($_POST['utf8'])))
963
		{
964
			if (!$databases[$db_type]['utf8_support']())
965
			{
966
				$incontext['error'] = sprintf($txt['error_utf8_support']);
967
				return false;
968
			}
969
970
			if (!empty($databases[$db_type]['utf8_version_check']) && version_compare($databases[$db_type]['utf8_version'], preg_replace('~\-.+?$~', '', eval($databases[$db_type]['utf8_version_check'])), '>'))
0 ignored issues
show
Coding Style introduced by
The function ForumSettings() contains an eval expression.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
971
			{
972
				$incontext['error'] = sprintf($txt['error_utf8_version'], $databases[$db_type]['utf8_version']);
973
				return false;
974
			}
975
			else
976
				// Set the character set here.
977
				updateSettingsFile(array('db_character_set' => 'utf8'));
978
		}
979
980
		// Good, skip on.
981
		return true;
982
	}
983
984
	return false;
985
}
986
987
// Step one: Do the SQL thang.
988
function DatabasePopulation()
989
{
990
	global $db_character_set, $txt, $db_connection, $smcFunc, $databases, $modSettings, $db_type, $db_prefix, $incontext, $db_name, $boardurl;
991
992
	$incontext['sub_template'] = 'populate_database';
993
	$incontext['page_title'] = $txt['db_populate'];
994
	$incontext['continue'] = 1;
995
996
	// Already done?
997
	if (isset($_POST['pop_done']))
998
		return true;
999
1000
	// Reload settings.
1001
	require(dirname(__FILE__) . '/Settings.php');
1002
	load_database();
1003
1004
	// Before running any of the queries, let's make sure another version isn't already installed.
1005
	$result = $smcFunc['db_query']('', '
1006
		SELECT variable, value
1007
		FROM {db_prefix}settings',
1008
		array(
1009
			'db_error_skip' => true,
1010
		)
1011
	);
1012
	$newSettings = array();
1013
	$modSettings = array();
1014
	if ($result !== false)
1015
	{
1016 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($result))
1017
			$modSettings[$row['variable']] = $row['value'];
1018
		$smcFunc['db_free_result']($result);
1019
1020
		// Do they match?  If so, this is just a refresh so charge on!
1021
		if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] != $GLOBALS['current_smf_version'])
1022
		{
1023
			$incontext['error'] = $txt['error_versions_do_not_match'];
1024
			return false;
1025
		}
1026
	}
1027
	$modSettings['disableQueryCheck'] = true;
1028
1029
	// If doing UTF8, select it. PostgreSQL requires passing it as a string...
1030 View Code Duplication
	if (!empty($db_character_set) && $db_character_set == 'utf8' && !empty($databases[$db_type]['utf8_support']))
1031
		$smcFunc['db_query']('', '
1032
			SET NAMES {string:utf8}',
1033
			array(
1034
				'db_error_skip' => true,
1035
				'utf8' => 'utf8',
1036
			)
1037
		);
1038
1039
	// Windows likes to leave the trailing slash, which yields to C:\path\to\SMF\/attachments...
1040
	if (substr(__DIR__, -1) == '\\')
1041
		$attachdir = __DIR__ . 'attachments';
1042
	else
1043
		$attachdir = __DIR__ . '/attachments';
1044
1045
	$replaces = array(
1046
		'{$db_prefix}' => $db_prefix,
1047
		'{$attachdir}' => json_encode(array(1 => $smcFunc['db_escape_string']($attachdir))),
1048
		'{$boarddir}' => $smcFunc['db_escape_string'](dirname(__FILE__)),
1049
		'{$boardurl}' => $boardurl,
1050
		'{$enableCompressedOutput}' => isset($_POST['compress']) ? '1' : '0',
1051
		'{$databaseSession_enable}' => isset($_POST['dbsession']) ? '1' : '0',
1052
		'{$smf_version}' => $GLOBALS['current_smf_version'],
1053
		'{$current_time}' => time(),
1054
		'{$sched_task_offset}' => 82800 + mt_rand(0, 86399),
1055
		'{$registration_method}' => isset($_POST['reg_mode']) ? $_POST['reg_mode'] : 0,
1056
	);
1057
1058
	foreach ($txt as $key => $value)
1059
	{
1060
		if (substr($key, 0, 8) == 'default_')
1061
			$replaces['{$' . $key . '}'] = $smcFunc['db_escape_string']($value);
1062
	}
1063
	$replaces['{$default_reserved_names}'] = strtr($replaces['{$default_reserved_names}'], array('\\\\n' => '\\n'));
1064
1065
	// MySQL-specific stuff - storage engine and UTF8 handling
1066
	if (substr($db_type, 0, 5) == 'mysql')
1067
	{
1068
		// Just in case the query fails for some reason...
1069
		$engines = array();
1070
1071
		// Figure out storage engines - what do we have, etc.
1072
		$get_engines = $smcFunc['db_query']('', 'SHOW ENGINES', array());
1073
1074 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($get_engines))
1075
		{
1076
			if ($row['Support'] == 'YES' || $row['Support'] == 'DEFAULT')
1077
				$engines[] = $row['Engine'];
1078
		}
1079
1080
		// Done with this now
1081
		$smcFunc['db_free_result']($get_engines);
1082
1083
		// InnoDB is better, so use it if possible...
1084
		$has_innodb = in_array('InnoDB', $engines);
1085
		$replaces['{$engine}'] = $has_innodb ? 'InnoDB' : 'MyISAM';
1086
		$replaces['{$memory}'] = (!$has_innodb && in_array('MEMORY', $engines)) ? 'MEMORY' : $replaces['{$engine}'];
1087
1088
		// If the UTF-8 setting was enabled, add it to the table definitions.
1089
		if (!empty($databases[$db_type]['utf8_support']) && (!empty($databases[$db_type]['utf8_required']) || isset($_POST['utf8'])))
1090
		{
1091
			$replaces['{$engine}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1092
			$replaces['{$memory}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1093
		}
1094
1095
		// One last thing - if we don't have InnoDB, we can't do transactions...
1096
		if (!$has_innodb)
1097
		{
1098
			$replaces['START TRANSACTION;'] = '';
1099
			$replaces['COMMIT;'] = '';
1100
		}
1101
	}
1102
	else
1103
	{
1104
		$has_innodb = false;
1105
	}
1106
1107
	// Read in the SQL.  Turn this on and that off... internationalize... etc.
1108
	$type = ($db_type == 'mysqli' ? 'mysql' : $db_type);
1109
	$sql_lines = explode("\n", strtr(implode(' ', file(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql')), $replaces));
1110
1111
	// Execute the SQL.
1112
	$current_statement = '';
1113
	$exists = array();
1114
	$incontext['failures'] = array();
1115
	$incontext['sql_results'] = array(
1116
		'tables' => 0,
1117
		'inserts' => 0,
1118
		'table_dups' => 0,
1119
		'insert_dups' => 0,
1120
	);
1121
	foreach ($sql_lines as $count => $line)
1122
	{
1123
		// No comments allowed!
1124
		if (substr(trim($line), 0, 1) != '#')
1125
			$current_statement .= "\n" . rtrim($line);
1126
1127
		// Is this the end of the query string?
1128
		if (empty($current_statement) || (preg_match('~;[\s]*$~s', $line) == 0 && $count != count($sql_lines)))
1129
			continue;
1130
1131
		// Does this table already exist?  If so, don't insert more data into it!
1132
		if (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) != 0 && in_array($match[1], $exists))
1133
		{
1134
			preg_match_all('~\)[,;]~', $current_statement, $matches);
1135 View Code Duplication
			if (!empty($matches[0]))
1136
				$incontext['sql_results']['insert_dups'] += count($matches[0]);
1137
			else
1138
				$incontext['sql_results']['insert_dups']++;
1139
1140
			$current_statement = '';
1141
			continue;
1142
		}
1143
1144
		if ($smcFunc['db_query']('', $current_statement, array('security_override' => true, 'db_error_skip' => true), $db_connection) === false)
1145
		{
1146
			// Use the appropriate function based on the DB type
1147
			if ($db_type == 'mysql' || $db_type == 'mysqli')
1148
				$db_errorno = $db_type . '_errno';
1149
1150
			// Error 1050: Table already exists!
1151
			// @todo Needs to be made better!
1152
			if ((($db_type != 'mysql' && $db_type != 'mysqli') || $db_errorno($db_connection) == 1050) && preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
0 ignored issues
show
Bug introduced by
The variable $db_errorno does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1153
			{
1154
				$exists[] = $match[1];
1155
				$incontext['sql_results']['table_dups']++;
1156
			}
1157
			// Don't error on duplicate indexes (or duplicate operators in PostgreSQL.)
1158
			elseif (!preg_match('~^\s*CREATE( UNIQUE)? INDEX ([^\n\r]+?)~', $current_statement, $match) && !($db_type == 'postgresql' && preg_match('~^\s*CREATE OPERATOR (^\n\r]+?)~', $current_statement, $match)))
1159
			{
1160
				// MySQLi requires a connection object. It's optional with MySQL and Postgres
1161
				$incontext['failures'][$count] = $smcFunc['db_error']($db_connection);
1162
			}
1163
		}
1164
		else
1165
		{
1166
			if (preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1167
				$incontext['sql_results']['tables']++;
1168
			elseif (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1169
			{
1170
				preg_match_all('~\)[,;]~', $current_statement, $matches);
1171 View Code Duplication
				if (!empty($matches[0]))
1172
					$incontext['sql_results']['inserts'] += count($matches[0]);
1173
				else
1174
					$incontext['sql_results']['inserts']++;
1175
			}
1176
		}
1177
1178
		$current_statement = '';
1179
1180
		// Wait, wait, I'm still working here!
1181
		set_time_limit(60);
1182
	}
1183
1184
	// Sort out the context for the SQL.
1185
	foreach ($incontext['sql_results'] as $key => $number)
1186
	{
1187
		if ($number == 0)
1188
			unset($incontext['sql_results'][$key]);
1189
		else
1190
			$incontext['sql_results'][$key] = sprintf($txt['db_populate_' . $key], $number);
1191
	}
1192
1193
	// Make sure UTF will be used globally.
1194
	if ((!empty($databases[$db_type]['utf8_support']) && !empty($databases[$db_type]['utf8_required'])) || (empty($databases[$db_type]['utf8_required']) && !empty($databases[$db_type]['utf8_support']) && isset($_POST['utf8'])))
1195
		$newSettings[] = array('global_character_set', 'UTF-8');
1196
1197
	// Maybe we can auto-detect better cookie settings?
1198
	preg_match('~^http[s]?://([^\.]+?)([^/]*?)(/.*)?$~', $boardurl, $matches);
1199
	if (!empty($matches))
1200
	{
1201
		// Default = both off.
1202
		$localCookies = false;
1203
		$globalCookies = false;
1204
1205
		// Okay... let's see.  Using a subdomain other than www.? (not a perfect check.)
1206
		if ($matches[2] != '' && (strpos(substr($matches[2], 1), '.') === false || in_array($matches[1], array('forum', 'board', 'community', 'forums', 'support', 'chat', 'help', 'talk', 'boards', 'www'))))
1207
			$globalCookies = true;
1208
		// If there's a / in the middle of the path, or it starts with ~... we want local.
1209
		if (isset($matches[3]) && strlen($matches[3]) > 3 && (substr($matches[3], 0, 2) == '/~' || strpos(substr($matches[3], 1), '/') !== false))
1210
			$localCookies = true;
1211
1212
		if ($globalCookies)
1213
			$newSettings[] = array('globalCookies', '1');
1214
		if ($localCookies)
1215
			$newSettings[] = array('localCookies', '1');
1216
	}
1217
1218
	// Are we allowing stat collection?
1219 View Code Duplication
	if (!empty($_POST['stats']) && substr($boardurl, 0, 16) != 'http://localhost' && empty($modSettings['allow_sm_stats']) && empty($modSettings['enable_sm_stats']))
1220
	{
1221
		$upcontext['allow_sm_stats'] = true;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$upcontext was never initialized. Although not strictly required by PHP, it is generally a good practice to add $upcontext = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1222
1223
		// Don't register if we still have a key.
1224
		if (empty($modSettings['sm_stats_key']))
1225
		{
1226
			// Attempt to register the site etc.
1227
			$fp = @fsockopen('www.simplemachines.org', 80, $errno, $errstr);
1228
			if ($fp)
1229
			{
1230
				$out = 'GET /smf/stats/register_stats.php?site=' . base64_encode($boardurl) . ' HTTP/1.1' . "\r\n";
1231
				$out .= 'Host: www.simplemachines.org' . "\r\n";
1232
				$out .= 'Connection: Close' . "\r\n\r\n";
1233
				fwrite($fp, $out);
1234
1235
				$return_data = '';
1236
				while (!feof($fp))
1237
					$return_data .= fgets($fp, 128);
1238
1239
				fclose($fp);
1240
1241
				// Get the unique site ID.
1242
				preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1243
1244
				if (!empty($ID[1]))
1245
					$smcFunc['db_insert']('replace',
1246
						$db_prefix . 'settings',
1247
						array('variable' => 'string', 'value' => 'string'),
1248
						array(
1249
							array('sm_stats_key', $ID[1]),
1250
							array('enable_sm_stats', 1),
1251
						),
1252
						array('variable')
1253
					);
1254
			}
1255
		}
1256
		else
1257
		{
1258
			$smcFunc['db_insert']('replace',
1259
				$db_prefix . 'settings',
1260
				array('variable' => 'string', 'value' => 'string'),
1261
				array('enable_sm_stats', 1),
1262
				array('variable')
1263
			);
1264
		}
1265
	}
1266
	// Don't remove stat collection unless we unchecked the box for real, not from the loop.
1267
	elseif (empty($_POST['stats']) && empty($upcontext['allow_sm_stats']))
0 ignored issues
show
Bug introduced by
The variable $upcontext seems only to be defined at a later point. As such the call to empty() seems to always evaluate to true.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
1268
		$smcFunc['db_query']('', '
1269
			DELETE FROM {db_prefix}settings
1270
			WHERE variable = {string:enable_sm_stats}',
1271
			array(
1272
				'enable_sm_stats' => 'enable_sm_stats',
1273
				'db_error_skip' => true,
1274
			)
1275
		);
1276
1277
	// Are we enabling SSL?
1278
	if (!empty($_POST['force_ssl']))
1279
		$newSettings[] = array('force_ssl', 2);
1280
1281
	// Setting a timezone is required.
1282
	if (!isset($modSettings['default_timezone']) && function_exists('date_default_timezone_set'))
1283
	{
1284
		// Get PHP's default timezone, if set
1285
		$ini_tz = ini_get('date.timezone');
1286
		if (!empty($ini_tz))
1287
			$timezone_id = $ini_tz;
1288
		else
1289
			$timezone_id = '';
1290
1291
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
1292 View Code Duplication
		if (!in_array($timezone_id, timezone_identifiers_list()))
1293
		{
1294
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
1295
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
1296
		}
1297
1298
		if (date_default_timezone_set($timezone_id))
1299
			$newSettings[] = array('default_timezone', $timezone_id);
1300
	}
1301
1302
	if (!empty($newSettings))
1303
	{
1304
		$smcFunc['db_insert']('replace',
1305
			'{db_prefix}settings',
1306
			array('variable' => 'string-255', 'value' => 'string-65534'),
1307
			$newSettings,
1308
			array('variable')
1309
		);
1310
	}
1311
1312
	// Let's optimize those new tables, but not on InnoDB, ok?
1313
	if (!$has_innodb)
1314
	{
1315
		db_extend();
1316
		$tables = $smcFunc['db_list_tables']($db_name, $db_prefix . '%');
1317
		foreach ($tables as $table)
1318
		{
1319
			$smcFunc['db_optimize_table']($table) != -1 or $db_messed = true;
1320
1321
			if (!empty($db_messed))
1322
			{
1323
				$incontext['failures'][-1] = $smcFunc['db_error']();
1324
				break;
1325
			}
1326
		}
1327
	}
1328
1329
	// MySQL specific stuff
1330
	if (substr($db_type, 0, 5) != 'mysql')
1331
		return false;
1332
1333
	// Find database user privileges.
1334
	$privs = array();
1335
	$get_privs = $smcFunc['db_query']('', 'SHOW PRIVILEGES', array());
1336
	while ($row = $smcFunc['db_fetch_assoc']($get_privs))
1337
	{
1338
		if ($row['Privilege'] == 'Alter')
1339
			$privs[] = $row['Privilege'];
1340
	}
1341
	$smcFunc['db_free_result']($get_privs);
1342
1343
	// Check for the ALTER privilege.
1344
	if (!empty($databases[$db_type]['alter_support']) && !in_array('Alter', $privs))
1345
	{
1346
		$incontext['error'] = $txt['error_db_alter_priv'];
1347
		return false;
1348
	}
1349
1350
	if (!empty($exists))
1351
	{
1352
		$incontext['page_title'] = $txt['user_refresh_install'];
1353
		$incontext['was_refresh'] = true;
1354
	}
1355
1356
	return false;
1357
}
1358
1359
// Ask for the administrator login information.
1360
function AdminAccount()
1361
{
1362
	global $txt, $db_type, $smcFunc, $incontext, $db_prefix, $db_passwd, $sourcedir, $db_character_set;
1363
1364
	$incontext['sub_template'] = 'admin_account';
1365
	$incontext['page_title'] = $txt['user_settings'];
1366
	$incontext['continue'] = 1;
1367
1368
	// Skipping?
1369
	if (!empty($_POST['skip']))
1370
		return true;
1371
1372
	// Need this to check whether we need the database password.
1373
	require(dirname(__FILE__) . '/Settings.php');
1374
	load_database();
1375
1376
	require_once($sourcedir . '/Subs-Auth.php');
1377
1378
	require_once($sourcedir . '/Subs.php');
1379
1380
	// We need this to properly hash the password for Admin
1381 View Code Duplication
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' : function($string) {
1382
			global $sourcedir;
1383
			if (function_exists('mb_strtolower'))
1384
				return mb_strtolower($string, 'UTF-8');
1385
			require_once($sourcedir . '/Subs-Charset.php');
1386
			return utf8_strtolower($string);
1387
		};
1388
1389
	if (!isset($_POST['username']))
1390
		$_POST['username'] = '';
1391
	if (!isset($_POST['email']))
1392
		$_POST['email'] = '';
1393
	if (!isset($_POST['server_email']))
1394
		$_POST['server_email'] = '';
1395
1396
	$incontext['username'] = htmlspecialchars(stripslashes($_POST['username']));
1397
	$incontext['email'] = htmlspecialchars(stripslashes($_POST['email']));
1398
	$incontext['server_email'] = htmlspecialchars(stripslashes($_POST['server_email']));
1399
1400
	$incontext['require_db_confirm'] = empty($db_type);
1401
1402
	// Only allow skipping if we think they already have an account setup.
1403
	$request = $smcFunc['db_query']('', '
1404
		SELECT id_member
1405
		FROM {db_prefix}members
1406
		WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
1407
		LIMIT 1',
1408
		array(
1409
			'db_error_skip' => true,
1410
			'admin_group' => 1,
1411
		)
1412
	);
1413
	if ($smcFunc['db_num_rows']($request) != 0)
1414
		$incontext['skip'] = 1;
1415
	$smcFunc['db_free_result']($request);
1416
1417
	// Trying to create an account?
1418
	if (isset($_POST['password1']) && !empty($_POST['contbutt']))
1419
	{
1420
		// Wrong password?
1421
		if ($incontext['require_db_confirm'] && $_POST['password3'] != $db_passwd)
1422
		{
1423
			$incontext['error'] = $txt['error_db_connect'];
1424
			return false;
1425
		}
1426
		// Not matching passwords?
1427
		if ($_POST['password1'] != $_POST['password2'])
1428
		{
1429
			$incontext['error'] = $txt['error_user_settings_again_match'];
1430
			return false;
1431
		}
1432
		// No password?
1433
		if (strlen($_POST['password1']) < 4)
1434
		{
1435
			$incontext['error'] = $txt['error_user_settings_no_password'];
1436
			return false;
1437
		}
1438
		if (!file_exists($sourcedir . '/Subs.php'))
1439
		{
1440
			$incontext['error'] = $txt['error_subs_missing'];
1441
			return false;
1442
		}
1443
1444
		// Update the webmaster's email?
1445
		if (!empty($_POST['server_email']) && (empty($webmaster_email) || $webmaster_email == '[email protected]'))
0 ignored issues
show
Bug introduced by
The variable $webmaster_email seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
Bug introduced by
The variable $webmaster_email does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1446
			updateSettingsFile(array('webmaster_email' => $_POST['server_email']));
1447
1448
		// Work out whether we're going to have dodgy characters and remove them.
1449
		$invalid_characters = preg_match('~[<>&"\'=\\\]~', $_POST['username']) != 0;
1450
		$_POST['username'] = preg_replace('~[<>&"\'=\\\]~', '', $_POST['username']);
1451
1452
		$result = $smcFunc['db_query']('', '
1453
			SELECT id_member, password_salt
1454
			FROM {db_prefix}members
1455
			WHERE member_name = {string:username} OR email_address = {string:email}
1456
			LIMIT 1',
1457
			array(
1458
				'username' => stripslashes($_POST['username']),
1459
				'email' => stripslashes($_POST['email']),
1460
				'db_error_skip' => true,
1461
			)
1462
		);
1463
		if ($smcFunc['db_num_rows']($result) != 0)
1464
		{
1465
			list ($incontext['member_id'], $incontext['member_salt']) = $smcFunc['db_fetch_row']($result);
1466
			$smcFunc['db_free_result']($result);
1467
1468
			$incontext['account_existed'] = $txt['error_user_settings_taken'];
1469
		}
1470
		elseif ($_POST['username'] == '' || strlen($_POST['username']) > 25)
1471
		{
1472
			// Try the previous step again.
1473
			$incontext['error'] = $_POST['username'] == '' ? $txt['error_username_left_empty'] : $txt['error_username_too_long'];
1474
			return false;
1475
		}
1476
		elseif ($invalid_characters || $_POST['username'] == '_' || $_POST['username'] == '|' || strpos($_POST['username'], '[code') !== false || strpos($_POST['username'], '[/code') !== false)
1477
		{
1478
			// Try the previous step again.
1479
			$incontext['error'] = $txt['error_invalid_characters_username'];
1480
			return false;
1481
		}
1482 View Code Duplication
		elseif (empty($_POST['email']) || !filter_var(stripslashes($_POST['email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['email'])) > 255)
1483
		{
1484
			// One step back, this time fill out a proper admin email address.
1485
			$incontext['error'] = sprintf($txt['error_valid_admin_email_needed'], $_POST['username']);
1486
			return false;
1487
		}
1488 View Code Duplication
		elseif (empty($_POST['server_email']) || !filter_var(stripslashes($_POST['server_email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['server_email'])) > 255)
1489
		{
1490
			// One step back, this time fill out a proper admin email address.
1491
			$incontext['error'] = $txt['error_valid_server_email_needed'];
1492
			return false;
1493
		}
1494
		elseif ($_POST['username'] != '')
1495
		{
1496
			$incontext['member_salt'] = substr(md5(mt_rand()), 0, 4);
1497
1498
			// Format the username properly.
1499
			$_POST['username'] = preg_replace('~[\t\n\r\x0B\0\xA0]+~', ' ', $_POST['username']);
1500
			$ip = isset($_SERVER['REMOTE_ADDR']) ? substr($_SERVER['REMOTE_ADDR'], 0, 255) : '';
1501
1502
			$_POST['password1'] = hash_password(stripslashes($_POST['username']), stripslashes($_POST['password1']));
1503
1504
			$incontext['member_id'] = $smcFunc['db_insert']('',
1505
				$db_prefix . 'members',
1506
				array(
1507
					'member_name' => 'string-25', 'real_name' => 'string-25', 'passwd' => 'string', 'email_address' => 'string',
1508
					'id_group' => 'int', 'posts' => 'int', 'date_registered' => 'int',
1509
					'password_salt' => 'string', 'lngfile' => 'string', 'personal_text' => 'string', 'avatar' => 'string',
1510
					'member_ip' => 'inet', 'member_ip2' => 'inet', 'buddy_list' => 'string', 'pm_ignore_list' => 'string',
1511
					'website_title' => 'string', 'website_url' => 'string',
1512
					'signature' => 'string', 'usertitle' => 'string', 'secret_question' => 'string',
1513
					'additional_groups' => 'string', 'ignore_boards' => 'string',
1514
				),
1515
				array(
1516
					stripslashes($_POST['username']), stripslashes($_POST['username']), $_POST['password1'], stripslashes($_POST['email']),
1517
					1, 0, time(),
1518
					$incontext['member_salt'], '', '', '',
1519
					$ip, $ip, '', '',
1520
					'', '',
1521
					'', '', '',
1522
					'', '',
1523
				),
1524
				array('id_member'),
1525
				1
1526
			);
1527
		}
1528
1529
		// If we're here we're good.
1530
		return true;
1531
	}
1532
1533
	return false;
1534
}
1535
1536
// Final step, clean up and a complete message!
1537
function DeleteInstall()
1538
{
1539
	global $smcFunc, $db_character_set, $context, $txt, $incontext;
1540
	global $current_smf_version, $databases, $sourcedir, $forum_version, $modSettings, $user_info, $db_type;
1541
1542
	$incontext['page_title'] = $txt['congratulations'];
1543
	$incontext['sub_template'] = 'delete_install';
1544
	$incontext['continue'] = 0;
1545
1546
	require(dirname(__FILE__) . '/Settings.php');
1547
	load_database();
1548
1549
	chdir(dirname(__FILE__));
1550
1551
	require_once($sourcedir . '/Errors.php');
1552
	require_once($sourcedir . '/Logging.php');
1553
	require_once($sourcedir . '/Subs.php');
1554
	require_once($sourcedir . '/Load.php');
1555
	require_once($sourcedir . '/Security.php');
1556
	require_once($sourcedir . '/Subs-Auth.php');
1557
1558
	// Bring a warning over.
1559
	if (!empty($incontext['account_existed']))
1560
		$incontext['warning'] = $incontext['account_existed'];
1561
1562 View Code Duplication
	if (!empty($db_character_set) && !empty($databases[$db_type]['utf8_support']))
1563
		$smcFunc['db_query']('', '
1564
			SET NAMES {string:db_character_set}',
1565
			array(
1566
				'db_character_set' => $db_character_set,
1567
				'db_error_skip' => true,
1568
			)
1569
		);
1570
1571
	// As track stats is by default enabled let's add some activity.
1572
	$smcFunc['db_insert']('ignore',
1573
		'{db_prefix}log_activity',
1574
		array('date' => 'date', 'topics' => 'int', 'posts' => 'int', 'registers' => 'int'),
1575
		array(strftime('%Y-%m-%d', time()), 1, 1, (!empty($incontext['member_id']) ? 1 : 0)),
1576
		array('date')
1577
	);
1578
1579
	// We're going to want our lovely $modSettings now.
1580
	$request = $smcFunc['db_query']('', '
1581
		SELECT variable, value
1582
		FROM {db_prefix}settings',
1583
		array(
1584
			'db_error_skip' => true,
1585
		)
1586
	);
1587
	// Only proceed if we can load the data.
1588
	if ($request)
1589
	{
1590 View Code Duplication
		while ($row = $smcFunc['db_fetch_row']($request))
1591
			$modSettings[$row[0]] = $row[1];
1592
		$smcFunc['db_free_result']($request);
1593
	}
1594
1595
	// Automatically log them in ;)
1596
	if (isset($incontext['member_id']) && isset($incontext['member_salt']))
1597
		setLoginCookie(3153600 * 60, $incontext['member_id'], hash_salt($_POST['password1'], $incontext['member_salt']));
1598
1599
	$result = $smcFunc['db_query']('', '
1600
		SELECT value
1601
		FROM {db_prefix}settings
1602
		WHERE variable = {string:db_sessions}',
1603
		array(
1604
			'db_sessions' => 'databaseSession_enable',
1605
			'db_error_skip' => true,
1606
		)
1607
	);
1608 View Code Duplication
	if ($smcFunc['db_num_rows']($result) != 0)
1609
		list ($db_sessions) = $smcFunc['db_fetch_row']($result);
1610
	$smcFunc['db_free_result']($result);
1611
1612
	if (empty($db_sessions))
1613
		$_SESSION['admin_time'] = time();
1614
	else
1615
	{
1616
		$_SERVER['HTTP_USER_AGENT'] = substr($_SERVER['HTTP_USER_AGENT'], 0, 211);
1617
1618
		$smcFunc['db_insert']('replace',
1619
			'{db_prefix}sessions',
1620
			array(
1621
				'session_id' => 'string', 'last_update' => 'int', 'data' => 'string',
1622
			),
1623
			array(
1624
				session_id(), time(), 'USER_AGENT|s:' . strlen($_SERVER['HTTP_USER_AGENT']) . ':"' . $_SERVER['HTTP_USER_AGENT'] . '";admin_time|i:' . time() . ';',
1625
			),
1626
			array('session_id')
1627
		);
1628
	}
1629
1630
	updateStats('member');
1631
	updateStats('message');
1632
	updateStats('topic');
1633
1634
	// This function is needed to do the updateStats('subject') call.
1635
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' :
1636 View Code Duplication
		function($string){
1637
			global $sourcedir;
1638
			if (function_exists('mb_strtolower'))
1639
				return mb_strtolower($string, 'UTF-8');
1640
			require_once($sourcedir . '/Subs-Charset.php');
1641
			return utf8_strtolower($string);
1642
		};
1643
1644
	$request = $smcFunc['db_query']('', '
1645
		SELECT id_msg
1646
		FROM {db_prefix}messages
1647
		WHERE id_msg = 1
1648
			AND modified_time = 0
1649
		LIMIT 1',
1650
		array(
1651
			'db_error_skip' => true,
1652
		)
1653
	);
1654
	$context['utf8'] = $db_character_set === 'utf8' || $txt['lang_character_set'] === 'UTF-8';
1655
	if ($smcFunc['db_num_rows']($request) > 0)
1656
		updateStats('subject', 1, htmlspecialchars($txt['default_topic_subject']));
1657
	$smcFunc['db_free_result']($request);
1658
1659
	// Now is the perfect time to fetch the SM files.
1660
	require_once($sourcedir . '/ScheduledTasks.php');
1661
	// Sanity check that they loaded earlier!
1662
	if (isset($modSettings['recycle_board']))
1663
	{
1664
		$forum_version = $current_smf_version; // The variable is usually defined in index.php so lets just use our variable to do it for us.
1665
		scheduled_fetchSMfiles(); // Now go get those files!
1666
1667
		// We've just installed!
1668
		$user_info['ip'] = $_SERVER['REMOTE_ADDR'];
1669
		$user_info['id'] = isset($incontext['member_id']) ? $incontext['member_id'] : 0;
1670
		logAction('install', array('version' => $forum_version), 'admin');
1671
	}
1672
1673
	// Check if we need some stupid MySQL fix.
1674
	$server_version = $smcFunc['db_server_info']();
1675 View Code Duplication
	if (($db_type == 'mysql' || $db_type == 'mysqli') && in_array(substr($server_version, 0, 6), array('5.0.50', '5.0.51')))
1676
		updateSettings(array('db_mysql_group_by_fix' => '1'));
1677
1678
	// Some final context for the template.
1679
	$incontext['dir_still_writable'] = is_writable(dirname(__FILE__)) && substr(__FILE__, 1, 2) != ':\\';
1680
	$incontext['probably_delete_install'] = isset($_SESSION['installer_temp_ftp']) || is_writable(dirname(__FILE__)) || is_writable(__FILE__);
1681
1682
	// Update hash's cost to an appropriate setting
1683
	updateSettings(array(
1684
		'bcrypt_hash_cost' => hash_benchmark(),
1685
	));
1686
1687
	return false;
1688
}
1689
1690
function updateSettingsFile($vars)
1691
{
1692
	// Modify Settings.php.
1693
	$settingsArray = file(dirname(__FILE__) . '/Settings.php');
1694
1695
	// @todo Do we just want to read the file in clean, and split it this way always?
1696
	if (count($settingsArray) == 1)
1697
		$settingsArray = preg_split('~[\r\n]~', $settingsArray[0]);
1698
1699
	for ($i = 0, $n = count($settingsArray); $i < $n; $i++)
1700
	{
1701
		// Remove the redirect...
1702
		if (trim($settingsArray[$i]) == 'if (file_exists(dirname(__FILE__) . \'/install.php\'))' && trim($settingsArray[$i + 1]) == '{' && trim($settingsArray[$i + 3]) == '}')
1703
		{
1704
			// Get the four lines to nothing.
1705
			$settingsArray[$i] = '';
1706
			$settingsArray[++$i] = '';
1707
			$settingsArray[++$i] = '';
1708
			$settingsArray[++$i] = '';
1709
			continue;
1710
		}
1711
1712
		if (trim($settingsArray[$i]) == '?' . '>')
1713
			$settingsArray[$i] = '';
1714
1715
		// Don't trim or bother with it if it's not a variable.
1716
		if (substr($settingsArray[$i], 0, 1) != '$')
1717
			continue;
1718
1719
		$settingsArray[$i] = rtrim($settingsArray[$i]) . "\n";
1720
1721
		foreach ($vars as $var => $val)
1722
			if (strncasecmp($settingsArray[$i], '$' . $var, 1 + strlen($var)) == 0)
1723
			{
1724
				$comment = strstr($settingsArray[$i], '#');
1725
				$settingsArray[$i] = '$' . $var . ' = \'' . $val . '\';' . ($comment != '' ? "\t\t" . $comment : "\n");
1726
				unset($vars[$var]);
1727
			}
1728
	}
1729
1730
	// Uh oh... the file wasn't empty... was it?
1731
	if (!empty($vars))
1732
	{
1733
		$settingsArray[$i++] = '';
1734
		foreach ($vars as $var => $val)
1735
			$settingsArray[$i++] = '$' . $var . ' = \'' . $val . '\';' . "\n";
1736
	}
1737
1738
	// Blank out the file - done to fix a oddity with some servers.
1739
	$fp = @fopen(dirname(__FILE__) . '/Settings.php', 'w');
1740
	if (!$fp)
1741
		return false;
1742
	fclose($fp);
1743
1744
	$fp = fopen(dirname(__FILE__) . '/Settings.php', 'r+');
1745
1746
	// Gotta have one of these ;)
1747
	if (trim($settingsArray[0]) != '<?php')
1748
		fwrite($fp, "<?php\n");
1749
1750
	$lines = count($settingsArray);
1751
	for ($i = 0; $i < $lines - 1; $i++)
1752
	{
1753
		// Don't just write a bunch of blank lines.
1754
		if ($settingsArray[$i] != '' || @$settingsArray[$i - 1] != '')
1755
			fwrite($fp, strtr($settingsArray[$i], "\r", ''));
0 ignored issues
show
Security File Manipulation introduced by
strtr($settingsArray[$i], ' ', '') can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

5 paths for user data to reach this point

  1. Path: Read from $_GET, and $changes is assigned in other/upgrade.php on line 1046
  1. Read from $_GET, and $changes is assigned
    in other/upgrade.php on line 1046
  2. $changes is passed to updateSettingsFile()
    in other/upgrade.php on line 1123
  3. $var is assigned
    in other/install.php on line 1734
  4. $settingsArray is assigned
    in other/install.php on line 1735
  5. $settingsArray[$i] is passed through strtr()
    in other/install.php on line 1755
  2. Path: Read from $_POST, and $_POST['maintitle'] is escaped by addslashes() for sql, xpath context(s), and $changes is assigned in other/upgrade.php on line 1056
  1. Read from $_POST, and $_POST['maintitle'] is escaped by addslashes() for sql, xpath context(s), and $changes is assigned
    in other/upgrade.php on line 1056
  2. $changes is assigned
    in other/upgrade.php on line 1057
  3. $changes is passed to updateSettingsFile()
    in other/upgrade.php on line 1123
  4. $var is assigned
    in other/install.php on line 1734
  5. $settingsArray is assigned
    in other/install.php on line 1735
  6. $settingsArray[$i] is passed through strtr()
    in other/install.php on line 1755
  3. Path: Read from $_POST, and $_POST['mainmessage'] is escaped by addslashes() for sql, xpath context(s), and $changes is assigned in other/upgrade.php on line 1057
  1. Read from $_POST, and $_POST['mainmessage'] is escaped by addslashes() for sql, xpath context(s), and $changes is assigned
    in other/upgrade.php on line 1057
  2. $changes is passed to updateSettingsFile()
    in other/upgrade.php on line 1123
  3. $var is assigned
    in other/install.php on line 1734
  4. $settingsArray is assigned
    in other/install.php on line 1735
  5. $settingsArray[$i] is passed through strtr()
    in other/install.php on line 1755
  4. Path: Read from $_POST, and $_POST[$config_var][0] is passed through addcslashes(), and $new_settings is assigned in Sources/ManageServer.php on line 1076
  1. Read from $_POST, and $_POST[$config_var][0] is passed through addcslashes(), and $new_settings is assigned
    in Sources/ManageServer.php on line 1076
  2. $new_settings is passed to updateSettingsFile()
    in Sources/ManageServer.php on line 1110
  3. $var is assigned
    in other/install.php on line 1734
  4. $settingsArray is assigned
    in other/install.php on line 1735
  5. $settingsArray[$i] is passed through strtr()
    in other/install.php on line 1755
  5. Path: Read from $_POST, and $_POST[$config_var] is passed through addcslashes(), and $new_settings is assigned in Sources/ManageServer.php on line 1080
  1. Read from $_POST, and $_POST[$config_var] is passed through addcslashes(), and $new_settings is assigned
    in Sources/ManageServer.php on line 1080
  2. $new_settings is passed to updateSettingsFile()
    in Sources/ManageServer.php on line 1110
  3. $var is assigned
    in other/install.php on line 1734
  4. $settingsArray is assigned
    in other/install.php on line 1735
  5. $settingsArray[$i] is passed through strtr()
    in other/install.php on line 1755

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
1756
	}
1757
	fwrite($fp, $settingsArray[$i] . '?' . '>');
0 ignored issues
show
Security File Manipulation introduced by
$settingsArray[$i] . '?' . '>' can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

5 paths for user data to reach this point

  1. Path: Read from $_GET, and $changes is assigned in other/upgrade.php on line 1046
  1. Read from $_GET, and $changes is assigned
    in other/upgrade.php on line 1046
  2. $changes is passed to updateSettingsFile()
    in other/upgrade.php on line 1123
  3. $var is assigned
    in other/install.php on line 1734
  4. $settingsArray is assigned
    in other/install.php on line 1735
  2. Path: Read from $_POST, and $_POST['maintitle'] is escaped by addslashes() for sql, xpath context(s), and $changes is assigned in other/upgrade.php on line 1056
  1. Read from $_POST, and $_POST['maintitle'] is escaped by addslashes() for sql, xpath context(s), and $changes is assigned
    in other/upgrade.php on line 1056
  2. $changes is assigned
    in other/upgrade.php on line 1057
  3. $changes is passed to updateSettingsFile()
    in other/upgrade.php on line 1123
  4. $var is assigned
    in other/install.php on line 1734
  5. $settingsArray is assigned
    in other/install.php on line 1735
  3. Path: Read from $_POST, and $_POST['mainmessage'] is escaped by addslashes() for sql, xpath context(s), and $changes is assigned in other/upgrade.php on line 1057
  1. Read from $_POST, and $_POST['mainmessage'] is escaped by addslashes() for sql, xpath context(s), and $changes is assigned
    in other/upgrade.php on line 1057
  2. $changes is passed to updateSettingsFile()
    in other/upgrade.php on line 1123
  3. $var is assigned
    in other/install.php on line 1734
  4. $settingsArray is assigned
    in other/install.php on line 1735
  4. Path: Read from $_POST, and $_POST[$config_var][0] is passed through addcslashes(), and $new_settings is assigned in Sources/ManageServer.php on line 1076
  1. Read from $_POST, and $_POST[$config_var][0] is passed through addcslashes(), and $new_settings is assigned
    in Sources/ManageServer.php on line 1076
  2. $new_settings is passed to updateSettingsFile()
    in Sources/ManageServer.php on line 1110
  3. $var is assigned
    in other/install.php on line 1734
  4. $settingsArray is assigned
    in other/install.php on line 1735
  5. Path: Read from $_POST, and $_POST[$config_var] is passed through addcslashes(), and $new_settings is assigned in Sources/ManageServer.php on line 1080
  1. Read from $_POST, and $_POST[$config_var] is passed through addcslashes(), and $new_settings is assigned
    in Sources/ManageServer.php on line 1080
  2. $new_settings is passed to updateSettingsFile()
    in Sources/ManageServer.php on line 1110
  3. $var is assigned
    in other/install.php on line 1734
  4. $settingsArray is assigned
    in other/install.php on line 1735

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
1758
	fclose($fp);
1759
1760
	// Even though on normal installations the filemtime should prevent this being used by the installer incorrectly
1761
	// it seems that there are times it might not. So let's MAKE it dump the cache.
1762
	if (function_exists('opcache_invalidate'))
1763
		opcache_invalidate(dirname(__FILE__) . '/Settings.php', true);
1764
1765
	return true;
1766
}
1767
1768
function updateDbLastError()
1769
{
1770
	// Write out the db_last_error file with the error timestamp
1771
	file_put_contents(dirname(__FILE__) . '/db_last_error.php', '<' . '?' . "php\n" . '$db_last_error = 0;' . "\n" . '?' . '>');
1772
1773
	return true;
1774
}
1775
1776
// Create an .htaccess file to prevent mod_security. SMF has filtering built-in.
1777
function fixModSecurity()
1778
{
1779
	$htaccess_addition = '
1780
<IfModule mod_security.c>
1781
	# Turn off mod_security filtering.  SMF is a big boy, it doesn\'t need its hands held.
1782
	SecFilterEngine Off
1783
1784
	# The below probably isn\'t needed, but better safe than sorry.
1785
	SecFilterScanPOST Off
1786
</IfModule>';
1787
1788
	if (!function_exists('apache_get_modules') || !in_array('mod_security', apache_get_modules()))
1789
		return true;
1790
	elseif (file_exists(dirname(__FILE__) . '/.htaccess') && is_writable(dirname(__FILE__) . '/.htaccess'))
1791
	{
1792
		$current_htaccess = implode('', file(dirname(__FILE__) . '/.htaccess'));
1793
1794
		// Only change something if mod_security hasn't been addressed yet.
1795
		if (strpos($current_htaccess, '<IfModule mod_security.c>') === false)
1796
		{
1797 View Code Duplication
			if ($ht_handle = fopen(dirname(__FILE__) . '/.htaccess', 'a'))
1798
			{
1799
				fwrite($ht_handle, $htaccess_addition);
1800
				fclose($ht_handle);
1801
				return true;
1802
			}
1803
			else
1804
				return false;
1805
		}
1806
		else
1807
			return true;
1808
	}
1809
	elseif (file_exists(dirname(__FILE__) . '/.htaccess'))
1810
		return strpos(implode('', file(dirname(__FILE__) . '/.htaccess')), '<IfModule mod_security.c>') !== false;
1811
	elseif (is_writable(dirname(__FILE__)))
1812
	{
1813 View Code Duplication
		if ($ht_handle = fopen(dirname(__FILE__) . '/.htaccess', 'w'))
1814
		{
1815
			fwrite($ht_handle, $htaccess_addition);
1816
			fclose($ht_handle);
1817
			return true;
1818
		}
1819
		else
1820
			return false;
1821
	}
1822
	else
1823
		return false;
1824
}
1825
1826
function template_install_above()
1827
{
1828
	global $incontext, $txt, $installurl;
1829
1830
	echo '<!DOCTYPE html>
1831
<html', $txt['lang_rtl'] == true ? ' dir="rtl"' : '', '>
1832
	<head>
1833
		<meta charset="', isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8', '">
1834
		<meta name="robots" content="noindex">
1835
		<title>', $txt['smf_installer'], '</title>
1836
		<link rel="stylesheet" href="Themes/default/css/index.css?alp21">
1837
		<link rel="stylesheet" href="Themes/default/css/install.css?alp21">
1838
		', $txt['lang_rtl'] == true ? '<link rel="stylesheet" href="Themes/default/css/rtl.css?alp21">' : '', '
1839
1840
		<script src="Themes/default/scripts/jquery-3.1.1.min.js"></script>
1841
		<script src="Themes/default/scripts/script.js"></script>
1842
	</head>
1843
	<body><div id="footerfix">
1844
		<div id="header">
1845
			<h1 class="forumtitle">', $txt['smf_installer'], '</h1>
1846
			<img id="smflogo" src="Themes/default/images/smflogo.png" alt="Simple Machines Forum" title="Simple Machines Forum">
1847
		</div>
1848
		<div id="wrapper">
1849
			<div id="upper_section">
1850
				<div id="inner_section">
1851
					<div id="inner_wrap">';
1852
1853
	// Have we got a language drop down - if so do it on the first step only.
1854
	if (!empty($incontext['detected_languages']) && count($incontext['detected_languages']) > 1 && $incontext['current_step'] == 0)
1855
	{
1856
		echo '
1857
						<div class="news">
1858
							<form action="', $installurl, '" method="get">
1859
								<label for="installer_language">', $txt['installer_language'], ':</label>
1860
								<select id="installer_language" name="lang_file" onchange="location.href = \'', $installurl, '?lang_file=\' + this.options[this.selectedIndex].value;">';
1861
1862
		foreach ($incontext['detected_languages'] as $lang => $name)
1863
			echo '
1864
									<option', isset($_SESSION['installer_temp_lang']) && $_SESSION['installer_temp_lang'] == $lang ? ' selected' : '', ' value="', $lang, '">', $name, '</option>';
1865
1866
		echo '
1867
								</select>
1868
								<noscript><input type="submit" value="', $txt['installer_language_set'], '" class="button_submit" /></noscript>
1869
							</form>
1870
						</div>
1871
						<hr class="clear" />';
1872
	}
1873
1874
	echo '
1875
					</div>
1876
				</div>
1877
			</div>
1878
			<div id="content_section">
1879
				<div id="main_content_section">
1880
					<div id="main_steps">
1881
						<h2>', $txt['upgrade_progress'], '</h2>
1882
						<ul>';
1883
1884 View Code Duplication
	foreach ($incontext['steps'] as $num => $step)
1885
		echo '
1886
							<li class="', $num < $incontext['current_step'] ? 'stepdone' : ($num == $incontext['current_step'] ? 'stepcurrent' : 'stepwaiting'), '">', $txt['upgrade_step'], ' ', $step[0], ': ', $step[1], '</li>';
1887
1888
	echo '
1889
						</ul>
1890
					</div>
1891
					<div id="progress_bar">
1892
						<div id="overall_text">', $incontext['overall_percent'], '%</div>
1893
						<div id="overall_progress" style="width: ', $incontext['overall_percent'], '%;">
1894
							<span>'. $txt['upgrade_overall_progress'], '</span>
1895
						</div>
1896
					</div>
1897
					<div id="main_screen" class="clear">
1898
						<h2>', $incontext['page_title'], '</h2>
1899
						<div class="panel">';
1900
}
1901
1902
function template_install_below()
1903
{
1904
	global $incontext, $txt;
1905
1906
	if (!empty($incontext['continue']) || !empty($incontext['skip']))
1907
	{
1908
		echo '
1909
								<div>';
1910
1911
		if (!empty($incontext['continue']))
1912
			echo '
1913
									<input type="submit" id="contbutt" name="contbutt" value="', $txt['upgrade_continue'], '" onclick="return submitThisOnce(this);" class="button_submit" />';
1914
		if (!empty($incontext['skip']))
1915
			echo '
1916
									<input type="submit" id="skip" name="skip" value="', $txt['upgrade_skip'], '" onclick="return submitThisOnce(this);" class="button_submit" />';
1917
		echo '
1918
								</div>';
1919
	}
1920
1921
	// Show the closing form tag and other data only if not in the last step
1922
	if (count($incontext['steps']) - 1 !== (int) $incontext['current_step'])
1923
		echo '
1924
							</form>';
1925
1926
	echo '
1927
						</div>
1928
					</div>
1929
				</div>
1930
			</div>
1931
		</div></div>
1932
		<div id="footer">
1933
			<ul>
1934
				<li class="copyright"><a href="https://www.simplemachines.org/" title="Simple Machines Forum" target="_blank" class="new_win">SMF &copy; 2017, Simple Machines</a></li>
1935
			</ul>
1936
		</div>
1937
	</body>
1938
</html>';
1939
}
1940
1941
// Welcome them to the wonderful world of SMF!
1942
function template_welcome_message()
1943
{
1944
	global $incontext, $txt;
1945
1946
	echo '
1947
	<script src="https://www.simplemachines.org/smf/current-version.js?version=' . $GLOBALS['current_smf_version'] . '"></script>
1948
	<form action="', $incontext['form_url'], '" method="post">
1949
		<p>', sprintf($txt['install_welcome_desc'], $GLOBALS['current_smf_version']), '</p>
1950
		<div id="version_warning" style="margin: 2ex; padding: 2ex; border: 2px dashed #a92174; color: black; background-color: #fbbbe2; display: none;">
1951
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
1952
			<strong style="text-decoration: underline;">', $txt['error_warning_notice'], '</strong><br>
1953
			<div style="padding-left: 6ex;">
1954
				', sprintf($txt['error_script_outdated'], '<em id="smfVersion" style="white-space: nowrap;">??</em>', '<em id="yourVersion" style="white-space: nowrap;">' . $GLOBALS['current_smf_version'] . '</em>'), '
1955
			</div>
1956
		</div>';
1957
1958
	// Show the warnings, or not.
1959
	if (template_warning_divs())
1960
		echo '
1961
		<h3>', $txt['install_all_lovely'], '</h3>';
1962
1963
	// Say we want the continue button!
1964
	if (empty($incontext['error']))
1965
		$incontext['continue'] = 1;
1966
1967
	// For the latest version stuff.
1968
	echo '
1969
		<script>
1970
			// Latest version?
1971
			function smfCurrentVersion()
1972
			{
1973
				var smfVer, yourVer;
1974
1975
				if (!(\'smfVersion\' in window))
1976
					return;
1977
1978
				window.smfVersion = window.smfVersion.replace(/SMF\s?/g, \'\');
1979
1980
				smfVer = document.getElementById("smfVersion");
1981
				yourVer = document.getElementById("yourVersion");
1982
1983
				setInnerHTML(smfVer, window.smfVersion);
1984
1985
				var currentVersion = getInnerHTML(yourVer);
1986
				if (currentVersion < window.smfVersion)
1987
					document.getElementById(\'version_warning\').style.display = \'\';
1988
			}
1989
			addLoadEvent(smfCurrentVersion);
1990
		</script>';
1991
}
1992
1993
// A shortcut for any warning stuff.
1994
function template_warning_divs()
1995
{
1996
	global $txt, $incontext;
1997
1998
	// Errors are very serious..
1999
	if (!empty($incontext['error']))
2000
		echo '
2001
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
2002
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
2003
			<strong style="text-decoration: underline;">', $txt['upgrade_critical_error'], '</strong><br>
2004
			<div style="padding-left: 6ex;">
2005
				', $incontext['error'], '
2006
			</div>
2007
		</div>';
2008
	// A warning message?
2009
	elseif (!empty($incontext['warning']))
2010
		echo '
2011
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
2012
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
2013
			<strong style="text-decoration: underline;">', $txt['upgrade_warning'], '</strong><br>
2014
			<div style="padding-left: 6ex;">
2015
				', $incontext['warning'], '
2016
			</div>
2017
		</div>';
2018
2019
	return empty($incontext['error']) && empty($incontext['warning']);
2020
}
2021
2022
function template_chmod_files()
2023
{
2024
	global $txt, $incontext;
2025
2026
	echo '
2027
		<p>', $txt['ftp_setup_why_info'], '</p>
2028
		<ul style="margin: 2.5ex; font-family: monospace;">
2029
			<li>', implode('</li>
2030
			<li>', $incontext['failed_files']), '</li>
2031
		</ul>';
2032
2033
	if (isset($incontext['systemos'], $incontext['detected_path']) && $incontext['systemos'] == 'linux')
2034
		echo '
2035
		<hr>
2036
		<p>', $txt['chmod_linux_info'], '</p>
2037
		<tt># chmod a+w ', implode(' ' . $incontext['detected_path'] . '/', $incontext['failed_files']), '</tt>';
2038
2039
	// This is serious!
2040
	if (!template_warning_divs())
2041
		return;
2042
2043
	echo '
2044
		<hr>
2045
		<p>', $txt['ftp_setup_info'], '</p>';
2046
2047
	if (!empty($incontext['ftp_errors']))
2048
		echo '
2049
		<div class="error_message">
2050
			', $txt['error_ftp_no_connect'], '<br><br>
2051
			<code>', implode('<br>', $incontext['ftp_errors']), '</code>
2052
		</div>
2053
		<br>';
2054
2055
	echo '
2056
		<form action="', $incontext['form_url'], '" method="post">
2057
			<table align="center" style="width: 520px; margin: 1em 0; padding: 0; border: 0">
2058
				<tr>
2059
					<td width="26%" valign="top" class="textbox"><label for="ftp_server">', $txt['ftp_server'], ':</label></td>
2060
					<td>
2061
						<div style="float: ', $txt['lang_rtl'] == false ? 'right' : 'left', '; margin-', $txt['lang_rtl'] == false ? 'right' : 'left', ': 1px;"><label for="ftp_port" class="textbox"><strong>', $txt['ftp_port'], ':&nbsp;</strong></label> <input type="text" size="3" name="ftp_port" id="ftp_port" value="', $incontext['ftp']['port'], '" class="input_text" /></div>
2062
						<input type="text" size="30" name="ftp_server" id="ftp_server" value="', $incontext['ftp']['server'], '" style="width: 70%;" class="input_text" />
2063
						<div class="smalltext block">', $txt['ftp_server_info'], '</div>
2064
					</td>
2065
				</tr><tr>
2066
					<td width="26%" valign="top" class="textbox"><label for="ftp_username">', $txt['ftp_username'], ':</label></td>
2067
					<td>
2068
						<input type="text" size="50" name="ftp_username" id="ftp_username" value="', $incontext['ftp']['username'], '" style="width: 99%;" class="input_text" />
2069
						<div class="smalltext block">', $txt['ftp_username_info'], '</div>
2070
					</td>
2071
				</tr><tr>
2072
					<td width="26%" valign="top" class="textbox"><label for="ftp_password">', $txt['ftp_password'], ':</label></td>
2073
					<td>
2074
						<input type="password" size="50" name="ftp_password" id="ftp_password" style="width: 99%;" class="input_password" />
2075
						<div class="smalltext block">', $txt['ftp_password_info'], '</div>
2076
					</td>
2077
				</tr><tr>
2078
					<td width="26%" valign="top" class="textbox"><label for="ftp_path">', $txt['ftp_path'], ':</label></td>
2079
					<td style="padding-bottom: 1ex;">
2080
						<input type="text" size="50" name="ftp_path" id="ftp_path" value="', $incontext['ftp']['path'], '" style="width: 99%;" class="input_text" />
2081
						<div class="smalltext block">', $incontext['ftp']['path_msg'], '</div>
2082
					</td>
2083
				</tr>
2084
			</table>
2085
			<div style="margin: 1ex; margin-top: 1ex; text-align: ', $txt['lang_rtl'] == false ? 'right' : 'left', ';"><input type="submit" value="', $txt['ftp_connect'], '" onclick="return submitThisOnce(this);" class="button_submit" /></div>
2086
		</form>
2087
		<a href="', $incontext['form_url'], '">', $txt['error_message_click'], '</a> ', $txt['ftp_setup_again'];
2088
}
2089
2090
// Get the database settings prepared.
2091
function template_database_settings()
2092
{
2093
	global $incontext, $txt;
2094
2095
	echo '
2096
	<form action="', $incontext['form_url'], '" method="post">
2097
		<p>', $txt['db_settings_info'], '</p>';
2098
2099
	template_warning_divs();
2100
2101
	echo '
2102
		<table width="100%" border="0" style="margin: 1em 0;">';
2103
2104
	// More than one database type?
2105
	if (count($incontext['supported_databases']) > 1)
2106
	{
2107
		echo '
2108
			<tr>
2109
				<td width="20%" valign="top" class="textbox"><label for="db_type_input">', $txt['db_settings_type'], ':</label></td>
2110
				<td>
2111
					<select name="db_type" id="db_type_input" onchange="toggleDBInput();">';
2112
2113
	foreach ($incontext['supported_databases'] as $key => $db)
2114
			echo '
2115
						<option value="', $key, '"', isset($_POST['db_type']) && $_POST['db_type'] == $key ? ' selected' : '', '>', $db['name'], '</option>';
2116
2117
	echo '
2118
					</select>
2119
					<div class="smalltext block">', $txt['db_settings_type_info'], '</div>
2120
				</td>
2121
			</tr>';
2122
	}
2123
	else
2124
	{
2125
		echo '
2126
			<tr style="display: none;">
2127
				<td>
2128
					<input type="hidden" name="db_type" value="', $incontext['db']['type'], '" />
2129
				</td>
2130
			</tr>';
2131
	}
2132
2133
	echo '
2134
			<tr id="db_server_contain">
2135
				<td width="20%" valign="top" class="textbox"><label for="db_server_input">', $txt['db_settings_server'], ':</label></td>
2136
				<td>
2137
					<input type="text" name="db_server" id="db_server_input" value="', $incontext['db']['server'], '" size="30" class="input_text" /><br>
2138
					<div class="smalltext block">', $txt['db_settings_server_info'], '</div>
2139
				</td>
2140
			</tr><tr id="db_port_contain">
2141
				<td width="20%" valign="top" class="textbox"><label for="db_port_input">', $txt['db_settings_port'], ':</label></td>
2142
				<td>
2143
					<input type="text" name="db_port" id="db_port_input" value="', $incontext['db']['port'], '"><br>
2144
					<div class="smalltext block">', $txt['db_settings_port_info'], '</div>
2145
				</td>
2146
			</tr><tr id="db_user_contain">
2147
				<td valign="top" class="textbox"><label for="db_user_input">', $txt['db_settings_username'], ':</label></td>
2148
				<td>
2149
					<input type="text" name="db_user" id="db_user_input" value="', $incontext['db']['user'], '" size="30" class="input_text" /><br>
2150
					<div class="smalltext block">', $txt['db_settings_username_info'], '</div>
2151
				</td>
2152
			</tr><tr id="db_passwd_contain">
2153
				<td valign="top" class="textbox"><label for="db_passwd_input">', $txt['db_settings_password'], ':</label></td>
2154
				<td>
2155
					<input type="password" name="db_passwd" id="db_passwd_input" value="', $incontext['db']['pass'], '" size="30" class="input_password" /><br>
2156
					<div class="smalltext block">', $txt['db_settings_password_info'], '</div>
2157
				</td>
2158
			</tr><tr id="db_name_contain">
2159
				<td valign="top" class="textbox"><label for="db_name_input">', $txt['db_settings_database'], ':</label></td>
2160
				<td>
2161
					<input type="text" name="db_name" id="db_name_input" value="', empty($incontext['db']['name']) ? 'smf' : $incontext['db']['name'], '" size="30" class="input_text" /><br>
2162
					<div class="smalltext block">', $txt['db_settings_database_info'], '
2163
					<span id="db_name_info_warning">', $txt['db_settings_database_info_note'], '</span></div>
2164
				</td>
2165
			</tr><tr id="db_filename_contain" style="display: none;">
2166
				<td valign="top" class="textbox"><label for="db_filename_input">', $txt['db_settings_database_file'], ':</label></td>
2167
				<td>
2168
					<input type="text" name="db_filename" id="db_filename_input" value="', empty($incontext['db']['name']) ? dirname(__FILE__) . '/smf_' . substr(md5(microtime()), 0, 10) : stripslashes($incontext['db']['name']), '" size="30" class="input_text" /><br>
2169
					<div class="smalltext block">', $txt['db_settings_database_file_info'], '</div>
2170
				</td>
2171
			</tr><tr>
2172
				<td valign="top" class="textbox"><label for="db_prefix_input">', $txt['db_settings_prefix'], ':</label></td>
2173
				<td>
2174
					<input type="text" name="db_prefix" id="db_prefix_input" value="', $incontext['db']['prefix'], '" size="30" class="input_text" /><br>
2175
					<div class="smalltext block">', $txt['db_settings_prefix_info'], '</div>
2176
				</td>
2177
			</tr>
2178
		</table>';
2179
2180
	// Toggles a warning related to db names in PostgreSQL
2181
	echo '
2182
	<script>
2183
		function toggleDBInput()
2184
		{
2185
			if (document.getElementById(\'db_type_input\').value == \'postgresql\')
2186
				document.getElementById(\'db_name_info_warning\').style.display = \'none\';
2187
			else
2188
				document.getElementById(\'db_name_info_warning\').style.display = \'\';
2189
		}
2190
		toggleDBInput();
2191
	</script>';
2192
}
2193
2194
// Stick in their forum settings.
2195
function template_forum_settings()
2196
{
2197
	global $incontext, $txt;
2198
2199
	echo '
2200
	<form action="', $incontext['form_url'], '" method="post">
2201
		<h3>', $txt['install_settings_info'], '</h3>';
2202
2203
	template_warning_divs();
2204
2205
	echo '
2206
		<table style="width: 100%; margin: 1em 0;">
2207
			<tr>
2208
				<td class="textbox" style="width: 20%; vertical-align: top;">
2209
					<label for="mbname_input">', $txt['install_settings_name'], ':</label>
2210
				</td>
2211
				<td>
2212
					<input type="text" name="mbname" id="mbname_input" value="', $txt['install_settings_name_default'], '" size="65" class="input_text" />
2213
					<div class="smalltext block">', $txt['install_settings_name_info'], '</div>
2214
				</td>
2215
			</tr>
2216
			<tr>
2217
				<td class="textbox" style="vertical-align: top;">
2218
					<label for="boardurl_input">', $txt['install_settings_url'], ':</label>
2219
				</td>
2220
				<td>
2221
					<input type="text" name="boardurl" id="boardurl_input" value="', $incontext['detected_url'], '" size="65" class="input_text" />
2222
					<br>
2223
					<div class="smalltext block">', $txt['install_settings_url_info'], '</div>
2224
				</td>
2225
			</tr>
2226
			<tr>
2227
				<td class="textbox" style="vertical-align: top;">
2228
					<label for="reg_mode">', $txt['install_settings_reg_mode'], ':</label>
2229
				</td>
2230
				<td>
2231
					<select name="reg_mode" id="reg_mode">
2232
						<optgroup label="', $txt['install_settings_reg_modes'], ':">
2233
							<option value="0" selected>', $txt['install_settings_reg_immediate'], '</option>
2234
							<option value="1">', $txt['install_settings_reg_email'], '</option>
2235
							<option value="2">', $txt['install_settings_reg_admin'], '</option>
2236
							<option value="3">', $txt['install_settings_reg_disabled'], '</option>
2237
						</optgroup>
2238
					</select>
2239
					<br>
2240
					<div class="smalltext block">', $txt['install_settings_reg_mode_info'], '</div>
2241
				</td>
2242
			</tr>
2243
			<tr>
2244
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_compress'], ':</td>
2245
				<td>
2246
					<input type="checkbox" name="compress" id="compress_check" checked class="input_check" />&nbsp;
2247
					<label for="compress_check">', $txt['install_settings_compress_title'], '</label>
2248
					<br>
2249
					<div class="smalltext block">', $txt['install_settings_compress_info'], '</div>
2250
				</td>
2251
			</tr>
2252
			<tr>
2253
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_dbsession'], ':</td>
2254
				<td>
2255
					<input type="checkbox" name="dbsession" id="dbsession_check" checked class="input_check" />&nbsp;
2256
					<label for="dbsession_check">', $txt['install_settings_dbsession_title'], '</label>
2257
					<br>
2258
					<div class="smalltext block">', $incontext['test_dbsession'] ? $txt['install_settings_dbsession_info1'] : $txt['install_settings_dbsession_info2'], '</div>
2259
				</td>
2260
			</tr>
2261
			<tr>
2262
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_utf8'], ':</td>
2263
				<td>
2264
					<input type="checkbox" name="utf8" id="utf8_check"', $incontext['utf8_default'] ? ' checked' : '', ' class="input_check"', $incontext['utf8_required'] ? ' disabled' : '', ' />&nbsp;
2265
					<label for="utf8_check">', $txt['install_settings_utf8_title'], '</label>
2266
					<br>
2267
					<div class="smalltext block">', $txt['install_settings_utf8_info'], '</div>
2268
				</td>
2269
			</tr>
2270
			<tr>
2271
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_stats'], ':</td>
2272
				<td>
2273
					<input type="checkbox" name="stats" id="stats_check" class="input_check" checked="checked" />&nbsp;
2274
					<label for="stats_check">', $txt['install_settings_stats_title'], '</label>
2275
					<br>
2276
					<div class="smalltext block">', $txt['install_settings_stats_info'], '</div>
2277
				</td>
2278
			</tr>
2279
			<tr>
2280
				<td class="textbox" style="vertical-align: top;">', $txt['force_ssl'], ':</td>
2281
				<td>
2282
					<input type="checkbox" name="force_ssl" id="force_ssl" class="input_check" />&nbsp;
2283
					<label for="force_ssl">', $txt['force_ssl_label'], '</label>
2284
					<br>
2285
					<div class="smalltext block">', $txt['force_ssl_info'], '</div>
2286
				</td>
2287
			</tr>
2288
		</table>
2289
	';
2290
}
2291
2292
// Show results of the database population.
2293
function template_populate_database()
2294
{
2295
	global $incontext, $txt;
2296
2297
	echo '
2298
	<form action="', $incontext['form_url'], '" method="post">
2299
		<p>', !empty($incontext['was_refresh']) ? $txt['user_refresh_install_desc'] : $txt['db_populate_info'], '</p>';
2300
2301
	if (!empty($incontext['sql_results']))
2302
	{
2303
		echo '
2304
		<ul>
2305
			<li>', implode('</li><li>', $incontext['sql_results']), '</li>
2306
		</ul>';
2307
	}
2308
2309
	if (!empty($incontext['failures']))
2310
	{
2311
		echo '
2312
				<div style="color: red;">', $txt['error_db_queries'], '</div>
2313
				<ul>';
2314
2315
		foreach ($incontext['failures'] as $line => $fail)
2316
			echo '
2317
						<li><strong>', $txt['error_db_queries_line'], $line + 1, ':</strong> ', nl2br(htmlspecialchars($fail)), '</li>';
2318
2319
		echo '
2320
				</ul>';
2321
	}
2322
2323
	echo '
2324
		<p>', $txt['db_populate_info2'], '</p>';
2325
2326
	template_warning_divs();
2327
2328
	echo '
2329
	<input type="hidden" name="pop_done" value="1" />';
2330
}
2331
2332
// Create the admin account.
2333
function template_admin_account()
2334
{
2335
	global $incontext, $txt;
2336
2337
	echo '
2338
	<form action="', $incontext['form_url'], '" method="post">
2339
		<p>', $txt['user_settings_info'], '</p>';
2340
2341
	template_warning_divs();
2342
2343
	echo '
2344
		<table width="100%" border="0" style="margin: 2em 0;">
2345
			<tr>
2346
				<td width="18%" valign="top" class="textbox"><label for="username">', $txt['user_settings_username'], ':</label></td>
2347
				<td>
2348
					<input type="text" name="username" id="username" value="', $incontext['username'], '" size="40" class="input_text" />
2349
					<div class="smalltext block">', $txt['user_settings_username_info'], '</div>
2350
				</td>
2351
			</tr><tr>
2352
				<td valign="top" class="textbox"><label for="password1">', $txt['user_settings_password'], ':</label></td>
2353
				<td>
2354
					<input type="password" name="password1" id="password1" size="40" class="input_password" />
2355
					<div class="smalltext block">', $txt['user_settings_password_info'], '</div>
2356
				</td>
2357
			</tr><tr>
2358
				<td valign="top" class="textbox"><label for="password2">', $txt['user_settings_again'], ':</label></td>
2359
				<td>
2360
					<input type="password" name="password2" id="password2" size="40" class="input_password" />
2361
					<div class="smalltext block">', $txt['user_settings_again_info'], '</div>
2362
				</td>
2363
			</tr><tr>
2364
				<td valign="top" class="textbox"><label for="email">', $txt['user_settings_admin_email'], ':</label></td>
2365
				<td>
2366
					<input type="text" name="email" id="email" value="', $incontext['email'], '" size="40" class="input_text" />
2367
					<div class="smalltext block">', $txt['user_settings_admin_email_info'], '</div>
2368
				</td>
2369
			</tr><tr>
2370
				<td valign="top" class="textbox"><label for="server_email">', $txt['user_settings_server_email'], ':</label></td>
2371
				<td>
2372
					<input type="text" name="server_email" id="server_email" value="', $incontext['server_email'], '" size="40" class="input_text" />
2373
					<div class="smalltext block">', $txt['user_settings_server_email_info'], '</div>
2374
				</td>
2375
			</tr>
2376
		</table>';
2377
2378
	if ($incontext['require_db_confirm'])
2379
		echo '
2380
		<h2>', $txt['user_settings_database'], '</h2>
2381
		<p>', $txt['user_settings_database_info'], '</p>
2382
2383
		<div style="margin-bottom: 2ex; padding-', $txt['lang_rtl'] == false ? 'left' : 'right', ': 50px;">
2384
			<input type="password" name="password3" size="30" class="input_password" />
2385
		</div>';
2386
}
2387
2388
// Tell them it's done, and to delete.
2389
function template_delete_install()
2390
{
2391
	global $incontext, $installurl, $txt, $boardurl;
2392
2393
	echo '
2394
		<p>', $txt['congratulations_help'], '</p>';
2395
2396
	template_warning_divs();
2397
2398
	// Install directory still writable?
2399
	if ($incontext['dir_still_writable'])
2400
		echo '
2401
		<em>', $txt['still_writable'], '</em><br>
2402
		<br>';
2403
2404
	// Don't show the box if it's like 99% sure it won't work :P.
2405
	if ($incontext['probably_delete_install'])
2406
		echo '
2407
		<div style="margin: 1ex; font-weight: bold;">
2408
			<label for="delete_self"><input type="checkbox" id="delete_self" onclick="doTheDelete();" class="input_check" /> ', $txt['delete_installer'], !isset($_SESSION['installer_temp_ftp']) ? ' ' . $txt['delete_installer_maybe'] : '', '</label>
2409
		</div>
2410
		<script>
2411
			function doTheDelete()
2412
			{
2413
				var theCheck = document.getElementById ? document.getElementById("delete_self") : document.all.delete_self;
2414
				var tempImage = new Image();
2415
2416
				tempImage.src = "', $installurl, '?delete=1&ts_" + (new Date().getTime());
2417
				tempImage.width = 0;
2418
				theCheck.disabled = true;
2419
			}
2420
		</script>
2421
		<br>';
2422
2423
	echo '
2424
		', sprintf($txt['go_to_your_forum'], $boardurl . '/index.php'), '<br>
2425
		<br>
2426
		', $txt['good_luck'];
2427
}
2428
2429
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
2430