Completed
Push — release-2.1 ( 001348...ca7b71 )
by Mathias
18:55
created

install.php ➔ initialize_inputs()   C

Complexity

Conditions 8
Paths 6

Size

Total Lines 115
Code Lines 37

Duplication

Lines 5
Ratio 4.35 %

Importance

Changes 0
Metric Value
cc 8
eloc 37
nc 6
nop 0
dl 5
loc 115
rs 5.2676
c 0
b 0
f 0

How to fix   Long Method   

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' => function() {
40
			return true;
41
		},
42
		'utf8_version' => '5.0.3',
43
		'utf8_version_check' => 'return mysqli_get_server_info($db_connection);',
44
		'utf8_default' => true,
45
		'utf8_required' => true,
46
		'alter_support' => true,
47
		'validate_prefix' => function(&$value) {
48
			$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
49
			return true;
50
		},
51
	),
52
	'postgresql' => array(
53
		'name' => 'PostgreSQL',
54
		'version' => '9.1',
55
		'function_check' => 'pg_connect',
56
		'version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
57
		'supported' => function_exists('pg_connect'),
58
		'always_has_db' => true,
59
		'utf8_default' => true,
60
		'utf8_required' => true,
61
		'utf8_support' => function() {
62
			$request = pg_query('SHOW SERVER_ENCODING');
63
			
64
			list ($charcode) = pg_fetch_row($request);
65
			
66
			if ($charcode == 'UTF8')			
67
				return true;
68
			else
69
				return false;
70
		},
71
		'utf8_version' => '8.0',
72
		'utf8_version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
73
		'validate_prefix' => function(&$value) {
74
			$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
75
76
			// Is it reserved?
77
			if ($value == 'pg_')
78
				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...
79
80
			// Is the prefix numeric?
81
			if (preg_match('~^\d~', $value))
82
				return $txt['error_db_prefix_numeric'];
83
84
			return true;
85
		},
86
	),
87
);
88
89
// Initialize everything and load the language files.
90
initialize_inputs();
91
load_lang_file();
92
93
// This is what we are.
94
$installurl = $_SERVER['PHP_SELF'];
95
96
// All the steps in detail.
97
// Number,Name,Function,Progress Weight.
98
$incontext['steps'] = array(
99
	0 => array(1, $txt['install_step_welcome'], 'Welcome', 0),
100
	1 => array(2, $txt['install_step_writable'], 'CheckFilesWritable', 10),
101
	2 => array(3, $txt['install_step_databaseset'], 'DatabaseSettings', 15),
102
	3 => array(4, $txt['install_step_forum'], 'ForumSettings', 40),
103
	4 => array(5, $txt['install_step_databasechange'], 'DatabasePopulation', 15),
104
	5 => array(6, $txt['install_step_admin'], 'AdminAccount', 20),
105
	6 => array(7, $txt['install_step_delete'], 'DeleteInstall', 0),
106
);
107
108
// Default title...
109
$incontext['page_title'] = $txt['smf_installer'];
110
111
// What step are we on?
112
$incontext['current_step'] = isset($_GET['step']) ? (int) $_GET['step'] : 0;
113
114
// Loop through all the steps doing each one as required.
115
$incontext['overall_percent'] = 0;
116
117
foreach ($incontext['steps'] as $num => $step)
118
{
119
	if ($num >= $incontext['current_step'])
120
	{
121
		// The current weight of this step in terms of overall progress.
122
		$incontext['step_weight'] = $step[3];
123
		// Make sure we reset the skip button.
124
		$incontext['skip'] = false;
125
126
		// Call the step and if it returns false that means pause!
127
		if (function_exists($step[2]) && $step[2]() === false)
128
			break;
129
		elseif (function_exists($step[2]))
130
			$incontext['current_step']++;
131
132
		// No warnings pass on.
133
		$incontext['warning'] = '';
134
	}
135
	$incontext['overall_percent'] += $step[3];
136
}
137
138
// Actually do the template stuff.
139
installExit();
140
141
function initialize_inputs()
142
{
143
	global $databases, $incontext;
144
145
	// Just so people using older versions of PHP aren't left in the cold.
146
	if (!isset($_SERVER['PHP_SELF']))
147
		$_SERVER['PHP_SELF'] = isset($GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']) ? $GLOBALS['HTTP_SERVER_VARS']['PHP_SELF'] : 'install.php';
148
149
	// Turn off magic quotes runtime and enable error reporting.
150
	if (function_exists('set_magic_quotes_runtime'))
151
		@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...
152
	error_reporting(E_ALL);
153
154
	// Fun.  Low PHP version...
155
	if (!isset($_GET))
156
	{
157
		$GLOBALS['_GET']['step'] = 0;
158
		return;
159
	}
160
161
	if (!isset($_GET['obgz']))
162
	{
163
		ob_start();
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
		if (function_exists('session_start'))
168
			@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...
169
	}
170
	else
171
	{
172
		ob_start('ob_gzhandler');
173
174
		if (ini_get('session.save_handler') == 'user')
175
			@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...
176
		session_start();
177
178
		if (!headers_sent())
179
			echo '<!DOCTYPE html>
180
<html>
181
	<head>
182
		<title>', htmlspecialchars($_GET['pass_string']), '</title>
183
	</head>
184
	<body style="background-color: #d4d4d4; margin-top: 16%; text-align: center; font-size: 16pt;">
185
		<strong>', htmlspecialchars($_GET['pass_string']), '</strong>
186
	</body>
187
</html>';
188
		exit;
189
	}
190
191
	// Add slashes, as long as they aren't already being added.
192
	if (!function_exists('get_magic_quotes_gpc') || @get_magic_quotes_gpc() == 0)
193
		foreach ($_POST as $k => $v)
194
			if (strpos($k, 'password') === false && strpos($k, 'db_passwd') === false)
195
				$_POST[$k] = addslashes($v);
196
197
	// This is really quite simple; if ?delete is on the URL, delete the installer...
198
	if (isset($_GET['delete']))
199
	{
200
		if (isset($_SESSION['installer_temp_ftp']))
201
		{
202
			$ftp = new ftp_connection($_SESSION['installer_temp_ftp']['server'], $_SESSION['installer_temp_ftp']['port'], $_SESSION['installer_temp_ftp']['username'], $_SESSION['installer_temp_ftp']['password']);
203
			$ftp->chdir($_SESSION['installer_temp_ftp']['path']);
204
205
			$ftp->unlink('install.php');
206
207
			foreach ($databases as $key => $dummy)
208
			{
209
				$type = ($key == 'mysqli') ? 'mysql' : $key;
210
				$ftp->unlink('install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
211
			}
212
213
			$ftp->close();
214
215
			unset($_SESSION['installer_temp_ftp']);
216
		}
217
		else
218
		{
219
			@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...
220
221
			foreach ($databases as $key => $dummy)
222
			{
223
				$type = ($key == 'mysqli') ? 'mysql' : $key;
224
				@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...
225
			}
226
		}
227
228
		// Now just redirect to a blank.png...
229
		header('Location: http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png');
230
		exit;
231
	}
232
233
	// PHP 5 might cry if we don't do this now.
234
	if (function_exists('date_default_timezone_set'))
235
	{
236
		// Get PHP's default timezone, if set
237
		$ini_tz = ini_get('date.timezone');
238
		if (!empty($ini_tz))
239
			$timezone_id = $ini_tz;
240
		else
241
			$timezone_id = '';
242
243
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
244 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...
245
		{
246
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
247
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
248
		}
249
250
		date_default_timezone_set($timezone_id);
251
	}
252
253
	// Force an integer step, defaulting to 0.
254
	$_GET['step'] = (int) @$_GET['step'];
255
}
256
257
// Load the list of language files, and the current language file.
258
function load_lang_file()
259
{
260
	global $txt, $incontext;
261
262
	$incontext['detected_languages'] = array();
263
264
	// Make sure the languages directory actually exists.
265
	if (file_exists(dirname(__FILE__) . '/Themes/default/languages'))
266
	{
267
		// Find all the "Install" language files in the directory.
268
		$dir = dir(dirname(__FILE__) . '/Themes/default/languages');
269
		while ($entry = $dir->read())
270
		{
271
			if (substr($entry, 0, 8) == 'Install.' && substr($entry, -4) == '.php')
272
				$incontext['detected_languages'][$entry] = ucfirst(substr($entry, 8, strlen($entry) - 12));
273
		}
274
		$dir->close();
275
	}
276
277
	// Didn't find any, show an error message!
278
	if (empty($incontext['detected_languages']))
279
	{
280
		// Let's not cache this message, eh?
281
		header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
282
		header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
283
		header('Cache-Control: no-cache');
284
285
		echo '<!DOCTYPE html>
286
<html>
287
	<head>
288
		<title>SMF Installer: Error!</title>
289
	</head>
290
	<body style="font-family: sans-serif;"><div style="width: 600px;">
291
		<h1 style="font-size: 14pt;">A critical error has occurred.</h1>
292
293
		<p>This installer was unable to find the installer\'s language file or files.  They should be found under:</p>
294
295
		<div style="margin: 1ex; font-family: monospace; font-weight: bold;">', dirname($_SERVER['PHP_SELF']) != '/' ? dirname($_SERVER['PHP_SELF']) : '', '/Themes/default/languages</div>
296
297
		<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>
298
		<p>If that doesn\'t help, please make sure this install.php file is in the same place as the Themes folder.</p>
299
300
		<p>If you continue to get this error message, feel free to <a href="https://support.simplemachines.org/">look to us for support</a>.</p>
301
	</div></body>
302
</html>';
303
		die;
304
	}
305
306
	// Override the language file?
307
	if (isset($_GET['lang_file']))
308
		$_SESSION['installer_temp_lang'] = $_GET['lang_file'];
309
	elseif (isset($GLOBALS['HTTP_GET_VARS']['lang_file']))
310
		$_SESSION['installer_temp_lang'] = $GLOBALS['HTTP_GET_VARS']['lang_file'];
311
312
	// Make sure it exists, if it doesn't reset it.
313
	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']))
314
	{
315
		// Use the first one...
316
		list ($_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
317
318
		// If we have english and some other language, use the other language.  We Americans hate english :P.
319
		if ($_SESSION['installer_temp_lang'] == 'Install.english.php' && count($incontext['detected_languages']) > 1)
320
			list (, $_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
321
	}
322
323
	// And now include the actual language file itself.
324
	require_once(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']);
325
}
326
327
// This handy function loads some settings and the like.
328
function load_database()
329
{
330
	global $db_prefix, $db_connection, $sourcedir;
331
	global $smcFunc, $modSettings, $db_type, $db_name, $db_user, $db_persist;
332
333
	if (empty($sourcedir))
334
		$sourcedir = dirname(__FILE__) . '/Sources';
335
336
	// Need this to check whether we need the database password.
337
	require(dirname(__FILE__) . '/Settings.php');
338
	if (!defined('SMF'))
339
		define('SMF', 1);
340
	if (empty($smcFunc))
341
		$smcFunc = array();
342
343
	$modSettings['disableQueryCheck'] = true;
344
345
	// Connect the database.
346
	if (!$db_connection)
347
	{
348
		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
349
		if (version_compare(PHP_VERSION, '5', '<'))
350
			require_once($sourcedir . '/Subs-Compat.php');
351
352
		$db_options = array('persist' => $db_persist);
353
		$port = '';
354
355
		// Figure out the port...
356
		if (!empty($_POST['db_port']))
357
		{
358
			if ($db_type == 'mysql')
359
			{
360
				$port = ((int) $_POST['db_port'] == ini_get($db_type . 'default_port')) ? '' : (int) $_POST['db_port'];
361
			}
362 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...
363
			{
364
				// PostgreSQL doesn't have a default port setting in php.ini, so just check against the default
365
				$port = ((int) $_POST['db_port'] == 5432) ? '' : (int) $_POST['db_port'];
366
			}
367
		}
368
369
		if (!empty($port))
370
			$db_options['port'] = $port;
371
372
		if (!$db_connection)
373
			$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...
374
	}
375
}
376
377
// This is called upon exiting the installer, for template etc.
378
function installExit($fallThrough = false)
379
{
380
	global $incontext, $installurl, $txt;
381
382
	// Send character set.
383
	header('Content-Type: text/html; charset=' . (isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8'));
384
385
	// We usually dump our templates out.
386
	if (!$fallThrough)
387
	{
388
		// The top install bit.
389
		template_install_above();
390
391
		// Call the template.
392
		if (isset($incontext['sub_template']))
393
		{
394
			$incontext['form_url'] = $installurl . '?step=' . $incontext['current_step'];
395
396
			call_user_func('template_' . $incontext['sub_template']);
397
		}
398
		// @todo REMOVE THIS!!
399
		else
400
		{
401
			if (function_exists('doStep' . $_GET['step']))
402
				call_user_func('doStep' . $_GET['step']);
403
		}
404
		// Show the footer.
405
		template_install_below();
406
	}
407
408
	// Bang - gone!
409
	die();
410
}
411
412
function Welcome()
413
{
414
	global $incontext, $txt, $databases, $installurl;
415
416
	$incontext['page_title'] = $txt['install_welcome'];
417
	$incontext['sub_template'] = 'welcome_message';
418
419
	// Done the submission?
420
	if (isset($_POST['contbutt']))
421
		return true;
422
423
	// See if we think they have already installed it?
424
	if (is_readable(dirname(__FILE__) . '/Settings.php'))
425
	{
426
		$probably_installed = 0;
427
		foreach (file(dirname(__FILE__) . '/Settings.php') as $line)
428
		{
429
			if (preg_match('~^\$db_passwd\s=\s\'([^\']+)\';$~', $line))
430
				$probably_installed++;
431
			if (preg_match('~^\$boardurl\s=\s\'([^\']+)\';~', $line) && !preg_match('~^\$boardurl\s=\s\'http://127\.0\.0\.1/smf\';~', $line))
432
				$probably_installed++;
433
		}
434
435
		if ($probably_installed == 2)
436
			$incontext['warning'] = $txt['error_already_installed'];
437
	}
438
439
	// Is some database support even compiled in?
440
	$incontext['supported_databases'] = array();
441
	foreach ($databases as $key => $db)
442
	{
443
		if ($db['supported'])
444
		{
445
			$type = ($key == 'mysqli') ? 'mysql' : $key;
446
			if (!file_exists(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql'))
447
			{
448
				$databases[$key]['supported'] = false;
449
				$notFoundSQLFile = true;
450
				$txt['error_db_script_missing'] = sprintf($txt['error_db_script_missing'], 'install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
451
			}
452
			else
453
				$incontext['supported_databases'][] = $db;
454
		}
455
	}
456
457
	// Check the PHP version.
458
	if ((!function_exists('version_compare') || version_compare($GLOBALS['required_php_version'], PHP_VERSION, '>')))
459
		$error = 'error_php_too_low';
460
	// Make sure we have a supported database
461
	elseif (empty($incontext['supported_databases']))
462
		$error = empty($notFoundSQLFile) ? 'error_db_missing' : 'error_db_script_missing';
463
	// How about session support?  Some crazy sysadmin remove it?
464
	elseif (!function_exists('session_start'))
465
		$error = 'error_session_missing';
466
	// Make sure they uploaded all the files.
467
	elseif (!file_exists(dirname(__FILE__) . '/index.php'))
468
		$error = 'error_missing_files';
469
	// Very simple check on the session.save_path for Windows.
470
	// @todo Move this down later if they don't use database-driven sessions?
471
	elseif (@ini_get('session.save_path') == '/tmp' && substr(__FILE__, 1, 2) == ':\\')
472
		$error = 'error_session_save_path';
473
474
	// Since each of the three messages would look the same, anyway...
475
	if (isset($error))
476
		$incontext['error'] = $txt[$error];
477
478
	// Mod_security blocks everything that smells funny. Let SMF handle security.
479
	if (!fixModSecurity() && !isset($_GET['overmodsecurity']))
480
		$incontext['error'] = $txt['error_mod_security'] . '<br><br><a href="' . $installurl . '?overmodsecurity=true">' . $txt['error_message_click'] . '</a> ' . $txt['error_message_bad_try_again'];
481
482
	return false;
483
}
484
485
function CheckFilesWritable()
486
{
487
	global $txt, $incontext;
488
489
	$incontext['page_title'] = $txt['ftp_checking_writable'];
490
	$incontext['sub_template'] = 'chmod_files';
491
492
	$writable_files = array(
493
		'attachments',
494
		'avatars',
495
		'custom_avatar',
496
		'cache',
497
		'Packages',
498
		'Smileys',
499
		'Themes',
500
		'agreement.txt',
501
		'Settings.php',
502
		'Settings_bak.php',
503
		'db_last_error.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.
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
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('Sources/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)
0 ignored issues
show
Coding Style introduced by
The function DatabaseSettings() contains an eval expression.

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

Loading history...
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 (!$databases[$db_type]['utf8_support']())
960
			{
961
				$incontext['error'] = sprintf($txt['error_utf8_support']);
962
				return false;
963
			}
964
				
965
			if (!empty($databases[$db_type]['utf8_version_check']) && version_compare($databases[$db_type]['utf8_version'], preg_replace('~\-.+?$~', '', eval($databases[$db_type]['utf8_version_check'])), '>'))
0 ignored issues
show
Coding Style introduced by
The function ForumSettings() contains an eval expression.

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

Loading history...
966
			{
967
				$incontext['error'] = sprintf($txt['error_utf8_version'], $databases[$db_type]['utf8_version']);
968
				return false;
969
			}
970
			else
971
				// Set the character set here.
972
				updateSettingsFile(array('db_character_set' => 'utf8'));
973
		}
974
975
		// Good, skip on.
976
		return true;
977
	}
978
979
	return false;
980
}
981
982
// Step one: Do the SQL thang.
983
function DatabasePopulation()
984
{
985
	global $db_character_set, $txt, $db_connection, $smcFunc, $databases, $modSettings, $db_type, $db_prefix, $incontext, $db_name, $boardurl;
986
987
	$incontext['sub_template'] = 'populate_database';
988
	$incontext['page_title'] = $txt['db_populate'];
989
	$incontext['continue'] = 1;
990
991
	// Already done?
992
	if (isset($_POST['pop_done']))
993
		return true;
994
995
	// Reload settings.
996
	require(dirname(__FILE__) . '/Settings.php');
997
	load_database();
998
999
	// Before running any of the queries, let's make sure another version isn't already installed.
1000
	$result = $smcFunc['db_query']('', '
1001
		SELECT variable, value
1002
		FROM {db_prefix}settings',
1003
		array(
1004
			'db_error_skip' => true,
1005
		)
1006
	);
1007
	$newSettings = array();
1008
	$modSettings = array();
1009
	if ($result !== false)
1010
	{
1011 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...
1012
			$modSettings[$row['variable']] = $row['value'];
1013
		$smcFunc['db_free_result']($result);
1014
1015
		// Do they match?  If so, this is just a refresh so charge on!
1016
		if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] != $GLOBALS['current_smf_version'])
1017
		{
1018
			$incontext['error'] = $txt['error_versions_do_not_match'];
1019
			return false;
1020
		}
1021
	}
1022
	$modSettings['disableQueryCheck'] = true;
1023
1024
	// If doing UTF8, select it. PostgreSQL requires passing it as a string...
1025 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...
1026
		$smcFunc['db_query']('', '
1027
			SET NAMES {string:utf8}',
1028
			array(
1029
				'db_error_skip' => true,
1030
				'utf8' => 'utf8',
1031
			)
1032
		);
1033
1034
	// Windows likes to leave the trailing slash, which yields to C:\path\to\SMF\/attachments...
1035
	if (substr(__DIR__, -1) == '\\')
1036
		$attachdir = __DIR__ . 'attachments';
1037
	else
1038
		$attachdir = __DIR__ . '/attachments';
1039
1040
	$replaces = array(
1041
		'{$db_prefix}' => $db_prefix,
1042
		'{$attachdir}' => json_encode(array(1 => $smcFunc['db_escape_string']($attachdir))),
1043
		'{$boarddir}' => $smcFunc['db_escape_string'](dirname(__FILE__)),
1044
		'{$boardurl}' => $boardurl,
1045
		'{$enableCompressedOutput}' => isset($_POST['compress']) ? '1' : '0',
1046
		'{$databaseSession_enable}' => isset($_POST['dbsession']) ? '1' : '0',
1047
		'{$smf_version}' => $GLOBALS['current_smf_version'],
1048
		'{$current_time}' => time(),
1049
		'{$sched_task_offset}' => 82800 + mt_rand(0, 86399),
1050
		'{$registration_method}' => isset($_POST['reg_mode']) ? $_POST['reg_mode'] : 0,
1051
	);
1052
1053
	foreach ($txt as $key => $value)
1054
	{
1055
		if (substr($key, 0, 8) == 'default_')
1056
			$replaces['{$' . $key . '}'] = $smcFunc['db_escape_string']($value);
1057
	}
1058
	$replaces['{$default_reserved_names}'] = strtr($replaces['{$default_reserved_names}'], array('\\\\n' => '\\n'));
1059
1060
	// MySQL-specific stuff - storage engine and UTF8 handling
1061
	if (substr($db_type, 0, 5) == 'mysql')
1062
	{
1063
		// Just in case the query fails for some reason...
1064
		$engines = array();
1065
1066
		// Figure out storage engines - what do we have, etc.
1067
		$get_engines = $smcFunc['db_query']('', 'SHOW ENGINES', array());
1068
1069 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...
1070
		{
1071
			if ($row['Support'] == 'YES' || $row['Support'] == 'DEFAULT')
1072
				$engines[] = $row['Engine'];
1073
		}
1074
1075
		// Done with this now
1076
		$smcFunc['db_free_result']($get_engines);
1077
1078
		// InnoDB is better, so use it if possible...
1079
		$has_innodb = in_array('InnoDB', $engines);
1080
		$replaces['{$engine}'] = $has_innodb ? 'InnoDB' : 'MyISAM';
1081
		$replaces['{$memory}'] = (!$has_innodb && in_array('MEMORY', $engines)) ? 'MEMORY' : $replaces['{$engine}'];
1082
1083
		// If the UTF-8 setting was enabled, add it to the table definitions.
1084
		if (!empty($databases[$db_type]['utf8_support']) && (!empty($databases[$db_type]['utf8_required']) || isset($_POST['utf8'])))
1085
		{
1086
			$replaces['{$engine}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1087
			$replaces['{$memory}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1088
		}
1089
1090
		// One last thing - if we don't have InnoDB, we can't do transactions...
1091
		if (!$has_innodb)
1092
		{
1093
			$replaces['START TRANSACTION;'] = '';
1094
			$replaces['COMMIT;'] = '';
1095
		}
1096
	}
1097
	else
1098
	{
1099
		$has_innodb = false;
1100
	}
1101
1102
	// Read in the SQL.  Turn this on and that off... internationalize... etc.
1103
	$type = ($db_type == 'mysqli' ? 'mysql' : $db_type);
1104
	$sql_lines = explode("\n", strtr(implode(' ', file(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql')), $replaces));
1105
1106
	// Execute the SQL.
1107
	$current_statement = '';
1108
	$exists = array();
1109
	$incontext['failures'] = array();
1110
	$incontext['sql_results'] = array(
1111
		'tables' => 0,
1112
		'inserts' => 0,
1113
		'table_dups' => 0,
1114
		'insert_dups' => 0,
1115
	);
1116
	foreach ($sql_lines as $count => $line)
1117
	{
1118
		// No comments allowed!
1119
		if (substr(trim($line), 0, 1) != '#')
1120
			$current_statement .= "\n" . rtrim($line);
1121
1122
		// Is this the end of the query string?
1123
		if (empty($current_statement) || (preg_match('~;[\s]*$~s', $line) == 0 && $count != count($sql_lines)))
1124
			continue;
1125
1126
		// Does this table already exist?  If so, don't insert more data into it!
1127
		if (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) != 0 && in_array($match[1], $exists))
1128
		{
1129
			preg_match_all('~\)[,;]~', $current_statement, $matches);
1130 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...
1131
				$incontext['sql_results']['insert_dups'] += count($matches[0]);
1132
			else
1133
				$incontext['sql_results']['insert_dups']++;
1134
1135
			$current_statement = '';
1136
			continue;
1137
		}
1138
1139
		if ($smcFunc['db_query']('', $current_statement, array('security_override' => true, 'db_error_skip' => true), $db_connection) === false)
1140
		{
1141
			// Use the appropriate function based on the DB type
1142
			if ($db_type == 'mysql' || $db_type == 'mysqli')
1143
				$db_errorno = $db_type . '_errno';
1144
1145
			// Error 1050: Table already exists!
1146
			// @todo Needs to be made better!
1147
			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...
1148
			{
1149
				$exists[] = $match[1];
1150
				$incontext['sql_results']['table_dups']++;
1151
			}
1152
			// Don't error on duplicate indexes (or duplicate operators in PostgreSQL.)
1153
			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)))
1154
			{
1155
				// MySQLi requires a connection object. It's optional with MySQL and Postgres
1156
				$incontext['failures'][$count] = $smcFunc['db_error']($db_connection);
1157
			}
1158
		}
1159
		else
1160
		{
1161
			if (preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1162
				$incontext['sql_results']['tables']++;
1163
			elseif (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1164
			{
1165
				preg_match_all('~\)[,;]~', $current_statement, $matches);
1166 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...
1167
					$incontext['sql_results']['inserts'] += count($matches[0]);
1168
				else
1169
					$incontext['sql_results']['inserts']++;
1170
			}
1171
		}
1172
1173
		$current_statement = '';
1174
1175
		// Wait, wait, I'm still working here!
1176
		set_time_limit(60);
1177
	}
1178
1179
	// Sort out the context for the SQL.
1180
	foreach ($incontext['sql_results'] as $key => $number)
1181
	{
1182
		if ($number == 0)
1183
			unset($incontext['sql_results'][$key]);
1184
		else
1185
			$incontext['sql_results'][$key] = sprintf($txt['db_populate_' . $key], $number);
1186
	}
1187
1188
	// Make sure UTF will be used globally.
1189
	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'])))
1190
		$newSettings[] = array('global_character_set', 'UTF-8');
1191
1192
	// Maybe we can auto-detect better cookie settings?
1193
	preg_match('~^http[s]?://([^\.]+?)([^/]*?)(/.*)?$~', $boardurl, $matches);
1194
	if (!empty($matches))
1195
	{
1196
		// Default = both off.
1197
		$localCookies = false;
1198
		$globalCookies = false;
1199
1200
		// Okay... let's see.  Using a subdomain other than www.? (not a perfect check.)
1201
		if ($matches[2] != '' && (strpos(substr($matches[2], 1), '.') === false || in_array($matches[1], array('forum', 'board', 'community', 'forums', 'support', 'chat', 'help', 'talk', 'boards', 'www'))))
1202
			$globalCookies = true;
1203
		// If there's a / in the middle of the path, or it starts with ~... we want local.
1204
		if (isset($matches[3]) && strlen($matches[3]) > 3 && (substr($matches[3], 0, 2) == '/~' || strpos(substr($matches[3], 1), '/') !== false))
1205
			$localCookies = true;
1206
1207
		if ($globalCookies)
1208
			$newSettings[] = array('globalCookies', '1');
1209
		if ($localCookies)
1210
			$newSettings[] = array('localCookies', '1');
1211
	}
1212
1213
	// Are we allowing stat collection?
1214
	if (isset($_POST['stats']) && (strpos($_POST['boardurl'], 'http://localhost') !== 0 || strpos($_POST['boardurl'], 'https://localhost') !== 0))
1215
	{
1216
		// Attempt to register the site etc.
1217
		$fp = @fsockopen("www.simplemachines.org", 80, $errno, $errstr);
1218
		if ($fp)
1219
		{
1220
			$out = "GET /smf/stats/register_stats.php?site=" . base64_encode($_POST['boardurl']) . " HTTP/1.1\r\n";
1221
			$out .= "Host: www.simplemachines.org\r\n";
1222
			$out .= "Connection: Close\r\n\r\n";
1223
			fwrite($fp, $out);
1224
1225
			$return_data = '';
1226
			while (!feof($fp))
1227
				$return_data .= fgets($fp, 128);
1228
1229
			fclose($fp);
1230
1231
			// Get the unique site ID.
1232
			preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1233
1234
			if (!empty($ID[1]))
1235
				$newSettings[] = array('allow_sm_stats', $ID[1]);
1236
		}
1237
	}
1238
1239
	// Are we enabling SSL?
1240
	if (!empty($_POST['force_ssl']))
1241
		$newSettings[] = array('force_ssl', 2);
1242
1243
	// Setting a timezone is required.
1244
	if (!isset($modSettings['default_timezone']) && function_exists('date_default_timezone_set'))
1245
	{
1246
		// Get PHP's default timezone, if set
1247
		$ini_tz = ini_get('date.timezone');
1248
		if (!empty($ini_tz))
1249
			$timezone_id = $ini_tz;
1250
		else
1251
			$timezone_id = '';
1252
1253
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
1254 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...
1255
		{
1256
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
1257
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
1258
		}
1259
1260
		if (date_default_timezone_set($timezone_id))
1261
			$newSettings[] = array('default_timezone', $timezone_id);
1262
	}
1263
1264
	if (!empty($newSettings))
1265
	{
1266
		$smcFunc['db_insert']('replace',
1267
			'{db_prefix}settings',
1268
			array('variable' => 'string-255', 'value' => 'string-65534'),
1269
			$newSettings,
1270
			array('variable')
1271
		);
1272
	}
1273
1274
	// Let's optimize those new tables, but not on InnoDB, ok?
1275
	if (!$has_innodb)
1276
	{
1277
		db_extend();
1278
		$tables = $smcFunc['db_list_tables']($db_name, $db_prefix . '%');
1279
		foreach ($tables as $table)
1280
		{
1281
			$smcFunc['db_optimize_table']($table) != -1 or $db_messed = true;
1282
1283
			if (!empty($db_messed))
1284
			{
1285
				$incontext['failures'][-1] = $smcFunc['db_error']();
1286
				break;
1287
			}
1288
		}
1289
	}
1290
1291
	// MySQL specific stuff
1292
	if (substr($db_type, 0, 5) != 'mysql')
1293
		return false;
1294
1295
	// Find database user privileges.
1296
	$privs = array();
1297
	$get_privs = $smcFunc['db_query']('', 'SHOW PRIVILEGES', array());
1298
	while ($row = $smcFunc['db_fetch_assoc']($get_privs))
1299
	{
1300
		if ($row['Privilege'] == 'Alter')
1301
			$privs[] = $row['Privilege'];
1302
	}
1303
	$smcFunc['db_free_result']($get_privs);
1304
1305
	// Check for the ALTER privilege.
1306
	if (!empty($databases[$db_type]['alter_support']) && !in_array('Alter', $privs))
1307
	{
1308
		$incontext['error'] = $txt['error_db_alter_priv'];
1309
		return false;
1310
	}
1311
1312
	if (!empty($exists))
1313
	{
1314
		$incontext['page_title'] = $txt['user_refresh_install'];
1315
		$incontext['was_refresh'] = true;
1316
	}
1317
1318
	return false;
1319
}
1320
1321
// Ask for the administrator login information.
1322
function AdminAccount()
1323
{
1324
	global $txt, $db_type, $db_connection, $smcFunc, $incontext, $db_prefix, $db_passwd, $sourcedir, $db_character_set;
1325
1326
	$incontext['sub_template'] = 'admin_account';
1327
	$incontext['page_title'] = $txt['user_settings'];
1328
	$incontext['continue'] = 1;
1329
1330
	// Skipping?
1331
	if (!empty($_POST['skip']))
1332
		return true;
1333
1334
	// Need this to check whether we need the database password.
1335
	require(dirname(__FILE__) . '/Settings.php');
1336
	load_database();
1337
1338
	require_once($sourcedir . '/Subs-Auth.php');
1339
1340
	require_once($sourcedir . '/Subs.php');
1341
1342
	// We need this to properly hash the password for Admin
1343 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...
1344
			global $sourcedir;
1345
			if (function_exists('mb_strtolower'))
1346
				return mb_strtolower($string, 'UTF-8');
1347
			require_once($sourcedir . '/Subs-Charset.php');
1348
			return utf8_strtolower($string);
1349
		};
1350
1351
	if (!isset($_POST['username']))
1352
		$_POST['username'] = '';
1353
	if (!isset($_POST['email']))
1354
		$_POST['email'] = '';
1355
	if (!isset($_POST['server_email']))
1356
		$_POST['server_email'] = '';
1357
1358
	$incontext['username'] = htmlspecialchars(stripslashes($_POST['username']));
1359
	$incontext['email'] = htmlspecialchars(stripslashes($_POST['email']));
1360
	$incontext['server_email'] = htmlspecialchars(stripslashes($_POST['server_email']));
1361
1362
	$incontext['require_db_confirm'] = empty($db_type);
1363
1364
	// Only allow skipping if we think they already have an account setup.
1365
	$request = $smcFunc['db_query']('', '
1366
		SELECT id_member
1367
		FROM {db_prefix}members
1368
		WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
1369
		LIMIT 1',
1370
		array(
1371
			'db_error_skip' => true,
1372
			'admin_group' => 1,
1373
		)
1374
	);
1375
	if ($smcFunc['db_num_rows']($request) != 0)
1376
		$incontext['skip'] = 1;
1377
	$smcFunc['db_free_result']($request);
1378
1379
	// Trying to create an account?
1380
	if (isset($_POST['password1']) && !empty($_POST['contbutt']))
1381
	{
1382
		// Wrong password?
1383
		if ($incontext['require_db_confirm'] && $_POST['password3'] != $db_passwd)
1384
		{
1385
			$incontext['error'] = $txt['error_db_connect'];
1386
			return false;
1387
		}
1388
		// Not matching passwords?
1389
		if ($_POST['password1'] != $_POST['password2'])
1390
		{
1391
			$incontext['error'] = $txt['error_user_settings_again_match'];
1392
			return false;
1393
		}
1394
		// No password?
1395
		if (strlen($_POST['password1']) < 4)
1396
		{
1397
			$incontext['error'] = $txt['error_user_settings_no_password'];
1398
			return false;
1399
		}
1400
		if (!file_exists($sourcedir . '/Subs.php'))
1401
		{
1402
			$incontext['error'] = $txt['error_subs_missing'];
1403
			return false;
1404
		}
1405
1406
		// Update the webmaster's email?
1407
		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...
1408
			updateSettingsFile(array('webmaster_email' => $_POST['server_email']));
1409
1410
		// Work out whether we're going to have dodgy characters and remove them.
1411
		$invalid_characters = preg_match('~[<>&"\'=\\\]~', $_POST['username']) != 0;
1412
		$_POST['username'] = preg_replace('~[<>&"\'=\\\]~', '', $_POST['username']);
1413
1414
		$result = $smcFunc['db_query']('', '
1415
			SELECT id_member, password_salt
1416
			FROM {db_prefix}members
1417
			WHERE member_name = {string:username} OR email_address = {string:email}
1418
			LIMIT 1',
1419
			array(
1420
				'username' => stripslashes($_POST['username']),
1421
				'email' => stripslashes($_POST['email']),
1422
				'db_error_skip' => true,
1423
			)
1424
		);
1425
		if ($smcFunc['db_num_rows']($result) != 0)
1426
		{
1427
			list ($incontext['member_id'], $incontext['member_salt']) = $smcFunc['db_fetch_row']($result);
1428
			$smcFunc['db_free_result']($result);
1429
1430
			$incontext['account_existed'] = $txt['error_user_settings_taken'];
1431
		}
1432
		elseif ($_POST['username'] == '' || strlen($_POST['username']) > 25)
1433
		{
1434
			// Try the previous step again.
1435
			$incontext['error'] = $_POST['username'] == '' ? $txt['error_username_left_empty'] : $txt['error_username_too_long'];
1436
			return false;
1437
		}
1438
		elseif ($invalid_characters || $_POST['username'] == '_' || $_POST['username'] == '|' || strpos($_POST['username'], '[code') !== false || strpos($_POST['username'], '[/code') !== false)
1439
		{
1440
			// Try the previous step again.
1441
			$incontext['error'] = $txt['error_invalid_characters_username'];
1442
			return false;
1443
		}
1444 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...
1445
		{
1446
			// One step back, this time fill out a proper admin email address.
1447
			$incontext['error'] = sprintf($txt['error_valid_admin_email_needed'], $_POST['username']);
1448
			return false;
1449
		}
1450 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...
1451
		{
1452
			// One step back, this time fill out a proper admin email address.
1453
			$incontext['error'] = $txt['error_valid_server_email_needed'];
1454
			return false;
1455
		}
1456
		elseif ($_POST['username'] != '')
1457
		{
1458
			$incontext['member_salt'] = substr(md5(mt_rand()), 0, 4);
1459
1460
			// Format the username properly.
1461
			$_POST['username'] = preg_replace('~[\t\n\r\x0B\0\xA0]+~', ' ', $_POST['username']);
1462
			$ip = isset($_SERVER['REMOTE_ADDR']) ? substr($_SERVER['REMOTE_ADDR'], 0, 255) : '';
1463
1464
			$_POST['password1'] = hash_password(stripslashes($_POST['username']), stripslashes($_POST['password1']));
1465
1466
			$incontext['member_id'] = $smcFunc['db_insert']('',
1467
				$db_prefix . 'members',
1468
				array(
1469
					'member_name' => 'string-25', 'real_name' => 'string-25', 'passwd' => 'string', 'email_address' => 'string',
1470
					'id_group' => 'int', 'posts' => 'int', 'date_registered' => 'int',
1471
					'password_salt' => 'string', 'lngfile' => 'string', 'personal_text' => 'string', 'avatar' => 'string',
1472
					'member_ip' => 'inet', 'member_ip2' => 'inet', 'buddy_list' => 'string', 'pm_ignore_list' => 'string',
1473
					'website_title' => 'string', 'website_url' => 'string',
1474
					'signature' => 'string', 'usertitle' => 'string', 'secret_question' => 'string',
1475
					'additional_groups' => 'string', 'ignore_boards' => 'string',
1476
				),
1477
				array(
1478
					stripslashes($_POST['username']), stripslashes($_POST['username']), $_POST['password1'], stripslashes($_POST['email']),
1479
					1, 0, time(),
1480
					$incontext['member_salt'], '', '', '',
1481
					$ip, $ip, '', '',
1482
					'', '',
1483
					'', '', '',
1484
					'', '',
1485
				),
1486
				array('id_member'),
1487
				1
1488
			);
1489
		}
1490
1491
		// If we're here we're good.
1492
		return true;
1493
	}
1494
1495
	return false;
1496
}
1497
1498
// Final step, clean up and a complete message!
1499
function DeleteInstall()
1500
{
1501
	global $txt, $incontext;
1502
	global $smcFunc, $db_character_set, $context, $cookiename;
1503
	global $current_smf_version, $databases, $sourcedir, $forum_version, $modSettings, $user_info, $db_type, $boardurl;
1504
1505
	$incontext['page_title'] = $txt['congratulations'];
1506
	$incontext['sub_template'] = 'delete_install';
1507
	$incontext['continue'] = 0;
1508
1509
	require(dirname(__FILE__) . '/Settings.php');
1510
	load_database();
1511
1512
	chdir(dirname(__FILE__));
1513
1514
	require_once($sourcedir . '/Errors.php');
1515
	require_once($sourcedir . '/Logging.php');
1516
	require_once($sourcedir . '/Subs.php');
1517
	require_once($sourcedir . '/Load.php');
1518
	require_once($sourcedir . '/Security.php');
1519
	require_once($sourcedir . '/Subs-Auth.php');
1520
1521
	// Bring a warning over.
1522
	if (!empty($incontext['account_existed']))
1523
		$incontext['warning'] = $incontext['account_existed'];
1524
1525 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...
1526
		$smcFunc['db_query']('', '
1527
			SET NAMES {string:db_character_set}',
1528
			array(
1529
				'db_character_set' => $db_character_set,
1530
				'db_error_skip' => true,
1531
			)
1532
		);
1533
1534
	// As track stats is by default enabled let's add some activity.
1535
	$smcFunc['db_insert']('ignore',
1536
		'{db_prefix}log_activity',
1537
		array('date' => 'date', 'topics' => 'int', 'posts' => 'int', 'registers' => 'int'),
1538
		array(strftime('%Y-%m-%d', time()), 1, 1, (!empty($incontext['member_id']) ? 1 : 0)),
1539
		array('date')
1540
	);
1541
1542
	// We're going to want our lovely $modSettings now.
1543
	$request = $smcFunc['db_query']('', '
1544
		SELECT variable, value
1545
		FROM {db_prefix}settings',
1546
		array(
1547
			'db_error_skip' => true,
1548
		)
1549
	);
1550
	// Only proceed if we can load the data.
1551
	if ($request)
1552
	{
1553 View Code Duplication
		while ($row = $smcFunc['db_fetch_row']($request))
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...
1554
			$modSettings[$row[0]] = $row[1];
1555
		$smcFunc['db_free_result']($request);
1556
	}
1557
1558
	// Automatically log them in ;)
1559
	if (isset($incontext['member_id']) && isset($incontext['member_salt']))
1560
		setLoginCookie(3153600 * 60, $incontext['member_id'], hash_salt($_POST['password1'], $incontext['member_salt']));
1561
1562
	$result = $smcFunc['db_query']('', '
1563
		SELECT value
1564
		FROM {db_prefix}settings
1565
		WHERE variable = {string:db_sessions}',
1566
		array(
1567
			'db_sessions' => 'databaseSession_enable',
1568
			'db_error_skip' => true,
1569
		)
1570
	);
1571 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...
1572
		list ($db_sessions) = $smcFunc['db_fetch_row']($result);
1573
	$smcFunc['db_free_result']($result);
1574
1575
	if (empty($db_sessions))
1576
		$_SESSION['admin_time'] = time();
1577
	else
1578
	{
1579
		$_SERVER['HTTP_USER_AGENT'] = substr($_SERVER['HTTP_USER_AGENT'], 0, 211);
1580
1581
		$smcFunc['db_insert']('replace',
1582
			'{db_prefix}sessions',
1583
			array(
1584
				'session_id' => 'string', 'last_update' => 'int', 'data' => 'string',
1585
			),
1586
			array(
1587
				session_id(), time(), 'USER_AGENT|s:' . strlen($_SERVER['HTTP_USER_AGENT']) . ':"' . $_SERVER['HTTP_USER_AGENT'] . '";admin_time|i:' . time() . ';',
1588
			),
1589
			array('session_id')
1590
		);
1591
	}
1592
1593
	updateStats('member');
1594
	updateStats('message');
1595
	updateStats('topic');
1596
1597
	// This function is needed to do the updateStats('subject') call.
1598
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' :
1599 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...
1600
			global $sourcedir;
1601
			if (function_exists('mb_strtolower'))
1602
				return mb_strtolower($string, 'UTF-8');
1603
			require_once($sourcedir . '/Subs-Charset.php');
1604
			return utf8_strtolower($string);
1605
		};
1606
1607
	$request = $smcFunc['db_query']('', '
1608
		SELECT id_msg
1609
		FROM {db_prefix}messages
1610
		WHERE id_msg = 1
1611
			AND modified_time = 0
1612
		LIMIT 1',
1613
		array(
1614
			'db_error_skip' => true,
1615
		)
1616
	);
1617
	$context['utf8'] = $db_character_set === 'utf8' || $txt['lang_character_set'] === 'UTF-8';
1618
	if ($smcFunc['db_num_rows']($request) > 0)
1619
		updateStats('subject', 1, htmlspecialchars($txt['default_topic_subject']));
1620
	$smcFunc['db_free_result']($request);
1621
1622
	// Now is the perfect time to fetch the SM files.
1623
	require_once($sourcedir . '/ScheduledTasks.php');
1624
	// Sanity check that they loaded earlier!
1625
	if (isset($modSettings['recycle_board']))
1626
	{
1627
		$forum_version = $current_smf_version; // The variable is usually defined in index.php so lets just use our variable to do it for us.
1628
		scheduled_fetchSMfiles(); // Now go get those files!
1629
1630
		// We've just installed!
1631
		$user_info['ip'] = $_SERVER['REMOTE_ADDR'];
1632
		$user_info['id'] = isset($incontext['member_id']) ? $incontext['member_id'] : 0;
1633
		logAction('install', array('version' => $forum_version), 'admin');
1634
	}
1635
1636
	// Check if we need some stupid MySQL fix.
1637
	$server_version = $smcFunc['db_server_info']();
1638 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...
1639
		updateSettings(array('db_mysql_group_by_fix' => '1'));
1640
1641
	// Some final context for the template.
1642
	$incontext['dir_still_writable'] = is_writable(dirname(__FILE__)) && substr(__FILE__, 1, 2) != ':\\';
1643
	$incontext['probably_delete_install'] = isset($_SESSION['installer_temp_ftp']) || is_writable(dirname(__FILE__)) || is_writable(__FILE__);
1644
1645
	// Update hash's cost to an appropriate setting
1646
	updateSettings(array(
1647
		'bcrypt_hash_cost' => hash_benchmark(),
1648
	));
1649
1650
	return false;
1651
}
1652
1653
function updateSettingsFile($vars)
1654
{
1655
	// Modify Settings.php.
1656
	$settingsArray = file(dirname(__FILE__) . '/Settings.php');
1657
1658
	// @todo Do we just want to read the file in clean, and split it this way always?
1659
	if (count($settingsArray) == 1)
1660
		$settingsArray = preg_split('~[\r\n]~', $settingsArray[0]);
1661
1662
	for ($i = 0, $n = count($settingsArray); $i < $n; $i++)
1663
	{
1664
		// Remove the redirect...
1665
		if (trim($settingsArray[$i]) == 'if (file_exists(dirname(__FILE__) . \'/install.php\'))' && trim($settingsArray[$i + 1]) == '{' && trim($settingsArray[$i + 3]) == '}')
1666
		{
1667
			// Get the four lines to nothing.
1668
			$settingsArray[$i] = '';
1669
			$settingsArray[++$i] = '';
1670
			$settingsArray[++$i] = '';
1671
			$settingsArray[++$i] = '';
1672
			continue;
1673
		}
1674
1675
		if (trim($settingsArray[$i]) == '?' . '>')
1676
			$settingsArray[$i] = '';
1677
1678
		// Don't trim or bother with it if it's not a variable.
1679
		if (substr($settingsArray[$i], 0, 1) != '$')
1680
			continue;
1681
1682
		$settingsArray[$i] = rtrim($settingsArray[$i]) . "\n";
1683
1684
		foreach ($vars as $var => $val)
1685
			if (strncasecmp($settingsArray[$i], '$' . $var, 1 + strlen($var)) == 0)
1686
			{
1687
				$comment = strstr($settingsArray[$i], '#');
1688
				$settingsArray[$i] = '$' . $var . ' = \'' . $val . '\';' . ($comment != '' ? "\t\t" . $comment : "\n");
1689
				unset($vars[$var]);
1690
			}
1691
	}
1692
1693
	// Uh oh... the file wasn't empty... was it?
1694
	if (!empty($vars))
1695
	{
1696
		$settingsArray[$i++] = '';
1697
		foreach ($vars as $var => $val)
1698
			$settingsArray[$i++] = '$' . $var . ' = \'' . $val . '\';' . "\n";
1699
	}
1700
1701
	// Blank out the file - done to fix a oddity with some servers.
1702
	$fp = @fopen(dirname(__FILE__) . '/Settings.php', 'w');
1703
	if (!$fp)
1704
		return false;
1705
	fclose($fp);
1706
1707
	$fp = fopen(dirname(__FILE__) . '/Settings.php', 'r+');
1708
1709
	// Gotta have one of these ;)
1710
	if (trim($settingsArray[0]) != '<?php')
1711
		fwrite($fp, "<?php\n");
1712
1713
	$lines = count($settingsArray);
1714
	for ($i = 0; $i < $lines - 1; $i++)
1715
	{
1716
		// Don't just write a bunch of blank lines.
1717
		if ($settingsArray[$i] != '' || @$settingsArray[$i - 1] != '')
1718
			fwrite($fp, strtr($settingsArray[$i], "\r", ''));
1719
	}
1720
	fwrite($fp, $settingsArray[$i] . '?' . '>');
1721
	fclose($fp);
1722
1723
	// Even though on normal installations the filemtime should prevent this being used by the installer incorrectly
1724
	// it seems that there are times it might not. So let's MAKE it dump the cache.
1725
	if (function_exists('opcache_invalidate'))
1726
		opcache_invalidate(dirname(__FILE__) . '/Settings.php', true);
1727
1728
	return true;
1729
}
1730
1731
function updateDbLastError()
1732
{
1733
	// Write out the db_last_error file with the error timestamp
1734
	file_put_contents(dirname(__FILE__) . '/db_last_error.php', '<' . '?' . "php\n" . '$db_last_error = 0;' . "\n" . '?' . '>');
1735
1736
	return true;
1737
}
1738
1739
// Create an .htaccess file to prevent mod_security. SMF has filtering built-in.
1740
function fixModSecurity()
1741
{
1742
	$htaccess_addition = '
1743
<IfModule mod_security.c>
1744
	# Turn off mod_security filtering.  SMF is a big boy, it doesn\'t need its hands held.
1745
	SecFilterEngine Off
1746
1747
	# The below probably isn\'t needed, but better safe than sorry.
1748
	SecFilterScanPOST Off
1749
</IfModule>';
1750
1751
	if (!function_exists('apache_get_modules') || !in_array('mod_security', apache_get_modules()))
1752
		return true;
1753
	elseif (file_exists(dirname(__FILE__) . '/.htaccess') && is_writable(dirname(__FILE__) . '/.htaccess'))
1754
	{
1755
		$current_htaccess = implode('', file(dirname(__FILE__) . '/.htaccess'));
1756
1757
		// Only change something if mod_security hasn't been addressed yet.
1758
		if (strpos($current_htaccess, '<IfModule mod_security.c>') === false)
1759
		{
1760 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...
1761
			{
1762
				fwrite($ht_handle, $htaccess_addition);
1763
				fclose($ht_handle);
1764
				return true;
1765
			}
1766
			else
1767
				return false;
1768
		}
1769
		else
1770
			return true;
1771
	}
1772
	elseif (file_exists(dirname(__FILE__) . '/.htaccess'))
1773
		return strpos(implode('', file(dirname(__FILE__) . '/.htaccess')), '<IfModule mod_security.c>') !== false;
1774
	elseif (is_writable(dirname(__FILE__)))
1775
	{
1776 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...
1777
		{
1778
			fwrite($ht_handle, $htaccess_addition);
1779
			fclose($ht_handle);
1780
			return true;
1781
		}
1782
		else
1783
			return false;
1784
	}
1785
	else
1786
		return false;
1787
}
1788
1789
function template_install_above()
1790
{
1791
	global $incontext, $txt, $installurl;
1792
1793
	echo '<!DOCTYPE html>
1794
<html', $txt['lang_rtl'] == true ? ' dir="rtl"' : '', '>
1795
	<head>
1796
		<meta charset="', isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8', '">
1797
		<meta name="robots" content="noindex">
1798
		<title>', $txt['smf_installer'], '</title>
1799
		<link rel="stylesheet" href="Themes/default/css/index.css?alp21">
1800
		<link rel="stylesheet" href="Themes/default/css/install.css?alp21">
1801
		', $txt['lang_rtl'] == true ? '<link rel="stylesheet" href="Themes/default/css/rtl.css?alp21">' : '', '
1802
1803
		<script src="Themes/default/scripts/jquery-3.1.1.min.js"></script>
1804
		<script src="Themes/default/scripts/script.js"></script>
1805
	</head>
1806
	<body><div id="footerfix">
1807
		<div id="header">
1808
			<h1 class="forumtitle">', $txt['smf_installer'], '</h1>
1809
			<img id="smflogo" src="Themes/default/images/smflogo.png" alt="Simple Machines Forum" title="Simple Machines Forum">
1810
		</div>
1811
		<div id="wrapper">
1812
			<div id="upper_section">
1813
				<div id="inner_section">
1814
					<div id="inner_wrap">';
1815
1816
	// Have we got a language drop down - if so do it on the first step only.
1817
	if (!empty($incontext['detected_languages']) && count($incontext['detected_languages']) > 1 && $incontext['current_step'] == 0)
1818
	{
1819
		echo '
1820
						<div class="news">
1821
							<form action="', $installurl, '" method="get">
1822
								<label for="installer_language">', $txt['installer_language'], ':</label>
1823
								<select id="installer_language" name="lang_file" onchange="location.href = \'', $installurl, '?lang_file=\' + this.options[this.selectedIndex].value;">';
1824
1825
		foreach ($incontext['detected_languages'] as $lang => $name)
1826
			echo '
1827
									<option', isset($_SESSION['installer_temp_lang']) && $_SESSION['installer_temp_lang'] == $lang ? ' selected' : '', ' value="', $lang, '">', $name, '</option>';
1828
1829
		echo '
1830
								</select>
1831
								<noscript><input type="submit" value="', $txt['installer_language_set'], '" class="button_submit" /></noscript>
1832
							</form>
1833
						</div>
1834
						<hr class="clear" />';
1835
	}
1836
1837
	echo '
1838
					</div>
1839
				</div>
1840
			</div>
1841
			<div id="content_section">
1842
				<div id="main_content_section">
1843
					<div id="main_steps">
1844
						<h2>', $txt['upgrade_progress'], '</h2>
1845
						<ul>';
1846
1847 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...
1848
		echo '
1849
							<li class="', $num < $incontext['current_step'] ? 'stepdone' : ($num == $incontext['current_step'] ? 'stepcurrent' : 'stepwaiting'), '">', $txt['upgrade_step'], ' ', $step[0], ': ', $step[1], '</li>';
1850
1851
	echo '
1852
						</ul>
1853
					</div>
1854
					<div id="progress_bar">
1855
						<div id="overall_text">', $incontext['overall_percent'], '%</div>
1856
						<div id="overall_progress" style="width: ', $incontext['overall_percent'], '%;">
1857
							<span>'. $txt['upgrade_overall_progress'], '</span>
1858
						</div>
1859
					</div>
1860
					<div id="main_screen" class="clear">
1861
						<h2>', $incontext['page_title'], '</h2>
1862
						<div class="panel">';
1863
}
1864
1865
function template_install_below()
1866
{
1867
	global $incontext, $txt;
1868
1869
	if (!empty($incontext['continue']) || !empty($incontext['skip']))
1870
	{
1871
		echo '
1872
								<div>';
1873
1874
		if (!empty($incontext['continue']))
1875
			echo '
1876
									<input type="submit" id="contbutt" name="contbutt" value="', $txt['upgrade_continue'], '" onclick="return submitThisOnce(this);" class="button_submit" />';
1877
		if (!empty($incontext['skip']))
1878
			echo '
1879
									<input type="submit" id="skip" name="skip" value="', $txt['upgrade_skip'], '" onclick="return submitThisOnce(this);" class="button_submit" />';
1880
		echo '
1881
								</div>';
1882
	}
1883
1884
	// Show the closing form tag and other data only if not in the last step
1885
	if (count($incontext['steps']) - 1 !== (int) $incontext['current_step'])
1886
		echo '
1887
							</form>';
1888
1889
	echo '
1890
						</div>
1891
					</div>
1892
				</div>
1893
			</div>
1894
		</div></div>
1895
		<div id="footer">
1896
			<ul>
1897
				<li class="copyright"><a href="https://www.simplemachines.org/" title="Simple Machines Forum" target="_blank" class="new_win">SMF &copy; 2017, Simple Machines</a></li>
1898
			</ul>
1899
		</div>
1900
	</body>
1901
</html>';
1902
}
1903
1904
// Welcome them to the wonderful world of SMF!
1905
function template_welcome_message()
1906
{
1907
	global $incontext, $txt;
1908
1909
	echo '
1910
	<script src="https://www.simplemachines.org/smf/current-version.js?version=' . $GLOBALS['current_smf_version'] . '"></script>
1911
	<form action="', $incontext['form_url'], '" method="post">
1912
		<p>', sprintf($txt['install_welcome_desc'], $GLOBALS['current_smf_version']), '</p>
1913
		<div id="version_warning" style="margin: 2ex; padding: 2ex; border: 2px dashed #a92174; color: black; background-color: #fbbbe2; display: none;">
1914
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
1915
			<strong style="text-decoration: underline;">', $txt['error_warning_notice'], '</strong><br>
1916
			<div style="padding-left: 6ex;">
1917
				', 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>'), '
1918
			</div>
1919
		</div>';
1920
1921
	// Show the warnings, or not.
1922
	if (template_warning_divs())
1923
		echo '
1924
		<h3>', $txt['install_all_lovely'], '</h3>';
1925
1926
	// Say we want the continue button!
1927
	if (empty($incontext['error']))
1928
		$incontext['continue'] = 1;
1929
1930
	// For the latest version stuff.
1931
	echo '
1932
		<script>
1933
			// Latest version?
1934
			function smfCurrentVersion()
1935
			{
1936
				var smfVer, yourVer;
1937
1938
				if (!(\'smfVersion\' in window))
1939
					return;
1940
1941
				window.smfVersion = window.smfVersion.replace(/SMF\s?/g, \'\');
1942
1943
				smfVer = document.getElementById("smfVersion");
1944
				yourVer = document.getElementById("yourVersion");
1945
1946
				setInnerHTML(smfVer, window.smfVersion);
1947
1948
				var currentVersion = getInnerHTML(yourVer);
1949
				if (currentVersion < window.smfVersion)
1950
					document.getElementById(\'version_warning\').style.display = \'\';
1951
			}
1952
			addLoadEvent(smfCurrentVersion);
1953
		</script>';
1954
}
1955
1956
// A shortcut for any warning stuff.
1957
function template_warning_divs()
1958
{
1959
	global $txt, $incontext;
1960
1961
	// Errors are very serious..
1962
	if (!empty($incontext['error']))
1963
		echo '
1964
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
1965
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
1966
			<strong style="text-decoration: underline;">', $txt['upgrade_critical_error'], '</strong><br>
1967
			<div style="padding-left: 6ex;">
1968
				', $incontext['error'], '
1969
			</div>
1970
		</div>';
1971
	// A warning message?
1972
	elseif (!empty($incontext['warning']))
1973
		echo '
1974
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
1975
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
1976
			<strong style="text-decoration: underline;">', $txt['upgrade_warning'], '</strong><br>
1977
			<div style="padding-left: 6ex;">
1978
				', $incontext['warning'], '
1979
			</div>
1980
		</div>';
1981
1982
	return empty($incontext['error']) && empty($incontext['warning']);
1983
}
1984
1985
function template_chmod_files()
1986
{
1987
	global $txt, $incontext;
1988
1989
	echo '
1990
		<p>', $txt['ftp_setup_why_info'], '</p>
1991
		<ul style="margin: 2.5ex; font-family: monospace;">
1992
			<li>', implode('</li>
1993
			<li>', $incontext['failed_files']), '</li>
1994
		</ul>';
1995
1996
	if (isset($incontext['systemos'], $incontext['detected_path']) && $incontext['systemos'] == 'linux')
1997
		echo '
1998
		<hr>
1999
		<p>', $txt['chmod_linux_info'], '</p>
2000
		<tt># chmod a+w ', implode(' ' . $incontext['detected_path'] . '/', $incontext['failed_files']), '</tt>';
2001
2002
	// This is serious!
2003
	if (!template_warning_divs())
2004
		return;
2005
2006
	echo '
2007
		<hr>
2008
		<p>', $txt['ftp_setup_info'], '</p>';
2009
2010
	if (!empty($incontext['ftp_errors']))
2011
		echo '
2012
		<div class="error_message">
2013
			', $txt['error_ftp_no_connect'], '<br><br>
2014
			<code>', implode('<br>', $incontext['ftp_errors']), '</code>
2015
		</div>
2016
		<br>';
2017
2018
	echo '
2019
		<form action="', $incontext['form_url'], '" method="post">
2020
			<table align="center" style="width: 520px; margin: 1em 0; padding: 0; border: 0">
2021
				<tr>
2022
					<td width="26%" valign="top" class="textbox"><label for="ftp_server">', $txt['ftp_server'], ':</label></td>
2023
					<td>
2024
						<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>
2025
						<input type="text" size="30" name="ftp_server" id="ftp_server" value="', $incontext['ftp']['server'], '" style="width: 70%;" class="input_text" />
2026
						<div class="smalltext block">', $txt['ftp_server_info'], '</div>
2027
					</td>
2028
				</tr><tr>
2029
					<td width="26%" valign="top" class="textbox"><label for="ftp_username">', $txt['ftp_username'], ':</label></td>
2030
					<td>
2031
						<input type="text" size="50" name="ftp_username" id="ftp_username" value="', $incontext['ftp']['username'], '" style="width: 99%;" class="input_text" />
2032
						<div class="smalltext block">', $txt['ftp_username_info'], '</div>
2033
					</td>
2034
				</tr><tr>
2035
					<td width="26%" valign="top" class="textbox"><label for="ftp_password">', $txt['ftp_password'], ':</label></td>
2036
					<td>
2037
						<input type="password" size="50" name="ftp_password" id="ftp_password" style="width: 99%;" class="input_password" />
2038
						<div class="smalltext block">', $txt['ftp_password_info'], '</div>
2039
					</td>
2040
				</tr><tr>
2041
					<td width="26%" valign="top" class="textbox"><label for="ftp_path">', $txt['ftp_path'], ':</label></td>
2042
					<td style="padding-bottom: 1ex;">
2043
						<input type="text" size="50" name="ftp_path" id="ftp_path" value="', $incontext['ftp']['path'], '" style="width: 99%;" class="input_text" />
2044
						<div class="smalltext block">', $incontext['ftp']['path_msg'], '</div>
2045
					</td>
2046
				</tr>
2047
			</table>
2048
			<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>
2049
		</form>
2050
		<a href="', $incontext['form_url'], '">', $txt['error_message_click'], '</a> ', $txt['ftp_setup_again'];
2051
}
2052
2053
// Get the database settings prepared.
2054
function template_database_settings()
2055
{
2056
	global $incontext, $txt;
2057
2058
	echo '
2059
	<form action="', $incontext['form_url'], '" method="post">
2060
		<p>', $txt['db_settings_info'], '</p>';
2061
2062
	template_warning_divs();
2063
2064
	echo '
2065
		<table width="100%" border="0" style="margin: 1em 0;">';
2066
2067
	// More than one database type?
2068
	if (count($incontext['supported_databases']) > 1)
2069
	{
2070
		echo '
2071
			<tr>
2072
				<td width="20%" valign="top" class="textbox"><label for="db_type_input">', $txt['db_settings_type'], ':</label></td>
2073
				<td>
2074
					<select name="db_type" id="db_type_input" onchange="toggleDBInput();">';
2075
2076
	foreach ($incontext['supported_databases'] as $key => $db)
2077
			echo '
2078
						<option value="', $key, '"', isset($_POST['db_type']) && $_POST['db_type'] == $key ? ' selected' : '', '>', $db['name'], '</option>';
2079
2080
	echo '
2081
					</select>
2082
					<div class="smalltext block">', $txt['db_settings_type_info'], '</div>
2083
				</td>
2084
			</tr>';
2085
	}
2086
	else
2087
	{
2088
		echo '
2089
			<tr style="display: none;">
2090
				<td>
2091
					<input type="hidden" name="db_type" value="', $incontext['db']['type'], '" />
2092
				</td>
2093
			</tr>';
2094
	}
2095
2096
	echo '
2097
			<tr id="db_server_contain">
2098
				<td width="20%" valign="top" class="textbox"><label for="db_server_input">', $txt['db_settings_server'], ':</label></td>
2099
				<td>
2100
					<input type="text" name="db_server" id="db_server_input" value="', $incontext['db']['server'], '" size="30" class="input_text" /><br>
2101
					<div class="smalltext block">', $txt['db_settings_server_info'], '</div>
2102
				</td>
2103
			</tr><tr id="db_port_contain">
2104
				<td width="20%" valign="top" class="textbox"><label for="db_port_input">', $txt['db_settings_port'], ':</label></td>
2105
				<td>
2106
					<input type="text" name="db_port" id="db_port_input" value="', $incontext['db']['port'], '"><br>
2107
					<div class="smalltext block">', $txt['db_settings_port_info'], '</div>
2108
				</td>
2109
			</tr><tr id="db_user_contain">
2110
				<td valign="top" class="textbox"><label for="db_user_input">', $txt['db_settings_username'], ':</label></td>
2111
				<td>
2112
					<input type="text" name="db_user" id="db_user_input" value="', $incontext['db']['user'], '" size="30" class="input_text" /><br>
2113
					<div class="smalltext block">', $txt['db_settings_username_info'], '</div>
2114
				</td>
2115
			</tr><tr id="db_passwd_contain">
2116
				<td valign="top" class="textbox"><label for="db_passwd_input">', $txt['db_settings_password'], ':</label></td>
2117
				<td>
2118
					<input type="password" name="db_passwd" id="db_passwd_input" value="', $incontext['db']['pass'], '" size="30" class="input_password" /><br>
2119
					<div class="smalltext block">', $txt['db_settings_password_info'], '</div>
2120
				</td>
2121
			</tr><tr id="db_name_contain">
2122
				<td valign="top" class="textbox"><label for="db_name_input">', $txt['db_settings_database'], ':</label></td>
2123
				<td>
2124
					<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>
2125
					<div class="smalltext block">', $txt['db_settings_database_info'], '
2126
					<span id="db_name_info_warning">', $txt['db_settings_database_info_note'], '</span></div>
2127
				</td>
2128
			</tr><tr id="db_filename_contain" style="display: none;">
2129
				<td valign="top" class="textbox"><label for="db_filename_input">', $txt['db_settings_database_file'], ':</label></td>
2130
				<td>
2131
					<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>
2132
					<div class="smalltext block">', $txt['db_settings_database_file_info'], '</div>
2133
				</td>
2134
			</tr><tr>
2135
				<td valign="top" class="textbox"><label for="db_prefix_input">', $txt['db_settings_prefix'], ':</label></td>
2136
				<td>
2137
					<input type="text" name="db_prefix" id="db_prefix_input" value="', $incontext['db']['prefix'], '" size="30" class="input_text" /><br>
2138
					<div class="smalltext block">', $txt['db_settings_prefix_info'], '</div>
2139
				</td>
2140
			</tr>
2141
		</table>';
2142
2143
	// Toggles a warning related to db names in PostgreSQL
2144
	echo '
2145
	<script>
2146
		function toggleDBInput()
2147
		{
2148
			if (document.getElementById(\'db_type_input\').value == \'postgresql\')
2149
				document.getElementById(\'db_name_info_warning\').style.display = \'none\';
2150
			else
2151
				document.getElementById(\'db_name_info_warning\').style.display = \'\';
2152
		}
2153
		toggleDBInput();
2154
	</script>';
2155
}
2156
2157
// Stick in their forum settings.
2158
function template_forum_settings()
2159
{
2160
	global $incontext, $txt;
2161
2162
	echo '
2163
	<form action="', $incontext['form_url'], '" method="post">
2164
		<h3>', $txt['install_settings_info'], '</h3>';
2165
2166
	template_warning_divs();
2167
2168
	echo '
2169
		<table style="width: 100%; margin: 1em 0;">
2170
			<tr>
2171
				<td class="textbox" style="width: 20%; vertical-align: top;">
2172
					<label for="mbname_input">', $txt['install_settings_name'], ':</label>
2173
				</td>
2174
				<td>
2175
					<input type="text" name="mbname" id="mbname_input" value="', $txt['install_settings_name_default'], '" size="65" class="input_text" />
2176
					<div class="smalltext block">', $txt['install_settings_name_info'], '</div>
2177
				</td>
2178
			</tr>
2179
			<tr>
2180
				<td class="textbox" style="vertical-align: top;">
2181
					<label for="boardurl_input">', $txt['install_settings_url'], ':</label>
2182
				</td>
2183
				<td>
2184
					<input type="text" name="boardurl" id="boardurl_input" value="', $incontext['detected_url'], '" size="65" class="input_text" />
2185
					<br>
2186
					<div class="smalltext block">', $txt['install_settings_url_info'], '</div>
2187
				</td>
2188
			</tr>
2189
			<tr>
2190
				<td class="textbox" style="vertical-align: top;">
2191
					<label for="reg_mode">', $txt['install_settings_reg_mode'], ':</label>
2192
				</td>
2193
				<td>
2194
					<select name="reg_mode" id="reg_mode">
2195
						<optgroup label="', $txt['install_settings_reg_modes'], ':">
2196
							<option value="0" selected>', $txt['install_settings_reg_immediate'], '</option>
2197
							<option value="1">', $txt['install_settings_reg_email'], '</option>
2198
							<option value="2">', $txt['install_settings_reg_admin'], '</option>
2199
							<option value="3">', $txt['install_settings_reg_disabled'], '</option>
2200
						</optgroup>
2201
					</select>
2202
					<br>
2203
					<div class="smalltext block">', $txt['install_settings_reg_mode_info'], '</div>
2204
				</td>
2205
			</tr>
2206
			<tr>
2207
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_compress'], ':</td>
2208
				<td>
2209
					<input type="checkbox" name="compress" id="compress_check" checked class="input_check" />&nbsp;
2210
					<label for="compress_check">', $txt['install_settings_compress_title'], '</label>
2211
					<br>
2212
					<div class="smalltext block">', $txt['install_settings_compress_info'], '</div>
2213
				</td>
2214
			</tr>
2215
			<tr>
2216
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_dbsession'], ':</td>
2217
				<td>
2218
					<input type="checkbox" name="dbsession" id="dbsession_check" checked class="input_check" />&nbsp;
2219
					<label for="dbsession_check">', $txt['install_settings_dbsession_title'], '</label>
2220
					<br>
2221
					<div class="smalltext block">', $incontext['test_dbsession'] ? $txt['install_settings_dbsession_info1'] : $txt['install_settings_dbsession_info2'], '</div>
2222
				</td>
2223
			</tr>
2224
			<tr>
2225
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_utf8'], ':</td>
2226
				<td>
2227
					<input type="checkbox" name="utf8" id="utf8_check"', $incontext['utf8_default'] ? ' checked' : '', ' class="input_check"', $incontext['utf8_required'] ? ' disabled' : '', ' />&nbsp;
2228
					<label for="utf8_check">', $txt['install_settings_utf8_title'], '</label>
2229
					<br>
2230
					<div class="smalltext block">', $txt['install_settings_utf8_info'], '</div>
2231
				</td>
2232
			</tr>
2233
			<tr>
2234
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_stats'], ':</td>
2235
				<td>
2236
					<input type="checkbox" name="stats" id="stats_check" class="input_check" />&nbsp;
2237
					<label for="stats_check">', $txt['install_settings_stats_title'], '</label>
2238
					<br>
2239
					<div class="smalltext block">', $txt['install_settings_stats_info'], '</div>
2240
				</td>
2241
			</tr>
2242
			<tr>
2243
				<td class="textbox" style="vertical-align: top;">', $txt['force_ssl'], ':</td>
2244
				<td>
2245
					<input type="checkbox" name="force_ssl" id="force_ssl" class="input_check" />&nbsp;
2246
					<label for="force_ssl">', $txt['force_ssl_label'], '</label>
2247
					<br>
2248
					<div class="smalltext block">', $txt['force_ssl_info'], '</div>
2249
				</td>
2250
			</tr>
2251
		</table>
2252
	';
2253
}
2254
2255
// Show results of the database population.
2256
function template_populate_database()
2257
{
2258
	global $incontext, $txt;
2259
2260
	echo '
2261
	<form action="', $incontext['form_url'], '" method="post">
2262
		<p>', !empty($incontext['was_refresh']) ? $txt['user_refresh_install_desc'] : $txt['db_populate_info'], '</p>';
2263
2264
	if (!empty($incontext['sql_results']))
2265
	{
2266
		echo '
2267
		<ul>
2268
			<li>', implode('</li><li>', $incontext['sql_results']), '</li>
2269
		</ul>';
2270
	}
2271
2272
	if (!empty($incontext['failures']))
2273
	{
2274
		echo '
2275
				<div style="color: red;">', $txt['error_db_queries'], '</div>
2276
				<ul>';
2277
2278
		foreach ($incontext['failures'] as $line => $fail)
2279
			echo '
2280
						<li><strong>', $txt['error_db_queries_line'], $line + 1, ':</strong> ', nl2br(htmlspecialchars($fail)), '</li>';
2281
2282
		echo '
2283
				</ul>';
2284
	}
2285
2286
	echo '
2287
		<p>', $txt['db_populate_info2'], '</p>';
2288
2289
	template_warning_divs();
2290
2291
	echo '
2292
	<input type="hidden" name="pop_done" value="1" />';
2293
}
2294
2295
// Create the admin account.
2296
function template_admin_account()
2297
{
2298
	global $incontext, $txt;
2299
2300
	echo '
2301
	<form action="', $incontext['form_url'], '" method="post">
2302
		<p>', $txt['user_settings_info'], '</p>';
2303
2304
	template_warning_divs();
2305
2306
	echo '
2307
		<table width="100%" border="0" style="margin: 2em 0;">
2308
			<tr>
2309
				<td width="18%" valign="top" class="textbox"><label for="username">', $txt['user_settings_username'], ':</label></td>
2310
				<td>
2311
					<input type="text" name="username" id="username" value="', $incontext['username'], '" size="40" class="input_text" />
2312
					<div class="smalltext block">', $txt['user_settings_username_info'], '</div>
2313
				</td>
2314
			</tr><tr>
2315
				<td valign="top" class="textbox"><label for="password1">', $txt['user_settings_password'], ':</label></td>
2316
				<td>
2317
					<input type="password" name="password1" id="password1" size="40" class="input_password" />
2318
					<div class="smalltext block">', $txt['user_settings_password_info'], '</div>
2319
				</td>
2320
			</tr><tr>
2321
				<td valign="top" class="textbox"><label for="password2">', $txt['user_settings_again'], ':</label></td>
2322
				<td>
2323
					<input type="password" name="password2" id="password2" size="40" class="input_password" />
2324
					<div class="smalltext block">', $txt['user_settings_again_info'], '</div>
2325
				</td>
2326
			</tr><tr>
2327
				<td valign="top" class="textbox"><label for="email">', $txt['user_settings_admin_email'], ':</label></td>
2328
				<td>
2329
					<input type="text" name="email" id="email" value="', $incontext['email'], '" size="40" class="input_text" />
2330
					<div class="smalltext block">', $txt['user_settings_admin_email_info'], '</div>
2331
				</td>
2332
			</tr><tr>
2333
				<td valign="top" class="textbox"><label for="server_email">', $txt['user_settings_server_email'], ':</label></td>
2334
				<td>
2335
					<input type="text" name="server_email" id="server_email" value="', $incontext['server_email'], '" size="40" class="input_text" />
2336
					<div class="smalltext block">', $txt['user_settings_server_email_info'], '</div>
2337
				</td>
2338
			</tr>
2339
		</table>';
2340
2341
	if ($incontext['require_db_confirm'])
2342
		echo '
2343
		<h2>', $txt['user_settings_database'], '</h2>
2344
		<p>', $txt['user_settings_database_info'], '</p>
2345
2346
		<div style="margin-bottom: 2ex; padding-', $txt['lang_rtl'] == false ? 'left' : 'right', ': 50px;">
2347
			<input type="password" name="password3" size="30" class="input_password" />
2348
		</div>';
2349
}
2350
2351
// Tell them it's done, and to delete.
2352
function template_delete_install()
2353
{
2354
	global $incontext, $installurl, $txt, $boardurl;
2355
2356
	echo '
2357
		<p>', $txt['congratulations_help'], '</p>';
2358
2359
	template_warning_divs();
2360
2361
	// Install directory still writable?
2362
	if ($incontext['dir_still_writable'])
2363
		echo '
2364
		<em>', $txt['still_writable'], '</em><br>
2365
		<br>';
2366
2367
	// Don't show the box if it's like 99% sure it won't work :P.
2368
	if ($incontext['probably_delete_install'])
2369
		echo '
2370
		<div style="margin: 1ex; font-weight: bold;">
2371
			<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>
2372
		</div>
2373
		<script>
2374
			function doTheDelete()
2375
			{
2376
				var theCheck = document.getElementById ? document.getElementById("delete_self") : document.all.delete_self;
2377
				var tempImage = new Image();
2378
2379
				tempImage.src = "', $installurl, '?delete=1&ts_" + (new Date().getTime());
2380
				tempImage.width = 0;
2381
				theCheck.disabled = true;
2382
			}
2383
		</script>
2384
		<br>';
2385
2386
	echo '
2387
		', sprintf($txt['go_to_your_forum'], $boardurl . '/index.php'), '<br>
2388
		<br>
2389
		', $txt['good_luck'];
2390
}
2391
2392
?>
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...
2393