Completed
Push — release-2.1 ( c5fac3...040693 )
by Mert
39:33
created

install.php ➔ initialize_inputs()   D

Complexity

Conditions 10
Paths 12

Size

Total Lines 125
Code Lines 43

Duplication

Lines 13
Ratio 10.4 %

Importance

Changes 0
Metric Value
cc 10
eloc 43
nc 12
nop 0
dl 13
loc 125
rs 4.8196
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.3.8';
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' => true,
40
		'utf8_version' => '5.0.3',
41
		'utf8_version_check' => 'return mysqli_get_server_info($db_connection);',
42
		'utf8_default' => true,
43
		'utf8_required' => true,
44
		'alter_support' => true,
45
		'validate_prefix' => function(&$value) {
46
			$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
47
			return true;
48
		},
49
	),
50
	'postgresql' => array(
51
		'name' => 'PostgreSQL',
52
		'version' => '9.1',
53
		'function_check' => 'pg_connect',
54
		'version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
55
		'supported' => function_exists('pg_connect'),
56
		'always_has_db' => true,
57
		'utf8_default' => true,
58
		'utf8_required' => true,
59
		'utf8_support' => true,
60
		'utf8_version' => '8.0',
61
		'utf8_version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
62
		'validate_prefix' => function(&$value) {
63
			$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
64
65
			// Is it reserved?
66
			if ($value == 'pg_')
67
				return $txt['error_db_prefix_reserved'];
0 ignored issues
show
Bug introduced by
The variable $txt 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...
68
69
			// Is the prefix numeric?
70
			if (preg_match('~^\d~', $value))
71
				return $txt['error_db_prefix_numeric'];
72
73
			return true;
74
		},
75
	),
76
);
77
78
// Initialize everything and load the language files.
79
initialize_inputs();
80
load_lang_file();
81
82
// This is what we are.
83
$installurl = $_SERVER['PHP_SELF'];
84
// This is where SMF is.
85
$smfsite = 'http://www.simplemachines.org/smf';
86
87
// All the steps in detail.
88
// Number,Name,Function,Progress Weight.
89
$incontext['steps'] = array(
90
	0 => array(1, $txt['install_step_welcome'], 'Welcome', 0),
91
	1 => array(2, $txt['install_step_writable'], 'CheckFilesWritable', 10),
92
	2 => array(3, $txt['install_step_databaseset'], 'DatabaseSettings', 15),
93
	3 => array(4, $txt['install_step_forum'], 'ForumSettings', 40),
94
	4 => array(5, $txt['install_step_databasechange'], 'DatabasePopulation', 15),
95
	5 => array(6, $txt['install_step_admin'], 'AdminAccount', 20),
96
	6 => array(7, $txt['install_step_delete'], 'DeleteInstall', 0),
97
);
98
99
// Default title...
100
$incontext['page_title'] = $txt['smf_installer'];
101
102
// What step are we on?
103
$incontext['current_step'] = isset($_GET['step']) ? (int) $_GET['step'] : 0;
104
105
// Loop through all the steps doing each one as required.
106
$incontext['overall_percent'] = 0;
107
108
foreach ($incontext['steps'] as $num => $step)
109
{
110
	if ($num >= $incontext['current_step'])
111
	{
112
		// The current weight of this step in terms of overall progress.
113
		$incontext['step_weight'] = $step[3];
114
		// Make sure we reset the skip button.
115
		$incontext['skip'] = false;
116
117
		// Call the step and if it returns false that means pause!
118 View Code Duplication
		if (function_exists($step[2]) && $step[2]() === false)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
119
			break;
120
		elseif (function_exists($step[2]))
121
			$incontext['current_step']++;
122
123
		// No warnings pass on.
124
		$incontext['warning'] = '';
125
	}
126
	$incontext['overall_percent'] += $step[3];
127
}
128
129
// Actually do the template stuff.
130
installExit();
131
132
function initialize_inputs()
133
{
134
	global $databases, $incontext;
135
136
	// Just so people using older versions of PHP aren't left in the cold.
137
	if (!isset($_SERVER['PHP_SELF']))
138
		$_SERVER['PHP_SELF'] = isset($GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']) ? $GLOBALS['HTTP_SERVER_VARS']['PHP_SELF'] : 'install.php';
139
140
	// Turn off magic quotes runtime and enable error reporting.
141
	if (function_exists('set_magic_quotes_runtime'))
142
		@set_magic_quotes_runtime(0);
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...
143
	error_reporting(E_ALL);
144
145
	// Fun.  Low PHP version...
146
	if (!isset($_GET))
147
	{
148
		$GLOBALS['_GET']['step'] = 0;
149
		return;
150
	}
151
152
	if (!isset($_GET['obgz']))
153
	{
154
		ob_start();
155
156
		if (ini_get('session.save_handler') == 'user')
157
			@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...
158
		if (function_exists('session_start'))
159
			@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...
160
	}
161
	else
162
	{
163
		ob_start('ob_gzhandler');
164
165
		if (ini_get('session.save_handler') == 'user')
166
			@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...
167
		session_start();
168
169
		if (!headers_sent())
170
			echo '<!DOCTYPE html>
171
<html>
172
	<head>
173
		<title>', htmlspecialchars($_GET['pass_string']), '</title>
174
	</head>
175
	<body style="background-color: #d4d4d4; margin-top: 16%; text-align: center; font-size: 16pt;">
176
		<strong>', htmlspecialchars($_GET['pass_string']), '</strong>
177
	</body>
178
</html>';
179
		exit;
180
	}
181
182
	// Anybody home?
183 View Code Duplication
	if (!isset($_GET['xml']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
184
	{
185
		$incontext['remote_files_available'] = false;
186
		$test = @fsockopen('www.simplemachines.org', 80, $errno, $errstr, 1);
187
		if ($test)
188
			$incontext['remote_files_available'] = true;
189
		@fclose($test);
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...
190
	}
191
192
	// Add slashes, as long as they aren't already being added.
193
	if (!function_exists('get_magic_quotes_gpc') || @get_magic_quotes_gpc() == 0)
194
		foreach ($_POST as $k => $v)
195
			if (strpos($k, 'password') === false && strpos($k, 'db_passwd') === false)
196
				$_POST[$k] = addslashes($v);
197
198
	// This is really quite simple; if ?delete is on the URL, delete the installer...
199
	if (isset($_GET['delete']))
200
	{
201
		if (isset($_SESSION['installer_temp_ftp']))
202
		{
203
			$ftp = new ftp_connection($_SESSION['installer_temp_ftp']['server'], $_SESSION['installer_temp_ftp']['port'], $_SESSION['installer_temp_ftp']['username'], $_SESSION['installer_temp_ftp']['password']);
204
			$ftp->chdir($_SESSION['installer_temp_ftp']['path']);
205
206
			$ftp->unlink('install.php');
207
208
			foreach ($databases as $key => $dummy)
209
			{
210
				$type = ($key == 'mysqli') ? 'mysql' : $key;
211
				$ftp->unlink('install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
212
			}
213
214
			$ftp->close();
215
216
			unset($_SESSION['installer_temp_ftp']);
217
		}
218
		else
219
		{
220
			@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...
221
222
			foreach ($databases as $key => $dummy)
223
			{
224
				$type = ($key == 'mysqli') ? 'mysql' : $key;
225
				@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...
226
			}
227
		}
228
229
		// Now just redirect to a blank.png...
230
		header('Location: http://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png');
231
		exit;
232
	}
233
234
	// PHP 5 might cry if we don't do this now.
235
	if (function_exists('date_default_timezone_set'))
236
	{
237
		// Get PHP's default timezone, if set
238
		$ini_tz = ini_get('date.timezone');
239
		if (!empty($ini_tz))
240
			$timezone_id = $ini_tz;
241
		else
242
			$timezone_id = '';
243
244
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
245 View Code Duplication
		if (!in_array($timezone_id, timezone_identifiers_list()))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
246
		{
247
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
248
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
249
		}
250
251
		date_default_timezone_set($timezone_id);
252
	}
253
254
	// Force an integer step, defaulting to 0.
255
	$_GET['step'] = (int) @$_GET['step'];
256
}
257
258
// Load the list of language files, and the current language file.
259
function load_lang_file()
260
{
261
	global $txt, $incontext;
262
263
	$incontext['detected_languages'] = array();
264
265
	// Make sure the languages directory actually exists.
266
	if (file_exists(dirname(__FILE__) . '/Themes/default/languages'))
267
	{
268
		// Find all the "Install" language files in the directory.
269
		$dir = dir(dirname(__FILE__) . '/Themes/default/languages');
270
		while ($entry = $dir->read())
271
		{
272
			if (substr($entry, 0, 8) == 'Install.' && substr($entry, -4) == '.php')
273
				$incontext['detected_languages'][$entry] = ucfirst(substr($entry, 8, strlen($entry) - 12));
274
		}
275
		$dir->close();
276
	}
277
278
	// Didn't find any, show an error message!
279
	if (empty($incontext['detected_languages']))
280
	{
281
		// Let's not cache this message, eh?
282
		header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
283
		header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
284
		header('Cache-Control: no-cache');
285
286
		echo '<!DOCTYPE html>
287
<html>
288
	<head>
289
		<title>SMF Installer: Error!</title>
290
	</head>
291
	<body style="font-family: sans-serif;"><div style="width: 600px;">
292
		<h1 style="font-size: 14pt;">A critical error has occurred.</h1>
293
294
		<p>This installer was unable to find the installer\'s language file or files.  They should be found under:</p>
295
296
		<div style="margin: 1ex; font-family: monospace; font-weight: bold;">', dirname($_SERVER['PHP_SELF']) != '/' ? dirname($_SERVER['PHP_SELF']) : '', '/Themes/default/languages</div>
297
298
		<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>
299
		<p>If that doesn\'t help, please make sure this install.php file is in the same place as the Themes folder.</p>
300
301
		<p>If you continue to get this error message, feel free to <a href="http://support.simplemachines.org/">look to us for support</a>.</p>
302
	</div></body>
303
</html>';
304
		die;
305
	}
306
307
	// Override the language file?
308
	if (isset($_GET['lang_file']))
309
		$_SESSION['installer_temp_lang'] = $_GET['lang_file'];
310
	elseif (isset($GLOBALS['HTTP_GET_VARS']['lang_file']))
311
		$_SESSION['installer_temp_lang'] = $GLOBALS['HTTP_GET_VARS']['lang_file'];
312
313
	// Make sure it exists, if it doesn't reset it.
314
	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']))
315
	{
316
		// Use the first one...
317
		list ($_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
318
319
		// If we have english and some other language, use the other language.  We Americans hate english :P.
320
		if ($_SESSION['installer_temp_lang'] == 'Install.english.php' && count($incontext['detected_languages']) > 1)
321
			list (, $_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
322
	}
323
324
	// And now include the actual language file itself.
325
	require_once(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']);
326
}
327
328
// This handy function loads some settings and the like.
329
function load_database()
330
{
331
	global $db_prefix, $db_connection, $sourcedir;
332
	global $smcFunc, $modSettings, $db_type, $db_name, $db_user, $db_persist;
333
334
	if (empty($sourcedir))
335
		$sourcedir = dirname(__FILE__) . '/Sources';
336
337
	// Need this to check whether we need the database password.
338
	require(dirname(__FILE__) . '/Settings.php');
339
	if (!defined('SMF'))
340
		define('SMF', 1);
341
	if (empty($smcFunc))
342
		$smcFunc = array();
343
344
	$modSettings['disableQueryCheck'] = true;
345
346
	// Connect the database.
347
	if (!$db_connection)
348
	{
349
		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
350
		if (version_compare(PHP_VERSION, '5', '<'))
351
			require_once($sourcedir . '/Subs-Compat.php');
352
353
		$db_options = array('persist' => $db_persist);
354
		$port = '';
355
356
		// Figure out the port...
357
		if (!empty($_POST['db_port']))
358
		{
359
			if ($db_type == 'mysql')
360
			{
361
				$port = ((int) $_POST['db_port'] == ini_get($db_type . 'default_port')) ? '' : (int) $_POST['db_port'];
362
			}
363 View Code Duplication
			elseif ($db_type == 'postgresql')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
364
			{
365
				// PostgreSQL doesn't have a default port setting in php.ini, so just check against the default
366
				$port = ((int) $_POST['db_port'] == 5432) ? '' : (int) $_POST['db_port'];
367
			}
368
		}
369
370
		if (!empty($port))
371
			$db_options['port'] = $port;
372
373
		if (!$db_connection)
374
			$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options);
0 ignored issues
show
Bug introduced by
The variable $db_server 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...
Bug introduced by
The variable $db_passwd 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...
375
	}
376
}
377
378
// This is called upon exiting the installer, for template etc.
379
function installExit($fallThrough = false)
380
{
381
	global $incontext, $installurl, $txt;
382
383
	// Send character set.
384
	header('Content-Type: text/html; charset=' . (isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8'));
385
386
	// We usually dump our templates out.
387
	if (!$fallThrough)
388
	{
389
		// The top install bit.
390
		template_install_above();
391
392
		// Call the template.
393
		if (isset($incontext['sub_template']))
394
		{
395
			$incontext['form_url'] = $installurl . '?step=' . $incontext['current_step'];
396
397
			call_user_func('template_' . $incontext['sub_template']);
398
		}
399
		// @todo REMOVE THIS!!
400
		else
401
		{
402
			if (function_exists('doStep' . $_GET['step']))
403
				call_user_func('doStep' . $_GET['step']);
404
		}
405
		// Show the footer.
406
		template_install_below();
407
	}
408
409
	// Bang - gone!
410
	die();
411
}
412
413
function Welcome()
414
{
415
	global $incontext, $txt, $databases, $installurl;
416
417
	$incontext['page_title'] = $txt['install_welcome'];
418
	$incontext['sub_template'] = 'welcome_message';
419
420
	// Done the submission?
421
	if (isset($_POST['contbutt']))
422
		return true;
423
424
	// See if we think they have already installed it?
425
	if (is_readable(dirname(__FILE__) . '/Settings.php'))
426
	{
427
		$probably_installed = 0;
428
		foreach (file(dirname(__FILE__) . '/Settings.php') as $line)
429
		{
430
			if (preg_match('~^\$db_passwd\s=\s\'([^\']+)\';$~', $line))
431
				$probably_installed++;
432
			if (preg_match('~^\$boardurl\s=\s\'([^\']+)\';~', $line) && !preg_match('~^\$boardurl\s=\s\'http://127\.0\.0\.1/smf\';~', $line))
433
				$probably_installed++;
434
		}
435
436
		if ($probably_installed == 2)
437
			$incontext['warning'] = $txt['error_already_installed'];
438
	}
439
440
	// Is some database support even compiled in?
441
	$incontext['supported_databases'] = array();
442
	foreach ($databases as $key => $db)
443
	{
444
		if ($db['supported'])
445
		{
446
			$type = ($key == 'mysqli') ? 'mysql' : $key;
447
			if (!file_exists(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql'))
448
			{
449
				$databases[$key]['supported'] = false;
450
				$notFoundSQLFile = true;
451
				$txt['error_db_script_missing'] = sprintf($txt['error_db_script_missing'], 'install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
452
			}
453
			else
454
				$incontext['supported_databases'][] = $db;
455
		}
456
	}
457
458
	// Check the PHP version.
459
	if ((!function_exists('version_compare') || version_compare($GLOBALS['required_php_version'], PHP_VERSION, '>')))
460
		$error = 'error_php_too_low';
461
	// Make sure we have a supported database
462
	elseif (empty($incontext['supported_databases']))
463
		$error = empty($notFoundSQLFile) ? 'error_db_missing' : 'error_db_script_missing';
464
	// How about session support?  Some crazy sysadmin remove it?
465
	elseif (!function_exists('session_start'))
466
		$error = 'error_session_missing';
467
	// Make sure they uploaded all the files.
468
	elseif (!file_exists(dirname(__FILE__) . '/index.php'))
469
		$error = 'error_missing_files';
470
	// Very simple check on the session.save_path for Windows.
471
	// @todo Move this down later if they don't use database-driven sessions?
472
	elseif (@ini_get('session.save_path') == '/tmp' && substr(__FILE__, 1, 2) == ':\\')
473
		$error = 'error_session_save_path';
474
475
	// Since each of the three messages would look the same, anyway...
476
	if (isset($error))
477
		$incontext['error'] = $txt[$error];
478
479
	// Mod_security blocks everything that smells funny. Let SMF handle security.
480
	if (!fixModSecurity() && !isset($_GET['overmodsecurity']))
481
		$incontext['error'] = $txt['error_mod_security'] . '<br><br><a href="' . $installurl . '?overmodsecurity=true">' . $txt['error_message_click'] . '</a> ' . $txt['error_message_bad_try_again'];
482
483
	return false;
484
}
485
486
function CheckFilesWritable()
487
{
488
	global $txt, $incontext, $sourcedir;
489
490
	$incontext['page_title'] = $txt['ftp_checking_writable'];
491
	$incontext['sub_template'] = 'chmod_files';
492
493
	$writable_files = array(
494
		'attachments',
495
		'avatars',
496
		'custom_avatar',
497
		'cache',
498
		'Packages',
499
		'Smileys',
500
		'Themes',
501
		'agreement.txt',
502
		'Settings.php',
503
		'Settings_bak.php',
504
	);
505
506
	foreach ($incontext['detected_languages'] as $lang => $temp)
507
		$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...
508
509
	// With mod_security installed, we could attempt to fix it with .htaccess.
510
	if (function_exists('apache_get_modules') && in_array('mod_security', apache_get_modules()))
511
		$writable_files[] = file_exists(dirname(__FILE__) . '/.htaccess') ? '.htaccess' : '.';
512
513
	$failed_files = array();
514
515
	// On linux, it's easy - just use is_writable!
516
	if (substr(__FILE__, 1, 2) != ':\\')
517
	{
518
		$incontext['systemos'] = 'linux';
519
520
		foreach ($writable_files as $file)
521
		{
522
			if (!is_writable(dirname(__FILE__) . '/' . $file))
523
			{
524
				@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...
525
526
				// Well, 755 hopefully worked... if not, try 777.
527
				if (!is_writable(dirname(__FILE__) . '/' . $file) && !@chmod(dirname(__FILE__) . '/' . $file, 0777))
528
					$failed_files[] = $file;
529
			}
530
		}
531 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...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
532
			@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...
533
	}
534
	// Windows is trickier.  Let's try opening for r+...
535
	else
536
	{
537
		$incontext['systemos'] = 'windows';
538
539
		foreach ($writable_files as $file)
540
		{
541
			// Folders can't be opened for write... but the index.php in them can ;)
542
			if (is_dir(dirname(__FILE__) . '/' . $file))
543
				$file .= '/index.php';
544
545
			// Funny enough, chmod actually does do something on windows - it removes the read only attribute.
546
			@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...
547
			$fp = @fopen(dirname(__FILE__) . '/' . $file, 'r+');
548
549
			// Hmm, okay, try just for write in that case...
550
			if (!is_resource($fp))
551
				$fp = @fopen(dirname(__FILE__) . '/' . $file, 'w');
552
553
			if (!is_resource($fp))
554
				$failed_files[] = $file;
555
556
			@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...
557
		}
558 View Code Duplication
		foreach ($extra_files as $file)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
559
			@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...
560
	}
561
562
	$failure = count($failed_files) >= 1;
563
564
	if (!isset($_SERVER))
565
		return !$failure;
566
567
	// Put the list into context.
568
	$incontext['failed_files'] = $failed_files;
569
570
	// It's not going to be possible to use FTP on windows to solve the problem...
571
	if ($failure && substr(__FILE__, 1, 2) == ':\\')
572
	{
573
		$incontext['error'] = $txt['error_windows_chmod'] . '
574
					<ul style="margin: 2.5ex; font-family: monospace;">
575
						<li>' . implode('</li>
576
						<li>', $failed_files) . '</li>
577
					</ul>';
578
579
		return false;
580
	}
581
	// We're going to have to use... FTP!
582
	elseif ($failure)
583
	{
584
		// Load any session data we might have...
585 View Code Duplication
		if (!isset($_POST['ftp_username']) && isset($_SESSION['installer_temp_ftp']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
586
		{
587
			$_POST['ftp_server'] = $_SESSION['installer_temp_ftp']['server'];
588
			$_POST['ftp_port'] = $_SESSION['installer_temp_ftp']['port'];
589
			$_POST['ftp_username'] = $_SESSION['installer_temp_ftp']['username'];
590
			$_POST['ftp_password'] = $_SESSION['installer_temp_ftp']['password'];
591
			$_POST['ftp_path'] = $_SESSION['installer_temp_ftp']['path'];
592
		}
593
594
		$incontext['ftp_errors'] = array();
595
		require_once($sourcedir . '/Class-Package.php');
596 View Code Duplication
		if (isset($_POST['ftp_username']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
597
		{
598
			$ftp = new ftp_connection($_POST['ftp_server'], $_POST['ftp_port'], $_POST['ftp_username'], $_POST['ftp_password']);
599
600
			if ($ftp->error === false)
601
			{
602
				// Try it without /home/abc just in case they messed up.
603
				if (!$ftp->chdir($_POST['ftp_path']))
604
				{
605
					$incontext['ftp_errors'][] = $ftp->last_message;
606
					$ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $_POST['ftp_path']));
607
				}
608
			}
609
		}
610
611
		if (!isset($ftp) || $ftp->error !== false)
612
		{
613
			if (!isset($ftp))
614
				$ftp = new ftp_connection(null);
615
			// Save the error so we can mess with listing...
616
			elseif ($ftp->error !== false && empty($incontext['ftp_errors']) && !empty($ftp->last_message))
617
				$incontext['ftp_errors'][] = $ftp->last_message;
618
619
			list ($username, $detect_path, $found_path) = $ftp->detect_path(dirname(__FILE__));
620
621
			if (empty($_POST['ftp_path']) && $found_path)
622
				$_POST['ftp_path'] = $detect_path;
623
624
			if (!isset($_POST['ftp_username']))
625
				$_POST['ftp_username'] = $username;
626
627
			// Set the username etc, into context.
628
			$incontext['ftp'] = array(
629
				'server' => isset($_POST['ftp_server']) ? $_POST['ftp_server'] : 'localhost',
630
				'port' => isset($_POST['ftp_port']) ? $_POST['ftp_port'] : '21',
631
				'username' => isset($_POST['ftp_username']) ? $_POST['ftp_username'] : '',
632
				'path' => isset($_POST['ftp_path']) ? $_POST['ftp_path'] : '/',
633
				'path_msg' => !empty($found_path) ? $txt['ftp_path_found_info'] : $txt['ftp_path_info'],
634
			);
635
636
			return false;
637
		}
638
		else
639
		{
640
			$_SESSION['installer_temp_ftp'] = array(
641
				'server' => $_POST['ftp_server'],
642
				'port' => $_POST['ftp_port'],
643
				'username' => $_POST['ftp_username'],
644
				'password' => $_POST['ftp_password'],
645
				'path' => $_POST['ftp_path']
646
			);
647
648
			$failed_files_updated = array();
649
650
			foreach ($failed_files as $file)
651
			{
652
				if (!is_writable(dirname(__FILE__) . '/' . $file))
653
					$ftp->chmod($file, 0755);
654
				if (!is_writable(dirname(__FILE__) . '/' . $file))
655
					$ftp->chmod($file, 0777);
656
				if (!is_writable(dirname(__FILE__) . '/' . $file))
657
				{
658
					$failed_files_updated[] = $file;
659
					$incontext['ftp_errors'][] = rtrim($ftp->last_message) . ' -> ' . $file . "\n";
660
				}
661
			}
662
663
			$ftp->close();
664
665
			// Are there any errors left?
666
			if (count($failed_files_updated) >= 1)
667
			{
668
				// Guess there are...
669
				$incontext['failed_files'] = $failed_files_updated;
670
671
				// Set the username etc, into context.
672
				$incontext['ftp'] = $_SESSION['installer_temp_ftp'] += array(
673
					'path_msg' => $txt['ftp_path_info'],
674
				);
675
676
				return false;
677
			}
678
		}
679
	}
680
681
	return true;
682
}
683
684
function DatabaseSettings()
685
{
686
	global $txt, $databases, $incontext, $smcFunc, $sourcedir;
687
688
	$incontext['sub_template'] = 'database_settings';
689
	$incontext['page_title'] = $txt['db_settings'];
690
	$incontext['continue'] = 1;
691
692
	// Set up the defaults.
693
	$incontext['db']['server'] = 'localhost';
694
	$incontext['db']['user'] = '';
695
	$incontext['db']['name'] = '';
696
	$incontext['db']['pass'] = '';
697
	$incontext['db']['type'] = '';
698
	$incontext['supported_databases'] = array();
699
700
	$foundOne = false;
701
	foreach ($databases as $key => $db)
702
	{
703
		// Override with the defaults for this DB if appropriate.
704
		if ($db['supported'])
705
		{
706
			$incontext['supported_databases'][$key] = $db;
707
708
			if (!$foundOne)
709
			{
710
				if (isset($db['default_host']))
711
					$incontext['db']['server'] = ini_get($db['default_host']) or $incontext['db']['server'] = 'localhost';
712
				if (isset($db['default_user']))
713
				{
714
					$incontext['db']['user'] = ini_get($db['default_user']);
715
					$incontext['db']['name'] = ini_get($db['default_user']);
716
				}
717
				if (isset($db['default_password']))
718
					$incontext['db']['pass'] = ini_get($db['default_password']);
719
720
				// For simplicity and less confusion, leave the port blank by default
721
				$incontext['db']['port'] = '';
722
723
				$incontext['db']['type'] = $key;
724
				$foundOne = true;
725
			}
726
		}
727
	}
728
729
	// Override for repost.
730
	if (isset($_POST['db_user']))
731
	{
732
		$incontext['db']['user'] = $_POST['db_user'];
733
		$incontext['db']['name'] = $_POST['db_name'];
734
		$incontext['db']['server'] = $_POST['db_server'];
735
		$incontext['db']['prefix'] = $_POST['db_prefix'];
736
737
		if (!empty($_POST['db_port']))
738
			$incontext['db']['port'] = $_POST['db_port'];
739
	}
740
	else
741
	{
742
		$incontext['db']['prefix'] = 'smf_';
743
	}
744
745
	// Are we submitting?
746
	if (isset($_POST['db_type']))
747
	{
748
		// What type are they trying?
749
		$db_type = preg_replace('~[^A-Za-z0-9]~', '', $_POST['db_type']);
750
		$db_prefix = $_POST['db_prefix'];
751
		// Validate the prefix.
752
		$valid_prefix = $databases[$db_type]['validate_prefix']($db_prefix);
753
754
		if ($valid_prefix !== true)
755
		{
756
			$incontext['error'] = $valid_prefix;
757
			return false;
758
		}
759
760
		// Take care of these variables...
761
		$vars = array(
762
			'db_type' => $db_type,
763
			'db_name' => $_POST['db_name'],
764
			'db_user' => $_POST['db_user'],
765
			'db_passwd' => isset($_POST['db_passwd']) ? $_POST['db_passwd'] : '',
766
			'db_server' => $_POST['db_server'],
767
			'db_prefix' => $db_prefix,
768
			// The cookiename is special; we want it to be the same if it ever needs to be reinstalled with the same info.
769
			'cookiename' => 'SMFCookie' . abs(crc32($_POST['db_name'] . preg_replace('~[^A-Za-z0-9_$]~', '', $_POST['db_prefix'])) % 1000),
770
		);
771
772
		// Only set the port if we're not using the default
773
		if (!empty($_POST['db_port']))
774
		{
775
			// For MySQL, we can get the "default port" from PHP. PostgreSQL has no such option though.
776
			if (($db_type == 'mysql' || $db_type == 'mysqli') && $_POST['db_port'] != ini_get($db_type . '.default_port'))
777
				$vars['db_port'] = (int) $_POST['db_port'];
778 View Code Duplication
			elseif ($db_type == 'postgresql' && $_POST['db_port'] != 5432)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
779
				$vars['db_port'] = (int) $_POST['db_port'];
780
		}
781
782
		// God I hope it saved!
783 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
784
		{
785
			$incontext['error'] = $txt['error_windows_chmod'];
786
			return false;
787
		}
788
789
		// Make sure it works.
790
		require(dirname(__FILE__) . '/Settings.php');
791
792
		if (empty($sourcedir))
793
			$sourcedir = dirname(__FILE__) . '/Sources';
794
795
		// Better find the database file!
796
		if (!file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php'))
797
		{
798
			$incontext['error'] = sprintf($txt['error_db_file'], 'Subs-Db-' . $db_type . '.php');
799
			return false;
800
		}
801
802
		// Now include it for database functions!
803
		if (!defined('SMF'))
804
			define('SMF', 1);
805
806
		$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...
807
		if (empty($smcFunc))
808
			$smcFunc = array();
809
810
			require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
811
812
		// What - running PHP4? The shame!
813
		if (version_compare(PHP_VERSION, '5', '<'))
814
			require_once($sourcedir . '/Subs-Compat.php');
815
816
		// Attempt a connection.
817
		$needsDB = !empty($databases[$db_type]['always_has_db']);
818
		$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('non_fatal' => true, 'dont_select_db' => !$needsDB));
0 ignored issues
show
Bug introduced by
The variable $db_server 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...
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
Bug introduced by
The variable $db_user seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
Bug introduced by
The variable $db_passwd 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...
819
820
		// No dice?  Let's try adding the prefix they specified, just in case they misread the instructions ;)
821
		if ($db_connection == null)
822
		{
823
			$db_error = @$smcFunc['db_error']();
824
825
			$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));
0 ignored issues
show
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
Bug introduced by
The variable $db_user seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
826
			if ($db_connection != null)
827
			{
828
				$db_user = $_POST['db_prefix'] . $db_user;
0 ignored issues
show
Bug introduced by
The variable $db_user seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
829
				updateSettingsFile(array('db_user' => $db_user));
830
			}
831
		}
832
833
		// Still no connection?  Big fat error message :P.
834
		if (!$db_connection)
835
		{
836
			$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...
837
			return false;
838
		}
839
840
		// Do they meet the install requirements?
841
		// @todo Old client, new server?
842
		if (version_compare($databases[$db_type]['version'], preg_replace('~^\D*|\-.+?$~', '', eval($databases[$db_type]['version_check']))) > 0)
843
		{
844
			$incontext['error'] = $txt['error_db_too_low'];
845
			return false;
846
		}
847
848
		// Let's try that database on for size... assuming we haven't already lost the opportunity.
849
		if ($db_name != '' && !$needsDB)
850
		{
851
			$smcFunc['db_query']('', "
852
				CREATE DATABASE IF NOT EXISTS `$db_name`",
0 ignored issues
show
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
853
				array(
854
					'security_override' => true,
855
					'db_error_skip' => true,
856
				),
857
				$db_connection
858
			);
859
860
			// Okay, let's try the prefix if it didn't work...
861
			if (!$smcFunc['db_select_db']($db_name, $db_connection) && $db_name != '')
0 ignored issues
show
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
862
			{
863
				$smcFunc['db_query']('', "
864
					CREATE DATABASE IF NOT EXISTS `$_POST[db_prefix]$db_name`",
0 ignored issues
show
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
865
					array(
866
						'security_override' => true,
867
						'db_error_skip' => true,
868
					),
869
					$db_connection
870
				);
871
872
				if ($smcFunc['db_select_db']($_POST['db_prefix'] . $db_name, $db_connection))
0 ignored issues
show
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
873
				{
874
					$db_name = $_POST['db_prefix'] . $db_name;
0 ignored issues
show
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
875
					updateSettingsFile(array('db_name' => $db_name));
876
				}
877
			}
878
879
			// Okay, now let's try to connect...
880
			if (!$smcFunc['db_select_db']($db_name, $db_connection))
881
			{
882
				$incontext['error'] = sprintf($txt['error_db_database'], $db_name);
0 ignored issues
show
Bug introduced by
The variable $db_name 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...
883
				return false;
884
			}
885
		}
886
887
		return true;
888
	}
889
890
	return false;
891
}
892
893
// Let's start with basic forum type settings.
894
function ForumSettings()
895
{
896
	global $txt, $incontext, $databases, $db_type, $db_connection;
897
898
	$incontext['sub_template'] = 'forum_settings';
899
	$incontext['page_title'] = $txt['install_settings'];
900
901
	// Let's see if we got the database type correct.
902
	if (isset($_POST['db_type'], $databases[$_POST['db_type']]))
903
		$db_type = $_POST['db_type'];
904
905
	// Else we'd better be able to get the connection.
906
	else
907
		load_database();
908
909
	$db_type = isset($_POST['db_type']) ? $_POST['db_type'] : $db_type;
910
911
	// What host and port are we on?
912
	$host = empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST'];
913
914
	// Now, to put what we've learned together... and add a path.
915
	$incontext['detected_url'] = 'http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . $host . substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
916
917
	// Check if the database sessions will even work.
918
	$incontext['test_dbsession'] = (ini_get('session.auto_start') != 1);
919
	$incontext['utf8_default'] = $databases[$db_type]['utf8_default'];
920
	$incontext['utf8_required'] = $databases[$db_type]['utf8_required'];
921
922
	$incontext['continue'] = 1;
923
924
	// Submitting?
925
	if (isset($_POST['boardurl']))
926
	{
927 View Code Duplication
		if (substr($_POST['boardurl'], -10) == '/index.php')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
928
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -10);
929
		elseif (substr($_POST['boardurl'], -1) == '/')
930
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -1);
931 View Code Duplication
		if (substr($_POST['boardurl'], 0, 7) != 'http://' && substr($_POST['boardurl'], 0, 7) != 'file://' && substr($_POST['boardurl'], 0, 8) != 'https://')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
932
			$_POST['boardurl'] = 'http://' . $_POST['boardurl'];
933
934
		// Save these variables.
935
		$vars = array(
936
			'boardurl' => $_POST['boardurl'],
937
			'boarddir' => addslashes(dirname(__FILE__)),
938
			'sourcedir' => addslashes(dirname(__FILE__)) . '/Sources',
939
			'cachedir' => addslashes(dirname(__FILE__)) . '/cache',
940
			'mbname' => strtr($_POST['mbname'], array('\"' => '"')),
941
			'language' => substr($_SESSION['installer_temp_lang'], 8, -4),
942
			'image_proxy_secret' => substr(sha1(mt_rand()), 0, 20),
943
			'image_proxy_enabled' => !empty($_POST['force_ssl']),
944
		);
945
946
		// Must save!
947 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
948
		{
949
			$incontext['error'] = $txt['error_windows_chmod'];
950
			return false;
951
		}
952
953
		// Make sure it works.
954
		require(dirname(__FILE__) . '/Settings.php');
955
956
		// UTF-8 requires a setting to override the language charset.
957
		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'])))
958
		{
959
			if (!empty($databases[$db_type]['utf8_version_check']) && version_compare($databases[$db_type]['utf8_version'], preg_replace('~\-.+?$~', '', eval($databases[$db_type]['utf8_version_check'])), '>'))
960
			{
961
				$incontext['error'] = sprintf($txt['error_utf8_version'], $databases[$db_type]['utf8_version']);
962
				return false;
963
			}
964
			else
965
				// Set the character set here.
966
				updateSettingsFile(array('db_character_set' => 'utf8'));
967
		}
968
969
		// Good, skip on.
970
		return true;
971
	}
972
973
	return false;
974
}
975
976
// Step one: Do the SQL thang.
977
function DatabasePopulation()
978
{
979
	global $db_character_set, $txt, $db_connection, $smcFunc, $databases, $modSettings, $db_type, $db_prefix, $incontext, $db_name, $boardurl;
980
981
	$incontext['sub_template'] = 'populate_database';
982
	$incontext['page_title'] = $txt['db_populate'];
983
	$incontext['continue'] = 1;
984
985
	// Already done?
986
	if (isset($_POST['pop_done']))
987
		return true;
988
989
	// Reload settings.
990
	require(dirname(__FILE__) . '/Settings.php');
991
	load_database();
992
993
	// Before running any of the queries, let's make sure another version isn't already installed.
994
	$result = $smcFunc['db_query']('', '
995
		SELECT variable, value
996
		FROM {db_prefix}settings',
997
		array(
998
			'db_error_skip' => true,
999
		)
1000
	);
1001
	$newSettings = array();
1002
	$modSettings = array();
1003
	if ($result !== false)
1004
	{
1005 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($result))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1006
			$modSettings[$row['variable']] = $row['value'];
1007
		$smcFunc['db_free_result']($result);
1008
1009
		// Do they match?  If so, this is just a refresh so charge on!
1010
		if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] != $GLOBALS['current_smf_version'])
1011
		{
1012
			$incontext['error'] = $txt['error_versions_do_not_match'];
1013
			return false;
1014
		}
1015
	}
1016
	$modSettings['disableQueryCheck'] = true;
1017
1018
	// If doing UTF8, select it. PostgreSQL requires passing it as a string...
1019 View Code Duplication
	if (!empty($db_character_set) && $db_character_set == 'utf8' && !empty($databases[$db_type]['utf8_support']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1020
		$smcFunc['db_query']('', '
1021
			SET NAMES {string:utf8}',
1022
			array(
1023
				'db_error_skip' => true,
1024
				'utf8' => 'utf8',
1025
			)
1026
		);
1027
1028
	// Windows likes to leave the trailing slash, which yields to C:\path\to\SMF\/attachments...
1029
	if (substr(__DIR__, -1) == '\\')
1030
		$attachdir = __DIR__ . 'attachments';
1031
	else
1032
		$attachdir = __DIR__ . '/attachments';
1033
1034
	$replaces = array(
1035
		'{$db_prefix}' => $db_prefix,
1036
		'{$attachdir}' => json_encode(array(1 => $smcFunc['db_escape_string']($attachdir))),
1037
		'{$boarddir}' => $smcFunc['db_escape_string'](dirname(__FILE__)),
1038
		'{$boardurl}' => $boardurl,
1039
		'{$enableCompressedOutput}' => isset($_POST['compress']) ? '1' : '0',
1040
		'{$databaseSession_enable}' => isset($_POST['dbsession']) ? '1' : '0',
1041
		'{$smf_version}' => $GLOBALS['current_smf_version'],
1042
		'{$current_time}' => time(),
1043
		'{$sched_task_offset}' => 82800 + mt_rand(0, 86399),
1044
		'{$registration_method}' => isset($_POST['reg_mode']) ? $_POST['reg_mode'] : 0,
1045
	);
1046
1047
	foreach ($txt as $key => $value)
1048
	{
1049
		if (substr($key, 0, 8) == 'default_')
1050
			$replaces['{$' . $key . '}'] = $smcFunc['db_escape_string']($value);
1051
	}
1052
	$replaces['{$default_reserved_names}'] = strtr($replaces['{$default_reserved_names}'], array('\\\\n' => '\\n'));
1053
1054
	// MySQL-specific stuff - storage engine and UTF8 handling
1055
	if (substr($db_type, 0, 5) == 'mysql')
1056
	{
1057
		// Just in case the query fails for some reason...
1058
		$engines = array();
1059
1060
		// Figure out storage engines - what do we have, etc.
1061
		$get_engines = $smcFunc['db_query']('', 'SHOW ENGINES', array());
1062
1063 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($get_engines))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1064
		{
1065
			if ($row['Support'] == 'YES' || $row['Support'] == 'DEFAULT')
1066
				$engines[] = $row['Engine'];
1067
		}
1068
1069
		// Done with this now
1070
		$smcFunc['db_free_result']($get_engines);
1071
1072
		// InnoDB is better, so use it if possible...
1073
		$has_innodb = in_array('InnoDB', $engines);
1074
		$replaces['{$engine}'] = $has_innodb ? 'InnoDB' : 'MyISAM';
1075
		$replaces['{$memory}'] = (!$has_innodb && in_array('MEMORY', $engines)) ? 'MEMORY' : $replaces['{$engine}'];
1076
1077
		// If the UTF-8 setting was enabled, add it to the table definitions.
1078
		if (!empty($databases[$db_type]['utf8_support']) && (!empty($databases[$db_type]['utf8_required']) || isset($_POST['utf8'])))
1079
		{
1080
			$replaces['{$engine}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1081
			$replaces['{$memory}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1082
		}
1083
1084
		// One last thing - if we don't have InnoDB, we can't do transactions...
1085
		if (!$has_innodb)
1086
		{
1087
			$replaces['START TRANSACTION;'] = '';
1088
			$replaces['COMMIT;'] = '';
1089
		}
1090
	}
1091
	else
1092
	{
1093
		$has_innodb = false;
1094
	}
1095
1096
	// Read in the SQL.  Turn this on and that off... internationalize... etc.
1097
	$type = ($db_type == 'mysqli' ? 'mysql' : $db_type);
1098
	$sql_lines = explode("\n", strtr(implode(' ', file(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql')), $replaces));
1099
1100
	// Execute the SQL.
1101
	$current_statement = '';
1102
	$exists = array();
1103
	$incontext['failures'] = array();
1104
	$incontext['sql_results'] = array(
1105
		'tables' => 0,
1106
		'inserts' => 0,
1107
		'table_dups' => 0,
1108
		'insert_dups' => 0,
1109
	);
1110
	foreach ($sql_lines as $count => $line)
1111
	{
1112
		// No comments allowed!
1113
		if (substr(trim($line), 0, 1) != '#')
1114
			$current_statement .= "\n" . rtrim($line);
1115
1116
		// Is this the end of the query string?
1117
		if (empty($current_statement) || (preg_match('~;[\s]*$~s', $line) == 0 && $count != count($sql_lines)))
1118
			continue;
1119
1120
		// Does this table already exist?  If so, don't insert more data into it!
1121
		if (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) != 0 && in_array($match[1], $exists))
1122
		{
1123
			preg_match_all('~\)[,;]~', $current_statement, $matches);
1124 View Code Duplication
			if (!empty($matches[0]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1125
				$incontext['sql_results']['insert_dups'] += count($matches[0]);
1126
			else
1127
				$incontext['sql_results']['insert_dups']++;
1128
1129
			$current_statement = '';
1130
			continue;
1131
		}
1132
1133
		if ($smcFunc['db_query']('', $current_statement, array('security_override' => true, 'db_error_skip' => true), $db_connection) === false)
1134
		{
1135
			// Use the appropriate function based on the DB type
1136
			if ($db_type == 'mysql' || $db_type == 'mysqli')
1137
				$db_errorno = $db_type . '_errno';
1138
1139
			// Error 1050: Table already exists!
1140
			// @todo Needs to be made better!
1141
			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...
1142
			{
1143
				$exists[] = $match[1];
1144
				$incontext['sql_results']['table_dups']++;
1145
			}
1146
			// Don't error on duplicate indexes (or duplicate operators in PostgreSQL.)
1147
			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)))
1148
			{
1149
				// MySQLi requires a connection object. It's optional with MySQL and Postgres
1150
				$incontext['failures'][$count] = $smcFunc['db_error']($db_connection);
1151
			}
1152
		}
1153
		else
1154
		{
1155
			if (preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1156
				$incontext['sql_results']['tables']++;
1157
			elseif (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1158
			{
1159
				preg_match_all('~\)[,;]~', $current_statement, $matches);
1160 View Code Duplication
				if (!empty($matches[0]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1161
					$incontext['sql_results']['inserts'] += count($matches[0]);
1162
				else
1163
					$incontext['sql_results']['inserts']++;
1164
			}
1165
		}
1166
1167
		$current_statement = '';
1168
1169
		// Wait, wait, I'm still working here!
1170
		set_time_limit(60);
1171
	}
1172
1173
	// Sort out the context for the SQL.
1174
	foreach ($incontext['sql_results'] as $key => $number)
1175
	{
1176
		if ($number == 0)
1177
			unset($incontext['sql_results'][$key]);
1178
		else
1179
			$incontext['sql_results'][$key] = sprintf($txt['db_populate_' . $key], $number);
1180
	}
1181
1182
	// Make sure UTF will be used globally.
1183
	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'])))
1184
		$newSettings[] = array('global_character_set', 'UTF-8');
1185
1186
	// Maybe we can auto-detect better cookie settings?
1187
	preg_match('~^http[s]?://([^\.]+?)([^/]*?)(/.*)?$~', $boardurl, $matches);
1188
	if (!empty($matches))
1189
	{
1190
		// Default = both off.
1191
		$localCookies = false;
1192
		$globalCookies = false;
1193
1194
		// Okay... let's see.  Using a subdomain other than www.? (not a perfect check.)
1195
		if ($matches[2] != '' && (strpos(substr($matches[2], 1), '.') === false || in_array($matches[1], array('forum', 'board', 'community', 'forums', 'support', 'chat', 'help', 'talk', 'boards', 'www'))))
1196
			$globalCookies = true;
1197
		// If there's a / in the middle of the path, or it starts with ~... we want local.
1198
		if (isset($matches[3]) && strlen($matches[3]) > 3 && (substr($matches[3], 0, 2) == '/~' || strpos(substr($matches[3], 1), '/') !== false))
1199
			$localCookies = true;
1200
1201
		if ($globalCookies)
1202
			$newSettings[] = array('globalCookies', '1');
1203
		if ($localCookies)
1204
			$newSettings[] = array('localCookies', '1');
1205
	}
1206
1207
	// Are we allowing stat collection?
1208
	if (isset($_POST['stats']) && strpos($_POST['boardurl'], 'http://localhost') !== 0)
1209
	{
1210
		// Attempt to register the site etc.
1211
		$fp = @fsockopen("www.simplemachines.org", 80, $errno, $errstr);
1212
		if ($fp)
1213
		{
1214
			$out = "GET /smf/stats/register_stats.php?site=" . base64_encode($_POST['boardurl']) . " HTTP/1.1\r\n";
1215
			$out .= "Host: www.simplemachines.org\r\n";
1216
			$out .= "Connection: Close\r\n\r\n";
1217
			fwrite($fp, $out);
1218
1219
			$return_data = '';
1220
			while (!feof($fp))
1221
				$return_data .= fgets($fp, 128);
1222
1223
			fclose($fp);
1224
1225
			// Get the unique site ID.
1226
			preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1227
1228
			if (!empty($ID[1]))
1229
				$newSettings[] = array('allow_sm_stats', $ID[1]);
1230
		}
1231
	}
1232
1233
	// Are we enabling SSL?
1234
	if (!empty($_POST['force_ssl']))
1235
		$newSettings[] = array('force_ssl', 2);
1236
1237
	// Setting a timezone is required.
1238
	if (!isset($modSettings['default_timezone']) && function_exists('date_default_timezone_set'))
1239
	{
1240
		// Get PHP's default timezone, if set
1241
		$ini_tz = ini_get('date.timezone');
1242
		if (!empty($ini_tz))
1243
			$timezone_id = $ini_tz;
1244
		else
1245
			$timezone_id = '';
1246
1247
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
1248 View Code Duplication
		if (!in_array($timezone_id, timezone_identifiers_list()))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1249
		{
1250
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
1251
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
1252
		}
1253
1254
		if (date_default_timezone_set($timezone_id))
1255
			$newSettings[] = array('default_timezone', $timezone_id);
1256
	}
1257
1258
	if (!empty($newSettings))
1259
	{
1260
		$smcFunc['db_insert']('replace',
1261
			'{db_prefix}settings',
1262
			array('variable' => 'string-255', 'value' => 'string-65534'),
1263
			$newSettings,
1264
			array('variable')
1265
		);
1266
	}
1267
1268
	// Let's optimize those new tables, but not on InnoDB, ok?
1269
	if (!$has_innodb)
1270
	{
1271
		db_extend();
1272
		$tables = $smcFunc['db_list_tables']($db_name, $db_prefix . '%');
1273
		foreach ($tables as $table)
1274
		{
1275
			$smcFunc['db_optimize_table']($table) != -1 or $db_messed = true;
1276
1277
			if (!empty($db_messed))
1278
			{
1279
				$incontext['failures'][-1] = $smcFunc['db_error']();
1280
				break;
1281
			}
1282
		}
1283
	}
1284
1285
	// MySQL specific stuff
1286
	if (substr($db_type, 0, 5) != 'mysql')
1287
		return false;
1288
1289
	// Find database user privileges.
1290
	$privs = array();
1291
	$get_privs = $smcFunc['db_query']('', 'SHOW PRIVILEGES', array());
1292
	while ($row = $smcFunc['db_fetch_assoc']($get_privs))
1293
	{
1294
		if ($row['Privilege'] == 'Alter')
1295
			$privs[] = $row['Privilege'];
1296
	}
1297
	$smcFunc['db_free_result']($get_privs);
1298
1299
	// Check for the ALTER privilege.
1300
	if (!empty($databases[$db_type]['alter_support']) && !in_array('Alter', $privs))
1301
	{
1302
		$incontext['error'] = $txt['error_db_alter_priv'];
1303
		return false;
1304
	}
1305
1306
	if (!empty($exists))
1307
	{
1308
		$incontext['page_title'] = $txt['user_refresh_install'];
1309
		$incontext['was_refresh'] = true;
1310
	}
1311
1312
	return false;
1313
}
1314
1315
// Ask for the administrator login information.
1316
function AdminAccount()
1317
{
1318
	global $txt, $db_type, $db_connection, $smcFunc, $incontext, $db_prefix, $db_passwd, $sourcedir, $db_character_set;
1319
1320
	$incontext['sub_template'] = 'admin_account';
1321
	$incontext['page_title'] = $txt['user_settings'];
1322
	$incontext['continue'] = 1;
1323
1324
	// Skipping?
1325
	if (!empty($_POST['skip']))
1326
		return true;
1327
1328
	// Need this to check whether we need the database password.
1329
	require(dirname(__FILE__) . '/Settings.php');
1330
	load_database();
1331
1332
	require_once($sourcedir . '/Subs-Auth.php');
1333
1334
	require_once($sourcedir . '/Subs.php');
1335
1336
	// We need this to properly hash the password for Admin
1337 View Code Duplication
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' : function($string) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1338
			global $sourcedir;
1339
			if (function_exists('mb_strtolower'))
1340
				return mb_strtolower($string, 'UTF-8');
1341
			require_once($sourcedir . '/Subs-Charset.php');
1342
			return utf8_strtolower($string);
1343
		};
1344
1345
	if (!isset($_POST['username']))
1346
		$_POST['username'] = '';
1347
	if (!isset($_POST['email']))
1348
		$_POST['email'] = '';
1349
	if (!isset($_POST['server_email']))
1350
		$_POST['server_email'] = '';
1351
1352
	$incontext['username'] = htmlspecialchars(stripslashes($_POST['username']));
1353
	$incontext['email'] = htmlspecialchars(stripslashes($_POST['email']));
1354
	$incontext['server_email'] = htmlspecialchars(stripslashes($_POST['server_email']));
1355
1356
	$incontext['require_db_confirm'] = empty($db_type);
1357
1358
	// Only allow skipping if we think they already have an account setup.
1359
	$request = $smcFunc['db_query']('', '
1360
		SELECT id_member
1361
		FROM {db_prefix}members
1362
		WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
1363
		LIMIT 1',
1364
		array(
1365
			'db_error_skip' => true,
1366
			'admin_group' => 1,
1367
		)
1368
	);
1369
	if ($smcFunc['db_num_rows']($request) != 0)
1370
		$incontext['skip'] = 1;
1371
	$smcFunc['db_free_result']($request);
1372
1373
	// Trying to create an account?
1374
	if (isset($_POST['password1']) && !empty($_POST['contbutt']))
1375
	{
1376
		// Wrong password?
1377
		if ($incontext['require_db_confirm'] && $_POST['password3'] != $db_passwd)
1378
		{
1379
			$incontext['error'] = $txt['error_db_connect'];
1380
			return false;
1381
		}
1382
		// Not matching passwords?
1383
		if ($_POST['password1'] != $_POST['password2'])
1384
		{
1385
			$incontext['error'] = $txt['error_user_settings_again_match'];
1386
			return false;
1387
		}
1388
		// No password?
1389
		if (strlen($_POST['password1']) < 4)
1390
		{
1391
			$incontext['error'] = $txt['error_user_settings_no_password'];
1392
			return false;
1393
		}
1394
		if (!file_exists($sourcedir . '/Subs.php'))
1395
		{
1396
			$incontext['error'] = $txt['error_subs_missing'];
1397
			return false;
1398
		}
1399
1400
		// Update the webmaster's email?
1401
		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...
1402
			updateSettingsFile(array('webmaster_email' => $_POST['server_email']));
1403
1404
		// Work out whether we're going to have dodgy characters and remove them.
1405
		$invalid_characters = preg_match('~[<>&"\'=\\\]~', $_POST['username']) != 0;
1406
		$_POST['username'] = preg_replace('~[<>&"\'=\\\]~', '', $_POST['username']);
1407
1408
		$result = $smcFunc['db_query']('', '
1409
			SELECT id_member, password_salt
1410
			FROM {db_prefix}members
1411
			WHERE member_name = {string:username} OR email_address = {string:email}
1412
			LIMIT 1',
1413
			array(
1414
				'username' => stripslashes($_POST['username']),
1415
				'email' => stripslashes($_POST['email']),
1416
				'db_error_skip' => true,
1417
			)
1418
		);
1419
		if ($smcFunc['db_num_rows']($result) != 0)
1420
		{
1421
			list ($incontext['member_id'], $incontext['member_salt']) = $smcFunc['db_fetch_row']($result);
1422
			$smcFunc['db_free_result']($result);
1423
1424
			$incontext['account_existed'] = $txt['error_user_settings_taken'];
1425
		}
1426
		elseif ($_POST['username'] == '' || strlen($_POST['username']) > 25)
1427
		{
1428
			// Try the previous step again.
1429
			$incontext['error'] = $_POST['username'] == '' ? $txt['error_username_left_empty'] : $txt['error_username_too_long'];
1430
			return false;
1431
		}
1432
		elseif ($invalid_characters || $_POST['username'] == '_' || $_POST['username'] == '|' || strpos($_POST['username'], '[code') !== false || strpos($_POST['username'], '[/code') !== false)
1433
		{
1434
			// Try the previous step again.
1435
			$incontext['error'] = $txt['error_invalid_characters_username'];
1436
			return false;
1437
		}
1438 View Code Duplication
		elseif (empty($_POST['email']) || !filter_var(stripslashes($_POST['email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['email'])) > 255)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1439
		{
1440
			// One step back, this time fill out a proper admin email address.
1441
			$incontext['error'] = sprintf($txt['error_valid_admin_email_needed'], $_POST['username']);
1442
			return false;
1443
		}
1444 View Code Duplication
		elseif (empty($_POST['server_email']) || !filter_var(stripslashes($_POST['server_email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['server_email'])) > 255)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1445
		{
1446
			// One step back, this time fill out a proper admin email address.
1447
			$incontext['error'] = $txt['error_valid_server_email_needed'];
1448
			return false;
1449
		}
1450
		elseif ($_POST['username'] != '')
1451
		{
1452
			$incontext['member_salt'] = substr(md5(mt_rand()), 0, 4);
1453
1454
			// Format the username properly.
1455
			$_POST['username'] = preg_replace('~[\t\n\r\x0B\0\xA0]+~', ' ', $_POST['username']);
1456
			$ip = isset($_SERVER['REMOTE_ADDR']) ? substr($_SERVER['REMOTE_ADDR'], 0, 255) : '';
1457
1458
			$_POST['password1'] = hash_password(stripslashes($_POST['username']), stripslashes($_POST['password1']));
1459
1460
			$incontext['member_id'] = $smcFunc['db_insert']('',
1461
				$db_prefix . 'members',
1462
				array(
1463
					'member_name' => 'string-25', 'real_name' => 'string-25', 'passwd' => 'string', 'email_address' => 'string',
1464
					'id_group' => 'int', 'posts' => 'int', 'date_registered' => 'int',
1465
					'password_salt' => 'string', 'lngfile' => 'string', 'personal_text' => 'string', 'avatar' => 'string',
1466
					'member_ip' => 'inet', 'member_ip2' => 'inet', 'buddy_list' => 'string', 'pm_ignore_list' => 'string',
1467
					'website_title' => 'string', 'website_url' => 'string',
1468
					'signature' => 'string', 'usertitle' => 'string', 'secret_question' => 'string',
1469
					'additional_groups' => 'string', 'ignore_boards' => 'string',
1470
				),
1471
				array(
1472
					stripslashes($_POST['username']), stripslashes($_POST['username']), $_POST['password1'], stripslashes($_POST['email']),
1473
					1, 0, time(),
1474
					$incontext['member_salt'], '', '', '',
1475
					$ip, $ip, '', '',
1476
					'', '',
1477
					'', '', '',
1478
					'', '',
1479
				),
1480
				array('id_member'),
1481
				1
1482
			);
1483
		}
1484
1485
		// If we're here we're good.
1486
		return true;
1487
	}
1488
1489
	return false;
1490
}
1491
1492
// Final step, clean up and a complete message!
1493
function DeleteInstall()
1494
{
1495
	global $txt, $incontext;
1496
	global $smcFunc, $db_character_set, $context, $cookiename;
1497
	global $current_smf_version, $databases, $sourcedir, $forum_version, $modSettings, $user_info, $db_type, $boardurl;
1498
1499
	$incontext['page_title'] = $txt['congratulations'];
1500
	$incontext['sub_template'] = 'delete_install';
1501
	$incontext['continue'] = 0;
1502
1503
	require(dirname(__FILE__) . '/Settings.php');
1504
	load_database();
1505
1506
	chdir(dirname(__FILE__));
1507
1508
	require_once($sourcedir . '/Errors.php');
1509
	require_once($sourcedir . '/Logging.php');
1510
	require_once($sourcedir . '/Subs.php');
1511
	require_once($sourcedir . '/Load.php');
1512
	require_once($sourcedir . '/Security.php');
1513
	require_once($sourcedir . '/Subs-Auth.php');
1514
1515
	// Bring a warning over.
1516
	if (!empty($incontext['account_existed']))
1517
		$incontext['warning'] = $incontext['account_existed'];
1518
1519 View Code Duplication
	if (!empty($db_character_set) && !empty($databases[$db_type]['utf8_support']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1520
		$smcFunc['db_query']('', '
1521
			SET NAMES {string:db_character_set}',
1522
			array(
1523
				'db_character_set' => $db_character_set,
1524
				'db_error_skip' => true,
1525
			)
1526
		);
1527
1528
	// As track stats is by default enabled let's add some activity.
1529
	$smcFunc['db_insert']('ignore',
1530
		'{db_prefix}log_activity',
1531
		array('date' => 'date', 'topics' => 'int', 'posts' => 'int', 'registers' => 'int'),
1532
		array(strftime('%Y-%m-%d', time()), 1, 1, (!empty($incontext['member_id']) ? 1 : 0)),
1533
		array('date')
1534
	);
1535
1536
	// We're going to want our lovely $modSettings now.
1537
	$request = $smcFunc['db_query']('', '
1538
		SELECT variable, value
1539
		FROM {db_prefix}settings',
1540
		array(
1541
			'db_error_skip' => true,
1542
		)
1543
	);
1544
	// Only proceed if we can load the data.
1545
	if ($request)
1546
	{
1547
		while ($row = $smcFunc['db_fetch_row']($request))
1548
			$modSettings[$row[0]] = $row[1];
1549
		$smcFunc['db_free_result']($request);
1550
	}
1551
1552
	// Automatically log them in ;)
1553
	if (isset($incontext['member_id']) && isset($incontext['member_salt']))
1554
		setLoginCookie(3153600 * 60, $incontext['member_id'], hash_salt($_POST['password1'], $incontext['member_salt']));
1555
1556
	$result = $smcFunc['db_query']('', '
1557
		SELECT value
1558
		FROM {db_prefix}settings
1559
		WHERE variable = {string:db_sessions}',
1560
		array(
1561
			'db_sessions' => 'databaseSession_enable',
1562
			'db_error_skip' => true,
1563
		)
1564
	);
1565 View Code Duplication
	if ($smcFunc['db_num_rows']($result) != 0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1566
		list ($db_sessions) = $smcFunc['db_fetch_row']($result);
1567
	$smcFunc['db_free_result']($result);
1568
1569
	if (empty($db_sessions))
1570
		$_SESSION['admin_time'] = time();
1571
	else
1572
	{
1573
		$_SERVER['HTTP_USER_AGENT'] = substr($_SERVER['HTTP_USER_AGENT'], 0, 211);
1574
1575
		$smcFunc['db_insert']('replace',
1576
			'{db_prefix}sessions',
1577
			array(
1578
				'session_id' => 'string', 'last_update' => 'int', 'data' => 'string',
1579
			),
1580
			array(
1581
				session_id(), time(), 'USER_AGENT|s:' . strlen($_SERVER['HTTP_USER_AGENT']) . ':"' . $_SERVER['HTTP_USER_AGENT'] . '";admin_time|i:' . time() . ';',
1582
			),
1583
			array('session_id')
1584
		);
1585
	}
1586
1587
	updateStats('member');
1588
	updateStats('message');
1589
	updateStats('topic');
1590
1591
	// This function is needed to do the updateStats('subject') call.
1592
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' :
1593 View Code Duplication
		function($string){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1594
			global $sourcedir;
1595
			if (function_exists('mb_strtolower'))
1596
				return mb_strtolower($string, 'UTF-8');
1597
			require_once($sourcedir . '/Subs-Charset.php');
1598
			return utf8_strtolower($string);
1599
		};
1600
1601
	$request = $smcFunc['db_query']('', '
1602
		SELECT id_msg
1603
		FROM {db_prefix}messages
1604
		WHERE id_msg = 1
1605
			AND modified_time = 0
1606
		LIMIT 1',
1607
		array(
1608
			'db_error_skip' => true,
1609
		)
1610
	);
1611
	$context['utf8'] = $db_character_set === 'utf8' || $txt['lang_character_set'] === 'UTF-8';
1612
	if ($smcFunc['db_num_rows']($request) > 0)
1613
		updateStats('subject', 1, htmlspecialchars($txt['default_topic_subject']));
1614
	$smcFunc['db_free_result']($request);
1615
1616
	// Now is the perfect time to fetch the SM files.
1617
	require_once($sourcedir . '/ScheduledTasks.php');
1618
	// Sanity check that they loaded earlier!
1619
	if (isset($modSettings['recycle_board']))
1620
	{
1621
		$forum_version = $current_smf_version; // The variable is usually defined in index.php so lets just use our variable to do it for us.
1622
		scheduled_fetchSMfiles(); // Now go get those files!
1623
1624
		// We've just installed!
1625
		$user_info['ip'] = $_SERVER['REMOTE_ADDR'];
1626
		$user_info['id'] = isset($incontext['member_id']) ? $incontext['member_id'] : 0;
1627
		logAction('install', array('version' => $forum_version), 'admin');
1628
	}
1629
1630
	// Check if we need some stupid MySQL fix.
1631
	$server_version = $smcFunc['db_server_info']();
1632 View Code Duplication
	if (($db_type == 'mysql' || $db_type == 'mysqli') && in_array(substr($server_version, 0, 6), array('5.0.50', '5.0.51')))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1633
		updateSettings(array('db_mysql_group_by_fix' => '1'));
1634
1635
	// Some final context for the template.
1636
	$incontext['dir_still_writable'] = is_writable(dirname(__FILE__)) && substr(__FILE__, 1, 2) != ':\\';
1637
	$incontext['probably_delete_install'] = isset($_SESSION['installer_temp_ftp']) || is_writable(dirname(__FILE__)) || is_writable(__FILE__);
1638
1639
	// Update hash's cost to an appropriate setting
1640
	updateSettings(array(
1641
		'bcrypt_hash_cost' => hash_benchmark(),
1642
	));
1643
1644
	return false;
1645
}
1646
1647
function updateSettingsFile($vars)
1648
{
1649
	// Modify Settings.php.
1650
	$settingsArray = file(dirname(__FILE__) . '/Settings.php');
1651
1652
	// @todo Do we just want to read the file in clean, and split it this way always?
1653
	if (count($settingsArray) == 1)
1654
		$settingsArray = preg_split('~[\r\n]~', $settingsArray[0]);
1655
1656
	for ($i = 0, $n = count($settingsArray); $i < $n; $i++)
1657
	{
1658
		// Remove the redirect...
1659
		if (trim($settingsArray[$i]) == 'if (file_exists(dirname(__FILE__) . \'/install.php\'))' && trim($settingsArray[$i + 1]) == '{' && trim($settingsArray[$i + 3]) == '}')
1660
		{
1661
			// Get the four lines to nothing.
1662
			$settingsArray[$i] = '';
1663
			$settingsArray[++$i] = '';
1664
			$settingsArray[++$i] = '';
1665
			$settingsArray[++$i] = '';
1666
			continue;
1667
		}
1668
1669
		if (trim($settingsArray[$i]) == '?' . '>')
1670
			$settingsArray[$i] = '';
1671
1672
		// Don't trim or bother with it if it's not a variable.
1673
		if (substr($settingsArray[$i], 0, 1) != '$')
1674
			continue;
1675
1676
		$settingsArray[$i] = rtrim($settingsArray[$i]) . "\n";
1677
1678
		foreach ($vars as $var => $val)
1679
			if (strncasecmp($settingsArray[$i], '$' . $var, 1 + strlen($var)) == 0)
1680
			{
1681
				$comment = strstr($settingsArray[$i], '#');
1682
				$settingsArray[$i] = '$' . $var . ' = \'' . $val . '\';' . ($comment != '' ? "\t\t" . $comment : "\n");
1683
				unset($vars[$var]);
1684
			}
1685
	}
1686
1687
	// Uh oh... the file wasn't empty... was it?
1688
	if (!empty($vars))
1689
	{
1690
		$settingsArray[$i++] = '';
1691
		foreach ($vars as $var => $val)
1692
			$settingsArray[$i++] = '$' . $var . ' = \'' . $val . '\';' . "\n";
1693
	}
1694
1695
	// Blank out the file - done to fix a oddity with some servers.
1696
	$fp = @fopen(dirname(__FILE__) . '/Settings.php', 'w');
1697
	if (!$fp)
1698
		return false;
1699
	fclose($fp);
1700
1701
	$fp = fopen(dirname(__FILE__) . '/Settings.php', 'r+');
1702
1703
	// Gotta have one of these ;)
1704
	if (trim($settingsArray[0]) != '<?php')
1705
		fwrite($fp, "<?php\n");
1706
1707
	$lines = count($settingsArray);
1708
	for ($i = 0; $i < $lines - 1; $i++)
1709
	{
1710
		// Don't just write a bunch of blank lines.
1711
		if ($settingsArray[$i] != '' || @$settingsArray[$i - 1] != '')
1712
			fwrite($fp, strtr($settingsArray[$i], "\r", ''));
1713
	}
1714
	fwrite($fp, $settingsArray[$i] . '?' . '>');
1715
	fclose($fp);
1716
1717
	// Even though on normal installations the filemtime should prevent this being used by the installer incorrectly
1718
	// it seems that there are times it might not. So let's MAKE it dump the cache.
1719
	if (function_exists('opcache_invalidate'))
1720
		opcache_invalidate(dirname(__FILE__) . '/Settings.php', true);
1721
1722
	return true;
1723
}
1724
1725
function updateDbLastError()
1726
{
1727
	// Write out the db_last_error file with the error timestamp
1728
	file_put_contents(dirname(__FILE__) . '/db_last_error.php', '<' . '?' . "php\n" . '$db_last_error = 0;' . "\n" . '?' . '>');
1729
1730
	return true;
1731
}
1732
1733
// Create an .htaccess file to prevent mod_security. SMF has filtering built-in.
1734
function fixModSecurity()
1735
{
1736
	$htaccess_addition = '
1737
<IfModule mod_security.c>
1738
	# Turn off mod_security filtering.  SMF is a big boy, it doesn\'t need its hands held.
1739
	SecFilterEngine Off
1740
1741
	# The below probably isn\'t needed, but better safe than sorry.
1742
	SecFilterScanPOST Off
1743
</IfModule>';
1744
1745
	if (!function_exists('apache_get_modules') || !in_array('mod_security', apache_get_modules()))
1746
		return true;
1747
	elseif (file_exists(dirname(__FILE__) . '/.htaccess') && is_writable(dirname(__FILE__) . '/.htaccess'))
1748
	{
1749
		$current_htaccess = implode('', file(dirname(__FILE__) . '/.htaccess'));
1750
1751
		// Only change something if mod_security hasn't been addressed yet.
1752
		if (strpos($current_htaccess, '<IfModule mod_security.c>') === false)
1753
		{
1754 View Code Duplication
			if ($ht_handle = fopen(dirname(__FILE__) . '/.htaccess', 'a'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1755
			{
1756
				fwrite($ht_handle, $htaccess_addition);
1757
				fclose($ht_handle);
1758
				return true;
1759
			}
1760
			else
1761
				return false;
1762
		}
1763
		else
1764
			return true;
1765
	}
1766
	elseif (file_exists(dirname(__FILE__) . '/.htaccess'))
1767
		return strpos(implode('', file(dirname(__FILE__) . '/.htaccess')), '<IfModule mod_security.c>') !== false;
1768
	elseif (is_writable(dirname(__FILE__)))
1769
	{
1770 View Code Duplication
		if ($ht_handle = fopen(dirname(__FILE__) . '/.htaccess', 'w'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1771
		{
1772
			fwrite($ht_handle, $htaccess_addition);
1773
			fclose($ht_handle);
1774
			return true;
1775
		}
1776
		else
1777
			return false;
1778
	}
1779
	else
1780
		return false;
1781
}
1782
1783
function template_install_above()
1784
{
1785
	global $incontext, $txt, $installurl;
1786
1787
	echo '<!DOCTYPE html>
1788
<html', $txt['lang_rtl'] == true ? ' dir="rtl"' : '', '>
1789
	<head>
1790
		<meta charset="', isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8', '">
1791
		<meta name="robots" content="noindex">
1792
		<title>', $txt['smf_installer'], '</title>
1793
		<link rel="stylesheet" href="Themes/default/css/index.css?alp21">
1794
		<link rel="stylesheet" href="Themes/default/css/install.css?alp21">
1795
		', $txt['lang_rtl'] == true ? '<link rel="stylesheet" href="Themes/default/css/rtl.css?alp21">' : '', '
1796
1797
		<script src="Themes/default/scripts/jquery-3.1.1.min.js"></script>
1798
		<script src="Themes/default/scripts/script.js"></script>
1799
	</head>
1800
	<body><div id="footerfix">
1801
		<div id="header">
1802
			<h1 class="forumtitle">', $txt['smf_installer'], '</h1>
1803
			<img id="smflogo" src="Themes/default/images/smflogo.png" alt="Simple Machines Forum" title="Simple Machines Forum">
1804
		</div>
1805
		<div id="wrapper">
1806
			<div id="upper_section">
1807
				<div id="inner_section">
1808
					<div id="inner_wrap">';
1809
1810
	// Have we got a language drop down - if so do it on the first step only.
1811
	if (!empty($incontext['detected_languages']) && count($incontext['detected_languages']) > 1 && $incontext['current_step'] == 0)
1812
	{
1813
		echo '
1814
						<div class="news">
1815
							<form action="', $installurl, '" method="get">
1816
								<label for="installer_language">', $txt['installer_language'], ':</label>
1817
								<select id="installer_language" name="lang_file" onchange="location.href = \'', $installurl, '?lang_file=\' + this.options[this.selectedIndex].value;">';
1818
1819
		foreach ($incontext['detected_languages'] as $lang => $name)
1820
			echo '
1821
									<option', isset($_SESSION['installer_temp_lang']) && $_SESSION['installer_temp_lang'] == $lang ? ' selected' : '', ' value="', $lang, '">', $name, '</option>';
1822
1823
		echo '
1824
								</select>
1825
								<noscript><input type="submit" value="', $txt['installer_language_set'], '" class="button_submit" /></noscript>
1826
							</form>
1827
						</div>
1828
						<hr class="clear" />';
1829
	}
1830
1831
	echo '
1832
					</div>
1833
				</div>
1834
			</div>
1835
			<div id="content_section">
1836
				<div id="main_content_section">
1837
					<div id="main_steps">
1838
						<h2>', $txt['upgrade_progress'], '</h2>
1839
						<ul>';
1840
1841 View Code Duplication
	foreach ($incontext['steps'] as $num => $step)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1842
		echo '
1843
							<li class="', $num < $incontext['current_step'] ? 'stepdone' : ($num == $incontext['current_step'] ? 'stepcurrent' : 'stepwaiting'), '">', $txt['upgrade_step'], ' ', $step[0], ': ', $step[1], '</li>';
1844
1845
	echo '
1846
						</ul>
1847
					</div>
1848
					<div id="progress_bar">
1849
						<div id="overall_text">', $incontext['overall_percent'], '%</div>
1850
						<div id="overall_progress" style="width: ', $incontext['overall_percent'], '%;">
1851
							<span>'. $txt['upgrade_overall_progress'], '</span>
1852
						</div>
1853
					</div>
1854
					<div id="main_screen" class="clear">
1855
						<h2>', $incontext['page_title'], '</h2>
1856
						<div class="panel">';
1857
}
1858
1859
function template_install_below()
1860
{
1861
	global $incontext, $txt;
1862
1863
	if (!empty($incontext['continue']) || !empty($incontext['skip']))
1864
	{
1865
		echo '
1866
								<div>';
1867
1868
		if (!empty($incontext['continue']))
1869
			echo '
1870
									<input type="submit" id="contbutt" name="contbutt" value="', $txt['upgrade_continue'], '" onclick="return submitThisOnce(this);" class="button_submit" />';
1871
		if (!empty($incontext['skip']))
1872
			echo '
1873
									<input type="submit" id="skip" name="skip" value="', $txt['upgrade_skip'], '" onclick="return submitThisOnce(this);" class="button_submit" />';
1874
		echo '
1875
								</div>';
1876
	}
1877
1878
	// Show the closing form tag and other data only if not in the last step
1879
	if (count($incontext['steps']) - 1 !== (int) $incontext['current_step'])
1880
		echo '
1881
							</form>';
1882
1883
	echo '
1884
						</div>
1885
					</div>
1886
				</div>
1887
			</div>
1888
		</div></div>
1889
		<div id="footer">
1890
			<ul>
1891
				<li class="copyright"><a href="http://www.simplemachines.org/" title="Simple Machines Forum" target="_blank" class="new_win">SMF &copy; 2017, Simple Machines</a></li>
1892
			</ul>
1893
		</div>
1894
	</body>
1895
</html>';
1896
}
1897
1898
// Welcome them to the wonderful world of SMF!
1899
function template_welcome_message()
1900
{
1901
	global $incontext, $txt;
1902
1903
	echo '
1904
	<script src="http://www.simplemachines.org/smf/current-version.js?version=' . $GLOBALS['current_smf_version'] . '"></script>
1905
	<form action="', $incontext['form_url'], '" method="post">
1906
		<p>', sprintf($txt['install_welcome_desc'], $GLOBALS['current_smf_version']), '</p>
1907
		<div id="version_warning" style="margin: 2ex; padding: 2ex; border: 2px dashed #a92174; color: black; background-color: #fbbbe2; display: none;">
1908
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
1909
			<strong style="text-decoration: underline;">', $txt['error_warning_notice'], '</strong><br>
1910
			<div style="padding-left: 6ex;">
1911
				', 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>'), '
1912
			</div>
1913
		</div>';
1914
1915
	// Show the warnings, or not.
1916
	if (template_warning_divs())
1917
		echo '
1918
		<h3>', $txt['install_all_lovely'], '</h3>';
1919
1920
	// Say we want the continue button!
1921
	if (empty($incontext['error']))
1922
		$incontext['continue'] = 1;
1923
1924
	// For the latest version stuff.
1925
	echo '
1926
		<script>
1927
			// Latest version?
1928
			function smfCurrentVersion()
1929
			{
1930
				var smfVer, yourVer;
1931
1932
				if (!(\'smfVersion\' in window))
1933
					return;
1934
1935
				window.smfVersion = window.smfVersion.replace(/SMF\s?/g, \'\');
1936
1937
				smfVer = document.getElementById("smfVersion");
1938
				yourVer = document.getElementById("yourVersion");
1939
1940
				setInnerHTML(smfVer, window.smfVersion);
1941
1942
				var currentVersion = getInnerHTML(yourVer);
1943
				if (currentVersion < window.smfVersion)
1944
					document.getElementById(\'version_warning\').style.display = \'\';
1945
			}
1946
			addLoadEvent(smfCurrentVersion);
1947
		</script>';
1948
}
1949
1950
// A shortcut for any warning stuff.
1951
function template_warning_divs()
1952
{
1953
	global $txt, $incontext;
1954
1955
	// Errors are very serious..
1956
	if (!empty($incontext['error']))
1957
		echo '
1958
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
1959
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
1960
			<strong style="text-decoration: underline;">', $txt['upgrade_critical_error'], '</strong><br>
1961
			<div style="padding-left: 6ex;">
1962
				', $incontext['error'], '
1963
			</div>
1964
		</div>';
1965
	// A warning message?
1966
	elseif (!empty($incontext['warning']))
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_warning'], '</strong><br>
1971
			<div style="padding-left: 6ex;">
1972
				', $incontext['warning'], '
1973
			</div>
1974
		</div>';
1975
1976
	return empty($incontext['error']) && empty($incontext['warning']);
1977
}
1978
1979
function template_chmod_files()
1980
{
1981
	global $txt, $incontext;
1982
1983
	echo '
1984
		<p>', $txt['ftp_setup_why_info'], '</p>
1985
		<ul style="margin: 2.5ex; font-family: monospace;">
1986
			<li>', implode('</li>
1987
			<li>', $incontext['failed_files']), '</li>
1988
		</ul>';
1989
1990
	if (isset($incontext['systemos'], $incontext['detected_path']) && $incontext['systemos'] == 'linux')
1991
		echo '
1992
		<hr>
1993
		<p>', $txt['chmod_linux_info'], '</p>
1994
		<tt># chmod a+w ', implode(' ' . $incontext['detected_path'] . '/', $incontext['failed_files']), '</tt>';
1995
1996
	// This is serious!
1997
	if (!template_warning_divs())
1998
		return;
1999
2000
	echo '
2001
		<hr>
2002
		<p>', $txt['ftp_setup_info'], '</p>';
2003
2004
	if (!empty($incontext['ftp_errors']))
2005
		echo '
2006
		<div class="error_message">
2007
			', $txt['error_ftp_no_connect'], '<br><br>
2008
			<code>', implode('<br>', $incontext['ftp_errors']), '</code>
2009
		</div>
2010
		<br>';
2011
2012
	echo '
2013
		<form action="', $incontext['form_url'], '" method="post">
2014
			<table align="center" style="width: 520px; margin: 1em 0; padding: 0; border: 0">
2015
				<tr>
2016
					<td width="26%" valign="top" class="textbox"><label for="ftp_server">', $txt['ftp_server'], ':</label></td>
2017
					<td>
2018
						<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>
2019
						<input type="text" size="30" name="ftp_server" id="ftp_server" value="', $incontext['ftp']['server'], '" style="width: 70%;" class="input_text" />
2020
						<div class="smalltext block">', $txt['ftp_server_info'], '</div>
2021
					</td>
2022
				</tr><tr>
2023
					<td width="26%" valign="top" class="textbox"><label for="ftp_username">', $txt['ftp_username'], ':</label></td>
2024
					<td>
2025
						<input type="text" size="50" name="ftp_username" id="ftp_username" value="', $incontext['ftp']['username'], '" style="width: 99%;" class="input_text" />
2026
						<div class="smalltext block">', $txt['ftp_username_info'], '</div>
2027
					</td>
2028
				</tr><tr>
2029
					<td width="26%" valign="top" class="textbox"><label for="ftp_password">', $txt['ftp_password'], ':</label></td>
2030
					<td>
2031
						<input type="password" size="50" name="ftp_password" id="ftp_password" style="width: 99%;" class="input_password" />
2032
						<div class="smalltext block">', $txt['ftp_password_info'], '</div>
2033
					</td>
2034
				</tr><tr>
2035
					<td width="26%" valign="top" class="textbox"><label for="ftp_path">', $txt['ftp_path'], ':</label></td>
2036
					<td style="padding-bottom: 1ex;">
2037
						<input type="text" size="50" name="ftp_path" id="ftp_path" value="', $incontext['ftp']['path'], '" style="width: 99%;" class="input_text" />
2038
						<div class="smalltext block">', $incontext['ftp']['path_msg'], '</div>
2039
					</td>
2040
				</tr>
2041
			</table>
2042
			<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>
2043
		</form>
2044
		<a href="', $incontext['form_url'], '">', $txt['error_message_click'], '</a> ', $txt['ftp_setup_again'];
2045
}
2046
2047
// Get the database settings prepared.
2048
function template_database_settings()
2049
{
2050
	global $incontext, $txt;
2051
2052
	echo '
2053
	<form action="', $incontext['form_url'], '" method="post">
2054
		<p>', $txt['db_settings_info'], '</p>';
2055
2056
	template_warning_divs();
2057
2058
	echo '
2059
		<table width="100%" border="0" style="margin: 1em 0;">';
2060
2061
	// More than one database type?
2062
	if (count($incontext['supported_databases']) > 1)
2063
	{
2064
		echo '
2065
			<tr>
2066
				<td width="20%" valign="top" class="textbox"><label for="db_type_input">', $txt['db_settings_type'], ':</label></td>
2067
				<td>
2068
					<select name="db_type" id="db_type_input" onchange="toggleDBInput();">';
2069
2070
	foreach ($incontext['supported_databases'] as $key => $db)
2071
			echo '
2072
						<option value="', $key, '"', isset($_POST['db_type']) && $_POST['db_type'] == $key ? ' selected' : '', '>', $db['name'], '</option>';
2073
2074
	echo '
2075
					</select>
2076
					<div class="smalltext block">', $txt['db_settings_type_info'], '</div>
2077
				</td>
2078
			</tr>';
2079
	}
2080
	else
2081
	{
2082
		echo '
2083
			<tr style="display: none;">
2084
				<td>
2085
					<input type="hidden" name="db_type" value="', $incontext['db']['type'], '" />
2086
				</td>
2087
			</tr>';
2088
	}
2089
2090
	echo '
2091
			<tr id="db_server_contain">
2092
				<td width="20%" valign="top" class="textbox"><label for="db_server_input">', $txt['db_settings_server'], ':</label></td>
2093
				<td>
2094
					<input type="text" name="db_server" id="db_server_input" value="', $incontext['db']['server'], '" size="30" class="input_text" /><br>
2095
					<div class="smalltext block">', $txt['db_settings_server_info'], '</div>
2096
				</td>
2097
			</tr><tr id="db_port_contain">
2098
				<td width="20%" valign="top" class="textbox"><label for="db_port_input">', $txt['db_settings_port'], ':</label></td>
2099
				<td>
2100
					<input type="text" name="db_port" id="db_port_input" value="', $incontext['db']['port'], '"><br>
2101
					<div class="smalltext block">', $txt['db_settings_port_info'], '</div>
2102
				</td>
2103
			</tr><tr id="db_user_contain">
2104
				<td valign="top" class="textbox"><label for="db_user_input">', $txt['db_settings_username'], ':</label></td>
2105
				<td>
2106
					<input type="text" name="db_user" id="db_user_input" value="', $incontext['db']['user'], '" size="30" class="input_text" /><br>
2107
					<div class="smalltext block">', $txt['db_settings_username_info'], '</div>
2108
				</td>
2109
			</tr><tr id="db_passwd_contain">
2110
				<td valign="top" class="textbox"><label for="db_passwd_input">', $txt['db_settings_password'], ':</label></td>
2111
				<td>
2112
					<input type="password" name="db_passwd" id="db_passwd_input" value="', $incontext['db']['pass'], '" size="30" class="input_password" /><br>
2113
					<div class="smalltext block">', $txt['db_settings_password_info'], '</div>
2114
				</td>
2115
			</tr><tr id="db_name_contain">
2116
				<td valign="top" class="textbox"><label for="db_name_input">', $txt['db_settings_database'], ':</label></td>
2117
				<td>
2118
					<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>
2119
					<div class="smalltext block">', $txt['db_settings_database_info'], '
2120
					<span id="db_name_info_warning">', $txt['db_settings_database_info_note'], '</span></div>
2121
				</td>
2122
			</tr><tr id="db_filename_contain" style="display: none;">
2123
				<td valign="top" class="textbox"><label for="db_filename_input">', $txt['db_settings_database_file'], ':</label></td>
2124
				<td>
2125
					<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>
2126
					<div class="smalltext block">', $txt['db_settings_database_file_info'], '</div>
2127
				</td>
2128
			</tr><tr>
2129
				<td valign="top" class="textbox"><label for="db_prefix_input">', $txt['db_settings_prefix'], ':</label></td>
2130
				<td>
2131
					<input type="text" name="db_prefix" id="db_prefix_input" value="', $incontext['db']['prefix'], '" size="30" class="input_text" /><br>
2132
					<div class="smalltext block">', $txt['db_settings_prefix_info'], '</div>
2133
				</td>
2134
			</tr>
2135
		</table>';
2136
2137
	// Toggles a warning related to db names in PostgreSQL
2138
	echo '
2139
	<script>
2140
		function toggleDBInput()
2141
		{
2142
			if (document.getElementById(\'db_type_input\').value == \'postgresql\')
2143
				document.getElementById(\'db_name_info_warning\').style.display = \'none\';
2144
			else
2145
				document.getElementById(\'db_name_info_warning\').style.display = \'\';
2146
		}
2147
		toggleDBInput();
2148
	</script>';
2149
}
2150
2151
// Stick in their forum settings.
2152
function template_forum_settings()
2153
{
2154
	global $incontext, $txt;
2155
2156
	echo '
2157
	<form action="', $incontext['form_url'], '" method="post">
2158
		<h3>', $txt['install_settings_info'], '</h3>';
2159
2160
	template_warning_divs();
2161
2162
	echo '
2163
		<table style="width: 100%; margin: 1em 0;">
2164
			<tr>
2165
				<td class="textbox" style="width: 20%; vertical-align: top;">
2166
					<label for="mbname_input">', $txt['install_settings_name'], ':</label>
2167
				</td>
2168
				<td>
2169
					<input type="text" name="mbname" id="mbname_input" value="', $txt['install_settings_name_default'], '" size="65" class="input_text" />
2170
					<div class="smalltext block">', $txt['install_settings_name_info'], '</div>
2171
				</td>
2172
			</tr>
2173
			<tr>
2174
				<td class="textbox" style="vertical-align: top;">
2175
					<label for="boardurl_input">', $txt['install_settings_url'], ':</label>
2176
				</td>
2177
				<td>
2178
					<input type="text" name="boardurl" id="boardurl_input" value="', $incontext['detected_url'], '" size="65" class="input_text" />
2179
					<br>
2180
					<div class="smalltext block">', $txt['install_settings_url_info'], '</div>
2181
				</td>
2182
			</tr>
2183
			<tr>
2184
				<td class="textbox" style="vertical-align: top;">
2185
					<label for="reg_mode">', $txt['install_settings_reg_mode'], ':</label>
2186
				</td>
2187
				<td>
2188
					<select name="reg_mode" id="reg_mode">
2189
						<optgroup label="', $txt['install_settings_reg_modes'], ':">
2190
							<option value="0" selected>', $txt['install_settings_reg_immediate'], '</option>
2191
							<option value="1">', $txt['install_settings_reg_email'], '</option>
2192
							<option value="2">', $txt['install_settings_reg_admin'], '</option>
2193
							<option value="3">', $txt['install_settings_reg_disabled'], '</option>
2194
						</optgroup>
2195
					</select>
2196
					<br>
2197
					<div class="smalltext block">', $txt['install_settings_reg_mode_info'], '</div>
2198
				</td>
2199
			</tr>
2200
			<tr>
2201
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_compress'], ':</td>
2202
				<td>
2203
					<input type="checkbox" name="compress" id="compress_check" checked class="input_check" />&nbsp;
2204
					<label for="compress_check">', $txt['install_settings_compress_title'], '</label>
2205
					<br>
2206
					<div class="smalltext block">', $txt['install_settings_compress_info'], '</div>
2207
				</td>
2208
			</tr>
2209
			<tr>
2210
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_dbsession'], ':</td>
2211
				<td>
2212
					<input type="checkbox" name="dbsession" id="dbsession_check" checked class="input_check" />&nbsp;
2213
					<label for="dbsession_check">', $txt['install_settings_dbsession_title'], '</label>
2214
					<br>
2215
					<div class="smalltext block">', $incontext['test_dbsession'] ? $txt['install_settings_dbsession_info1'] : $txt['install_settings_dbsession_info2'], '</div>
2216
				</td>
2217
			</tr>
2218
			<tr>
2219
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_utf8'], ':</td>
2220
				<td>
2221
					<input type="checkbox" name="utf8" id="utf8_check"', $incontext['utf8_default'] ? ' checked' : '', ' class="input_check"', $incontext['utf8_required'] ? ' disabled' : '', ' />&nbsp;
2222
					<label for="utf8_check">', $txt['install_settings_utf8_title'], '</label>
2223
					<br>
2224
					<div class="smalltext block">', $txt['install_settings_utf8_info'], '</div>
2225
				</td>
2226
			</tr>
2227
			<tr>
2228
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_stats'], ':</td>
2229
				<td>
2230
					<input type="checkbox" name="stats" id="stats_check" class="input_check" />&nbsp;
2231
					<label for="stats_check">', $txt['install_settings_stats_title'], '</label>
2232
					<br>
2233
					<div class="smalltext block">', $txt['install_settings_stats_info'], '</div>
2234
				</td>
2235
			</tr>
2236
			<tr>
2237
				<td class="textbox" style="vertical-align: top;">', $txt['force_ssl'], ':</td>
2238
				<td>
2239
					<input type="checkbox" name="force_ssl" id="force_ssl" class="input_check" />&nbsp;
2240
					<label for="force_ssl">', $txt['force_ssl_label'], '</label>
2241
					<br>
2242
					<div class="smalltext block">', $txt['force_ssl_info'], '</div>
2243
				</td>
2244
			</tr>
2245
		</table>
2246
	';
2247
}
2248
2249
// Show results of the database population.
2250
function template_populate_database()
2251
{
2252
	global $incontext, $txt;
2253
2254
	echo '
2255
	<form action="', $incontext['form_url'], '" method="post">
2256
		<p>', !empty($incontext['was_refresh']) ? $txt['user_refresh_install_desc'] : $txt['db_populate_info'], '</p>';
2257
2258
	if (!empty($incontext['sql_results']))
2259
	{
2260
		echo '
2261
		<ul>
2262
			<li>', implode('</li><li>', $incontext['sql_results']), '</li>
2263
		</ul>';
2264
	}
2265
2266
	if (!empty($incontext['failures']))
2267
	{
2268
		echo '
2269
				<div style="color: red;">', $txt['error_db_queries'], '</div>
2270
				<ul>';
2271
2272
		foreach ($incontext['failures'] as $line => $fail)
2273
			echo '
2274
						<li><strong>', $txt['error_db_queries_line'], $line + 1, ':</strong> ', nl2br(htmlspecialchars($fail)), '</li>';
2275
2276
		echo '
2277
				</ul>';
2278
	}
2279
2280
	echo '
2281
		<p>', $txt['db_populate_info2'], '</p>';
2282
2283
	template_warning_divs();
2284
2285
	echo '
2286
	<input type="hidden" name="pop_done" value="1" />';
2287
}
2288
2289
// Create the admin account.
2290
function template_admin_account()
2291
{
2292
	global $incontext, $txt;
2293
2294
	echo '
2295
	<form action="', $incontext['form_url'], '" method="post">
2296
		<p>', $txt['user_settings_info'], '</p>';
2297
2298
	template_warning_divs();
2299
2300
	echo '
2301
		<table width="100%" border="0" style="margin: 2em 0;">
2302
			<tr>
2303
				<td width="18%" valign="top" class="textbox"><label for="username">', $txt['user_settings_username'], ':</label></td>
2304
				<td>
2305
					<input type="text" name="username" id="username" value="', $incontext['username'], '" size="40" class="input_text" />
2306
					<div class="smalltext block">', $txt['user_settings_username_info'], '</div>
2307
				</td>
2308
			</tr><tr>
2309
				<td valign="top" class="textbox"><label for="password1">', $txt['user_settings_password'], ':</label></td>
2310
				<td>
2311
					<input type="password" name="password1" id="password1" size="40" class="input_password" />
2312
					<div class="smalltext block">', $txt['user_settings_password_info'], '</div>
2313
				</td>
2314
			</tr><tr>
2315
				<td valign="top" class="textbox"><label for="password2">', $txt['user_settings_again'], ':</label></td>
2316
				<td>
2317
					<input type="password" name="password2" id="password2" size="40" class="input_password" />
2318
					<div class="smalltext block">', $txt['user_settings_again_info'], '</div>
2319
				</td>
2320
			</tr><tr>
2321
				<td valign="top" class="textbox"><label for="email">', $txt['user_settings_admin_email'], ':</label></td>
2322
				<td>
2323
					<input type="text" name="email" id="email" value="', $incontext['email'], '" size="40" class="input_text" />
2324
					<div class="smalltext block">', $txt['user_settings_admin_email_info'], '</div>
2325
				</td>
2326
			</tr><tr>
2327
				<td valign="top" class="textbox"><label for="server_email">', $txt['user_settings_server_email'], ':</label></td>
2328
				<td>
2329
					<input type="text" name="server_email" id="server_email" value="', $incontext['server_email'], '" size="40" class="input_text" />
2330
					<div class="smalltext block">', $txt['user_settings_server_email_info'], '</div>
2331
				</td>
2332
			</tr>
2333
		</table>';
2334
2335
	if ($incontext['require_db_confirm'])
2336
		echo '
2337
		<h2>', $txt['user_settings_database'], '</h2>
2338
		<p>', $txt['user_settings_database_info'], '</p>
2339
2340
		<div style="margin-bottom: 2ex; padding-', $txt['lang_rtl'] == false ? 'left' : 'right', ': 50px;">
2341
			<input type="password" name="password3" size="30" class="input_password" />
2342
		</div>';
2343
}
2344
2345
// Tell them it's done, and to delete.
2346
function template_delete_install()
2347
{
2348
	global $incontext, $installurl, $txt, $boardurl;
2349
2350
	echo '
2351
		<p>', $txt['congratulations_help'], '</p>';
2352
2353
	template_warning_divs();
2354
2355
	// Install directory still writable?
2356
	if ($incontext['dir_still_writable'])
2357
		echo '
2358
		<em>', $txt['still_writable'], '</em><br>
2359
		<br>';
2360
2361
	// Don't show the box if it's like 99% sure it won't work :P.
2362
	if ($incontext['probably_delete_install'])
2363
		echo '
2364
		<div style="margin: 1ex; font-weight: bold;">
2365
			<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>
2366
		</div>
2367
		<script>
2368
			function doTheDelete()
2369
			{
2370
				var theCheck = document.getElementById ? document.getElementById("delete_self") : document.all.delete_self;
2371
				var tempImage = new Image();
2372
2373
				tempImage.src = "', $installurl, '?delete=1&ts_" + (new Date().getTime());
2374
				tempImage.width = 0;
2375
				theCheck.disabled = true;
2376
			}
2377
		</script>
2378
		<br>';
2379
2380
	echo '
2381
		', sprintf($txt['go_to_your_forum'], $boardurl . '/index.php'), '<br>
2382
		<br>
2383
		', $txt['good_luck'];
2384
}
2385
2386
?>
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...
2387