Completed
Push — release-2.1 ( cc489b...7ebe8b )
by John
08:38
created

install.php ➔ template_install_above()   C

Complexity

Conditions 13
Paths 4

Size

Total Lines 75
Code Lines 28

Duplication

Lines 3
Ratio 4 %

Importance

Changes 0
Metric Value
cc 13
eloc 28
nc 4
nop 0
dl 3
loc 75
rs 5.3314
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
	if (isset($_POST['stats']) && (strpos($_POST['boardurl'], 'http://localhost') !== 0 || strpos($_POST['boardurl'], 'https://localhost') !== 0))
1220
	{
1221
		// Attempt to register the site etc.
1222
		$fp = @fsockopen("www.simplemachines.org", 80, $errno, $errstr);
1223
		if ($fp)
1224
		{
1225
			$out = "GET /smf/stats/register_stats.php?site=" . base64_encode($_POST['boardurl']) . " HTTP/1.1\r\n";
1226
			$out .= "Host: www.simplemachines.org\r\n";
1227
			$out .= "Connection: Close\r\n\r\n";
1228
			fwrite($fp, $out);
1229
1230
			$return_data = '';
1231
			while (!feof($fp))
1232
				$return_data .= fgets($fp, 128);
1233
1234
			fclose($fp);
1235
1236
			// Get the unique site ID.
1237
			preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1238
1239
			if (!empty($ID[1]))
1240
				$newSettings[] = array('allow_sm_stats', $ID[1]);
1241
		}
1242
	}
1243
1244
	// Are we enabling SSL?
1245
	if (!empty($_POST['force_ssl']))
1246
		$newSettings[] = array('force_ssl', 2);
1247
1248
	// Setting a timezone is required.
1249
	if (!isset($modSettings['default_timezone']) && function_exists('date_default_timezone_set'))
1250
	{
1251
		// Get PHP's default timezone, if set
1252
		$ini_tz = ini_get('date.timezone');
1253
		if (!empty($ini_tz))
1254
			$timezone_id = $ini_tz;
1255
		else
1256
			$timezone_id = '';
1257
1258
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
1259 View Code Duplication
		if (!in_array($timezone_id, timezone_identifiers_list()))
1260
		{
1261
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
1262
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
1263
		}
1264
1265
		if (date_default_timezone_set($timezone_id))
1266
			$newSettings[] = array('default_timezone', $timezone_id);
1267
	}
1268
1269
	if (!empty($newSettings))
1270
	{
1271
		$smcFunc['db_insert']('replace',
1272
			'{db_prefix}settings',
1273
			array('variable' => 'string-255', 'value' => 'string-65534'),
1274
			$newSettings,
1275
			array('variable')
1276
		);
1277
	}
1278
1279
	// Let's optimize those new tables, but not on InnoDB, ok?
1280
	if (!$has_innodb)
1281
	{
1282
		db_extend();
1283
		$tables = $smcFunc['db_list_tables']($db_name, $db_prefix . '%');
1284
		foreach ($tables as $table)
1285
		{
1286
			$smcFunc['db_optimize_table']($table) != -1 or $db_messed = true;
1287
1288
			if (!empty($db_messed))
1289
			{
1290
				$incontext['failures'][-1] = $smcFunc['db_error']();
1291
				break;
1292
			}
1293
		}
1294
	}
1295
1296
	// MySQL specific stuff
1297
	if (substr($db_type, 0, 5) != 'mysql')
1298
		return false;
1299
1300
	// Find database user privileges.
1301
	$privs = array();
1302
	$get_privs = $smcFunc['db_query']('', 'SHOW PRIVILEGES', array());
1303
	while ($row = $smcFunc['db_fetch_assoc']($get_privs))
1304
	{
1305
		if ($row['Privilege'] == 'Alter')
1306
			$privs[] = $row['Privilege'];
1307
	}
1308
	$smcFunc['db_free_result']($get_privs);
1309
1310
	// Check for the ALTER privilege.
1311
	if (!empty($databases[$db_type]['alter_support']) && !in_array('Alter', $privs))
1312
	{
1313
		$incontext['error'] = $txt['error_db_alter_priv'];
1314
		return false;
1315
	}
1316
1317
	if (!empty($exists))
1318
	{
1319
		$incontext['page_title'] = $txt['user_refresh_install'];
1320
		$incontext['was_refresh'] = true;
1321
	}
1322
1323
	return false;
1324
}
1325
1326
// Ask for the administrator login information.
1327
function AdminAccount()
1328
{
1329
	global $txt, $db_type, $smcFunc, $incontext, $db_prefix, $db_passwd, $sourcedir, $db_character_set;
1330
1331
	$incontext['sub_template'] = 'admin_account';
1332
	$incontext['page_title'] = $txt['user_settings'];
1333
	$incontext['continue'] = 1;
1334
1335
	// Skipping?
1336
	if (!empty($_POST['skip']))
1337
		return true;
1338
1339
	// Need this to check whether we need the database password.
1340
	require(dirname(__FILE__) . '/Settings.php');
1341
	load_database();
1342
1343
	require_once($sourcedir . '/Subs-Auth.php');
1344
1345
	require_once($sourcedir . '/Subs.php');
1346
1347
	// We need this to properly hash the password for Admin
1348 View Code Duplication
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' : function($string) {
1349
			global $sourcedir;
1350
			if (function_exists('mb_strtolower'))
1351
				return mb_strtolower($string, 'UTF-8');
1352
			require_once($sourcedir . '/Subs-Charset.php');
1353
			return utf8_strtolower($string);
1354
		};
1355
1356
	if (!isset($_POST['username']))
1357
		$_POST['username'] = '';
1358
	if (!isset($_POST['email']))
1359
		$_POST['email'] = '';
1360
	if (!isset($_POST['server_email']))
1361
		$_POST['server_email'] = '';
1362
1363
	$incontext['username'] = htmlspecialchars(stripslashes($_POST['username']));
1364
	$incontext['email'] = htmlspecialchars(stripslashes($_POST['email']));
1365
	$incontext['server_email'] = htmlspecialchars(stripslashes($_POST['server_email']));
1366
1367
	$incontext['require_db_confirm'] = empty($db_type);
1368
1369
	// Only allow skipping if we think they already have an account setup.
1370
	$request = $smcFunc['db_query']('', '
1371
		SELECT id_member
1372
		FROM {db_prefix}members
1373
		WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
1374
		LIMIT 1',
1375
		array(
1376
			'db_error_skip' => true,
1377
			'admin_group' => 1,
1378
		)
1379
	);
1380
	if ($smcFunc['db_num_rows']($request) != 0)
1381
		$incontext['skip'] = 1;
1382
	$smcFunc['db_free_result']($request);
1383
1384
	// Trying to create an account?
1385
	if (isset($_POST['password1']) && !empty($_POST['contbutt']))
1386
	{
1387
		// Wrong password?
1388
		if ($incontext['require_db_confirm'] && $_POST['password3'] != $db_passwd)
1389
		{
1390
			$incontext['error'] = $txt['error_db_connect'];
1391
			return false;
1392
		}
1393
		// Not matching passwords?
1394
		if ($_POST['password1'] != $_POST['password2'])
1395
		{
1396
			$incontext['error'] = $txt['error_user_settings_again_match'];
1397
			return false;
1398
		}
1399
		// No password?
1400
		if (strlen($_POST['password1']) < 4)
1401
		{
1402
			$incontext['error'] = $txt['error_user_settings_no_password'];
1403
			return false;
1404
		}
1405
		if (!file_exists($sourcedir . '/Subs.php'))
1406
		{
1407
			$incontext['error'] = $txt['error_subs_missing'];
1408
			return false;
1409
		}
1410
1411
		// Update the webmaster's email?
1412
		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...
1413
			updateSettingsFile(array('webmaster_email' => $_POST['server_email']));
1414
1415
		// Work out whether we're going to have dodgy characters and remove them.
1416
		$invalid_characters = preg_match('~[<>&"\'=\\\]~', $_POST['username']) != 0;
1417
		$_POST['username'] = preg_replace('~[<>&"\'=\\\]~', '', $_POST['username']);
1418
1419
		$result = $smcFunc['db_query']('', '
1420
			SELECT id_member, password_salt
1421
			FROM {db_prefix}members
1422
			WHERE member_name = {string:username} OR email_address = {string:email}
1423
			LIMIT 1',
1424
			array(
1425
				'username' => stripslashes($_POST['username']),
1426
				'email' => stripslashes($_POST['email']),
1427
				'db_error_skip' => true,
1428
			)
1429
		);
1430
		if ($smcFunc['db_num_rows']($result) != 0)
1431
		{
1432
			list ($incontext['member_id'], $incontext['member_salt']) = $smcFunc['db_fetch_row']($result);
1433
			$smcFunc['db_free_result']($result);
1434
1435
			$incontext['account_existed'] = $txt['error_user_settings_taken'];
1436
		}
1437
		elseif ($_POST['username'] == '' || strlen($_POST['username']) > 25)
1438
		{
1439
			// Try the previous step again.
1440
			$incontext['error'] = $_POST['username'] == '' ? $txt['error_username_left_empty'] : $txt['error_username_too_long'];
1441
			return false;
1442
		}
1443
		elseif ($invalid_characters || $_POST['username'] == '_' || $_POST['username'] == '|' || strpos($_POST['username'], '[code') !== false || strpos($_POST['username'], '[/code') !== false)
1444
		{
1445
			// Try the previous step again.
1446
			$incontext['error'] = $txt['error_invalid_characters_username'];
1447
			return false;
1448
		}
1449 View Code Duplication
		elseif (empty($_POST['email']) || !filter_var(stripslashes($_POST['email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['email'])) > 255)
1450
		{
1451
			// One step back, this time fill out a proper admin email address.
1452
			$incontext['error'] = sprintf($txt['error_valid_admin_email_needed'], $_POST['username']);
1453
			return false;
1454
		}
1455 View Code Duplication
		elseif (empty($_POST['server_email']) || !filter_var(stripslashes($_POST['server_email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['server_email'])) > 255)
1456
		{
1457
			// One step back, this time fill out a proper admin email address.
1458
			$incontext['error'] = $txt['error_valid_server_email_needed'];
1459
			return false;
1460
		}
1461
		elseif ($_POST['username'] != '')
1462
		{
1463
			$incontext['member_salt'] = substr(md5(mt_rand()), 0, 4);
1464
1465
			// Format the username properly.
1466
			$_POST['username'] = preg_replace('~[\t\n\r\x0B\0\xA0]+~', ' ', $_POST['username']);
1467
			$ip = isset($_SERVER['REMOTE_ADDR']) ? substr($_SERVER['REMOTE_ADDR'], 0, 255) : '';
1468
1469
			$_POST['password1'] = hash_password(stripslashes($_POST['username']), stripslashes($_POST['password1']));
1470
1471
			$incontext['member_id'] = $smcFunc['db_insert']('',
1472
				$db_prefix . 'members',
1473
				array(
1474
					'member_name' => 'string-25', 'real_name' => 'string-25', 'passwd' => 'string', 'email_address' => 'string',
1475
					'id_group' => 'int', 'posts' => 'int', 'date_registered' => 'int',
1476
					'password_salt' => 'string', 'lngfile' => 'string', 'personal_text' => 'string', 'avatar' => 'string',
1477
					'member_ip' => 'inet', 'member_ip2' => 'inet', 'buddy_list' => 'string', 'pm_ignore_list' => 'string',
1478
					'website_title' => 'string', 'website_url' => 'string',
1479
					'signature' => 'string', 'usertitle' => 'string', 'secret_question' => 'string',
1480
					'additional_groups' => 'string', 'ignore_boards' => 'string',
1481
				),
1482
				array(
1483
					stripslashes($_POST['username']), stripslashes($_POST['username']), $_POST['password1'], stripslashes($_POST['email']),
1484
					1, 0, time(),
1485
					$incontext['member_salt'], '', '', '',
1486
					$ip, $ip, '', '',
1487
					'', '',
1488
					'', '', '',
1489
					'', '',
1490
				),
1491
				array('id_member'),
1492
				1
1493
			);
1494
		}
1495
1496
		// If we're here we're good.
1497
		return true;
1498
	}
1499
1500
	return false;
1501
}
1502
1503
// Final step, clean up and a complete message!
1504
function DeleteInstall()
1505
{
1506
	global $smcFunc, $db_character_set, $context, $txt, $incontext;
1507
	global $current_smf_version, $databases, $sourcedir, $forum_version, $modSettings, $user_info, $db_type;
1508
1509
	$incontext['page_title'] = $txt['congratulations'];
1510
	$incontext['sub_template'] = 'delete_install';
1511
	$incontext['continue'] = 0;
1512
1513
	require(dirname(__FILE__) . '/Settings.php');
1514
	load_database();
1515
1516
	chdir(dirname(__FILE__));
1517
1518
	require_once($sourcedir . '/Errors.php');
1519
	require_once($sourcedir . '/Logging.php');
1520
	require_once($sourcedir . '/Subs.php');
1521
	require_once($sourcedir . '/Load.php');
1522
	require_once($sourcedir . '/Security.php');
1523
	require_once($sourcedir . '/Subs-Auth.php');
1524
1525
	// Bring a warning over.
1526
	if (!empty($incontext['account_existed']))
1527
		$incontext['warning'] = $incontext['account_existed'];
1528
1529 View Code Duplication
	if (!empty($db_character_set) && !empty($databases[$db_type]['utf8_support']))
1530
		$smcFunc['db_query']('', '
1531
			SET NAMES {string:db_character_set}',
1532
			array(
1533
				'db_character_set' => $db_character_set,
1534
				'db_error_skip' => true,
1535
			)
1536
		);
1537
1538
	// As track stats is by default enabled let's add some activity.
1539
	$smcFunc['db_insert']('ignore',
1540
		'{db_prefix}log_activity',
1541
		array('date' => 'date', 'topics' => 'int', 'posts' => 'int', 'registers' => 'int'),
1542
		array(strftime('%Y-%m-%d', time()), 1, 1, (!empty($incontext['member_id']) ? 1 : 0)),
1543
		array('date')
1544
	);
1545
1546
	// We're going to want our lovely $modSettings now.
1547
	$request = $smcFunc['db_query']('', '
1548
		SELECT variable, value
1549
		FROM {db_prefix}settings',
1550
		array(
1551
			'db_error_skip' => true,
1552
		)
1553
	);
1554
	// Only proceed if we can load the data.
1555
	if ($request)
1556
	{
1557 View Code Duplication
		while ($row = $smcFunc['db_fetch_row']($request))
1558
			$modSettings[$row[0]] = $row[1];
1559
		$smcFunc['db_free_result']($request);
1560
	}
1561
1562
	// Automatically log them in ;)
1563
	if (isset($incontext['member_id']) && isset($incontext['member_salt']))
1564
		setLoginCookie(3153600 * 60, $incontext['member_id'], hash_salt($_POST['password1'], $incontext['member_salt']));
1565
1566
	$result = $smcFunc['db_query']('', '
1567
		SELECT value
1568
		FROM {db_prefix}settings
1569
		WHERE variable = {string:db_sessions}',
1570
		array(
1571
			'db_sessions' => 'databaseSession_enable',
1572
			'db_error_skip' => true,
1573
		)
1574
	);
1575 View Code Duplication
	if ($smcFunc['db_num_rows']($result) != 0)
1576
		list ($db_sessions) = $smcFunc['db_fetch_row']($result);
1577
	$smcFunc['db_free_result']($result);
1578
1579
	if (empty($db_sessions))
1580
		$_SESSION['admin_time'] = time();
1581
	else
1582
	{
1583
		$_SERVER['HTTP_USER_AGENT'] = substr($_SERVER['HTTP_USER_AGENT'], 0, 211);
1584
1585
		$smcFunc['db_insert']('replace',
1586
			'{db_prefix}sessions',
1587
			array(
1588
				'session_id' => 'string', 'last_update' => 'int', 'data' => 'string',
1589
			),
1590
			array(
1591
				session_id(), time(), 'USER_AGENT|s:' . strlen($_SERVER['HTTP_USER_AGENT']) . ':"' . $_SERVER['HTTP_USER_AGENT'] . '";admin_time|i:' . time() . ';',
1592
			),
1593
			array('session_id')
1594
		);
1595
	}
1596
1597
	updateStats('member');
1598
	updateStats('message');
1599
	updateStats('topic');
1600
1601
	// This function is needed to do the updateStats('subject') call.
1602
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' :
1603 View Code Duplication
		function($string){
1604
			global $sourcedir;
1605
			if (function_exists('mb_strtolower'))
1606
				return mb_strtolower($string, 'UTF-8');
1607
			require_once($sourcedir . '/Subs-Charset.php');
1608
			return utf8_strtolower($string);
1609
		};
1610
1611
	$request = $smcFunc['db_query']('', '
1612
		SELECT id_msg
1613
		FROM {db_prefix}messages
1614
		WHERE id_msg = 1
1615
			AND modified_time = 0
1616
		LIMIT 1',
1617
		array(
1618
			'db_error_skip' => true,
1619
		)
1620
	);
1621
	$context['utf8'] = $db_character_set === 'utf8' || $txt['lang_character_set'] === 'UTF-8';
1622
	if ($smcFunc['db_num_rows']($request) > 0)
1623
		updateStats('subject', 1, htmlspecialchars($txt['default_topic_subject']));
1624
	$smcFunc['db_free_result']($request);
1625
1626
	// Now is the perfect time to fetch the SM files.
1627
	require_once($sourcedir . '/ScheduledTasks.php');
1628
	// Sanity check that they loaded earlier!
1629
	if (isset($modSettings['recycle_board']))
1630
	{
1631
		$forum_version = $current_smf_version; // The variable is usually defined in index.php so lets just use our variable to do it for us.
1632
		scheduled_fetchSMfiles(); // Now go get those files!
1633
1634
		// We've just installed!
1635
		$user_info['ip'] = $_SERVER['REMOTE_ADDR'];
1636
		$user_info['id'] = isset($incontext['member_id']) ? $incontext['member_id'] : 0;
1637
		logAction('install', array('version' => $forum_version), 'admin');
1638
	}
1639
1640
	// Check if we need some stupid MySQL fix.
1641
	$server_version = $smcFunc['db_server_info']();
1642 View Code Duplication
	if (($db_type == 'mysql' || $db_type == 'mysqli') && in_array(substr($server_version, 0, 6), array('5.0.50', '5.0.51')))
1643
		updateSettings(array('db_mysql_group_by_fix' => '1'));
1644
1645
	// Some final context for the template.
1646
	$incontext['dir_still_writable'] = is_writable(dirname(__FILE__)) && substr(__FILE__, 1, 2) != ':\\';
1647
	$incontext['probably_delete_install'] = isset($_SESSION['installer_temp_ftp']) || is_writable(dirname(__FILE__)) || is_writable(__FILE__);
1648
1649
	// Update hash's cost to an appropriate setting
1650
	updateSettings(array(
1651
		'bcrypt_hash_cost' => hash_benchmark(),
1652
	));
1653
1654
	return false;
1655
}
1656
1657
function updateSettingsFile($vars)
1658
{
1659
	// Modify Settings.php.
1660
	$settingsArray = file(dirname(__FILE__) . '/Settings.php');
1661
1662
	// @todo Do we just want to read the file in clean, and split it this way always?
1663
	if (count($settingsArray) == 1)
1664
		$settingsArray = preg_split('~[\r\n]~', $settingsArray[0]);
1665
1666
	for ($i = 0, $n = count($settingsArray); $i < $n; $i++)
1667
	{
1668
		// Remove the redirect...
1669
		if (trim($settingsArray[$i]) == 'if (file_exists(dirname(__FILE__) . \'/install.php\'))' && trim($settingsArray[$i + 1]) == '{' && trim($settingsArray[$i + 3]) == '}')
1670
		{
1671
			// Get the four lines to nothing.
1672
			$settingsArray[$i] = '';
1673
			$settingsArray[++$i] = '';
1674
			$settingsArray[++$i] = '';
1675
			$settingsArray[++$i] = '';
1676
			continue;
1677
		}
1678
1679
		if (trim($settingsArray[$i]) == '?' . '>')
1680
			$settingsArray[$i] = '';
1681
1682
		// Don't trim or bother with it if it's not a variable.
1683
		if (substr($settingsArray[$i], 0, 1) != '$')
1684
			continue;
1685
1686
		$settingsArray[$i] = rtrim($settingsArray[$i]) . "\n";
1687
1688
		foreach ($vars as $var => $val)
1689
			if (strncasecmp($settingsArray[$i], '$' . $var, 1 + strlen($var)) == 0)
1690
			{
1691
				$comment = strstr($settingsArray[$i], '#');
1692
				$settingsArray[$i] = '$' . $var . ' = \'' . $val . '\';' . ($comment != '' ? "\t\t" . $comment : "\n");
1693
				unset($vars[$var]);
1694
			}
1695
	}
1696
1697
	// Uh oh... the file wasn't empty... was it?
1698
	if (!empty($vars))
1699
	{
1700
		$settingsArray[$i++] = '';
1701
		foreach ($vars as $var => $val)
1702
			$settingsArray[$i++] = '$' . $var . ' = \'' . $val . '\';' . "\n";
1703
	}
1704
1705
	// Blank out the file - done to fix a oddity with some servers.
1706
	$fp = @fopen(dirname(__FILE__) . '/Settings.php', 'w');
1707
	if (!$fp)
1708
		return false;
1709
	fclose($fp);
1710
1711
	$fp = fopen(dirname(__FILE__) . '/Settings.php', 'r+');
1712
1713
	// Gotta have one of these ;)
1714
	if (trim($settingsArray[0]) != '<?php')
1715
		fwrite($fp, "<?php\n");
1716
1717
	$lines = count($settingsArray);
1718
	for ($i = 0; $i < $lines - 1; $i++)
1719
	{
1720
		// Don't just write a bunch of blank lines.
1721
		if ($settingsArray[$i] != '' || @$settingsArray[$i - 1] != '')
1722
			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 1027
  1. Read from $_GET, and $changes is assigned
    in other/upgrade.php on line 1027
  2. $changes is passed to updateSettingsFile()
    in other/upgrade.php on line 1104
  3. $var is assigned
    in other/install.php on line 1701
  4. $settingsArray is assigned
    in other/install.php on line 1702
  5. $settingsArray[$i] is passed through strtr()
    in other/install.php on line 1722
  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 1037
  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 1037
  2. $changes is assigned
    in other/upgrade.php on line 1038
  3. $changes is passed to updateSettingsFile()
    in other/upgrade.php on line 1104
  4. $var is assigned
    in other/install.php on line 1701
  5. $settingsArray is assigned
    in other/install.php on line 1702
  6. $settingsArray[$i] is passed through strtr()
    in other/install.php on line 1722
  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 1038
  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 1038
  2. $changes is passed to updateSettingsFile()
    in other/upgrade.php on line 1104
  3. $var is assigned
    in other/install.php on line 1701
  4. $settingsArray is assigned
    in other/install.php on line 1702
  5. $settingsArray[$i] is passed through strtr()
    in other/install.php on line 1722
  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 1064
  1. Read from $_POST, and $_POST[$config_var][0] is passed through addcslashes(), and $new_settings is assigned
    in Sources/ManageServer.php on line 1064
  2. $new_settings is passed to updateSettingsFile()
    in Sources/ManageServer.php on line 1098
  3. $var is assigned
    in other/install.php on line 1701
  4. $settingsArray is assigned
    in other/install.php on line 1702
  5. $settingsArray[$i] is passed through strtr()
    in other/install.php on line 1722
  5. Path: Read from $_POST, and $_POST[$config_var] is passed through addcslashes(), and $new_settings is assigned in Sources/ManageServer.php on line 1068
  1. Read from $_POST, and $_POST[$config_var] is passed through addcslashes(), and $new_settings is assigned
    in Sources/ManageServer.php on line 1068
  2. $new_settings is passed to updateSettingsFile()
    in Sources/ManageServer.php on line 1098
  3. $var is assigned
    in other/install.php on line 1701
  4. $settingsArray is assigned
    in other/install.php on line 1702
  5. $settingsArray[$i] is passed through strtr()
    in other/install.php on line 1722

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...
1723
	}
1724
	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 1027
  1. Read from $_GET, and $changes is assigned
    in other/upgrade.php on line 1027
  2. $changes is passed to updateSettingsFile()
    in other/upgrade.php on line 1104
  3. $var is assigned
    in other/install.php on line 1701
  4. $settingsArray is assigned
    in other/install.php on line 1702
  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 1037
  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 1037
  2. $changes is assigned
    in other/upgrade.php on line 1038
  3. $changes is passed to updateSettingsFile()
    in other/upgrade.php on line 1104
  4. $var is assigned
    in other/install.php on line 1701
  5. $settingsArray is assigned
    in other/install.php on line 1702
  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 1038
  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 1038
  2. $changes is passed to updateSettingsFile()
    in other/upgrade.php on line 1104
  3. $var is assigned
    in other/install.php on line 1701
  4. $settingsArray is assigned
    in other/install.php on line 1702
  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 1064
  1. Read from $_POST, and $_POST[$config_var][0] is passed through addcslashes(), and $new_settings is assigned
    in Sources/ManageServer.php on line 1064
  2. $new_settings is passed to updateSettingsFile()
    in Sources/ManageServer.php on line 1098
  3. $var is assigned
    in other/install.php on line 1701
  4. $settingsArray is assigned
    in other/install.php on line 1702
  5. Path: Read from $_POST, and $_POST[$config_var] is passed through addcslashes(), and $new_settings is assigned in Sources/ManageServer.php on line 1068
  1. Read from $_POST, and $_POST[$config_var] is passed through addcslashes(), and $new_settings is assigned
    in Sources/ManageServer.php on line 1068
  2. $new_settings is passed to updateSettingsFile()
    in Sources/ManageServer.php on line 1098
  3. $var is assigned
    in other/install.php on line 1701
  4. $settingsArray is assigned
    in other/install.php on line 1702

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