Failed Conditions
Branch release-2.1 (4e22cf)
by Rick
06:39
created

install.php ➔ load_database()   F

Complexity

Conditions 13
Paths 392

Size

Total Lines 48
Code Lines 26

Duplication

Lines 5
Ratio 10.42 %

Importance

Changes 0
Metric Value
cc 13
eloc 26
nc 392
nop 0
dl 5
loc 48
rs 3.7737
c 0
b 0
f 0

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Simple Machines Forum (SMF)
5
 *
6
 * @package SMF
7
 * @author Simple Machines http://www.simplemachines.org
8
 * @copyright 2017 Simple Machines and individual contributors
9
 * @license http://www.simplemachines.org/about/smf/license.php BSD
10
 *
11
 * @version 2.1 Beta 4
12
 */
13
14
$GLOBALS['current_smf_version'] = '2.1 Beta 4';
15
$GLOBALS['db_script_version'] = '2-1';
16
17
$GLOBALS['required_php_version'] = '5.4.0';
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')
0 ignored issues
show
Coding Style introduced by
The if-else statement can be simplified to return $charcode == 'UTF8';.
Loading history...
67
				return true;
68
			else
69
				return false;
70
		},
71
		'utf8_version' => '8.0',
72
		'utf8_version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
73
		'validate_prefix' => function(&$value) {
74
			global $txt;
75
76
			$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
77
78
			// Is it reserved?
79
			if ($value == 'pg_')
80
				return $txt['error_db_prefix_reserved'];
81
82
			// Is the prefix numeric?
83
			if (preg_match('~^\d~', $value))
84
				return $txt['error_db_prefix_numeric'];
85
86
			return true;
87
		},
88
	),
89
);
90
91
global $txt;
92
93
// Initialize everything and load the language files.
94
initialize_inputs();
95
load_lang_file();
96
97
// This is what we are.
98
$installurl = $_SERVER['PHP_SELF'];
99
100
// All the steps in detail.
101
// Number,Name,Function,Progress Weight.
102
$incontext['steps'] = array(
103
	0 => array(1, $txt['install_step_welcome'], 'Welcome', 0),
104
	1 => array(2, $txt['install_step_writable'], 'CheckFilesWritable', 10),
105
	2 => array(3, $txt['install_step_databaseset'], 'DatabaseSettings', 15),
106
	3 => array(4, $txt['install_step_forum'], 'ForumSettings', 40),
107
	4 => array(5, $txt['install_step_databasechange'], 'DatabasePopulation', 15),
108
	5 => array(6, $txt['install_step_admin'], 'AdminAccount', 20),
109
	6 => array(7, $txt['install_step_delete'], 'DeleteInstall', 0),
110
);
111
112
// Default title...
113
$incontext['page_title'] = $txt['smf_installer'];
114
115
// What step are we on?
116
$incontext['current_step'] = isset($_GET['step']) ? (int) $_GET['step'] : 0;
117
118
// Loop through all the steps doing each one as required.
119
$incontext['overall_percent'] = 0;
120
121
foreach ($incontext['steps'] as $num => $step)
122
{
123
	if ($num >= $incontext['current_step'])
124
	{
125
		// The current weight of this step in terms of overall progress.
126
		$incontext['step_weight'] = $step[3];
127
		// Make sure we reset the skip button.
128
		$incontext['skip'] = false;
129
130
		// Call the step and if it returns false that means pause!
131
		if (function_exists($step[2]) && $step[2]() === false)
132
			break;
133
		elseif (function_exists($step[2]))
134
			$incontext['current_step']++;
135
136
		// No warnings pass on.
137
		$incontext['warning'] = '';
138
	}
139
	$incontext['overall_percent'] += $step[3];
140
}
141
142
// Actually do the template stuff.
143
installExit();
144
145
function initialize_inputs()
146
{
147
	global $databases;
148
149
	// Just so people using older versions of PHP aren't left in the cold.
150
	if (!isset($_SERVER['PHP_SELF']))
151
		$_SERVER['PHP_SELF'] = isset($GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']) ? $GLOBALS['HTTP_SERVER_VARS']['PHP_SELF'] : 'install.php';
152
153
	// Enable error reporting.
154
	error_reporting(E_ALL);
155
156
	// Fun.  Low PHP version...
157
	if (!isset($_GET))
158
	{
159
		$GLOBALS['_GET']['step'] = 0;
160
		return;
161
	}
162
163
	if (!isset($_GET['obgz']))
164
	{
165
		ob_start();
166
167
		if (ini_get('session.save_handler') == 'user')
168
			@ini_set('session.save_handler', 'files');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
227
			}
228
		}
229
230
		// Now just redirect to a blank.png...
231
		header('Location: http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png');
232
		exit;
233
	}
234
235
	// PHP 5 might cry if we don't do this now.
236
	if (function_exists('date_default_timezone_set'))
237
	{
238
		// Get PHP's default timezone, if set
239
		$ini_tz = ini_get('date.timezone');
240
		if (!empty($ini_tz))
241
			$timezone_id = $ini_tz;
242
		else
243
			$timezone_id = '';
244
245
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
246 View Code Duplication
		if (!in_array($timezone_id, timezone_identifiers_list()))
247
		{
248
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
249
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
250
		}
251
252
		date_default_timezone_set($timezone_id);
253
	}
254
255
	// Force an integer step, defaulting to 0.
256
	$_GET['step'] = (int) @$_GET['step'];
257
}
258
259
// Load the list of language files, and the current language file.
260
function load_lang_file()
261
{
262
	global $txt, $incontext;
263
264
	$incontext['detected_languages'] = array();
265
266
	// Make sure the languages directory actually exists.
267
	if (file_exists(dirname(__FILE__) . '/Themes/default/languages'))
268
	{
269
		// Find all the "Install" language files in the directory.
270
		$dir = dir(dirname(__FILE__) . '/Themes/default/languages');
271
		while ($entry = $dir->read())
272
		{
273
			if (substr($entry, 0, 8) == 'Install.' && substr($entry, -4) == '.php')
274
				$incontext['detected_languages'][$entry] = ucfirst(substr($entry, 8, strlen($entry) - 12));
275
		}
276
		$dir->close();
277
	}
278
279
	// Didn't find any, show an error message!
280
	if (empty($incontext['detected_languages']))
281
	{
282
		// Let's not cache this message, eh?
283
		header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
284
		header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
285
		header('Cache-Control: no-cache');
286
287
		echo '<!DOCTYPE html>
288
<html>
289
	<head>
290
		<title>SMF Installer: Error!</title>
291
	</head>
292
	<body style="font-family: sans-serif;"><div style="width: 600px;">
293
		<h1 style="font-size: 14pt;">A critical error has occurred.</h1>
294
295
		<p>This installer was unable to find the installer\'s language file or files.  They should be found under:</p>
296
297
		<div style="margin: 1ex; font-family: monospace; font-weight: bold;">', dirname($_SERVER['PHP_SELF']) != '/' ? dirname($_SERVER['PHP_SELF']) : '', '/Themes/default/languages</div>
298
299
		<p>In some cases, FTP clients do not properly upload files with this many folders.  Please double check to make sure you <span style="font-weight: 600;">have uploaded all the files in the distribution</span>.</p>
300
		<p>If that doesn\'t help, please make sure this install.php file is in the same place as the Themes folder.</p>
301
302
		<p>If you continue to get this error message, feel free to <a href="https://support.simplemachines.org/">look to us for support</a>.</p>
303
	</div></body>
304
</html>';
305
		die;
306
	}
307
308
	// Override the language file?
309
	if (isset($_GET['lang_file']))
310
		$_SESSION['installer_temp_lang'] = $_GET['lang_file'];
311
	elseif (isset($GLOBALS['HTTP_GET_VARS']['lang_file']))
312
		$_SESSION['installer_temp_lang'] = $GLOBALS['HTTP_GET_VARS']['lang_file'];
313
314
	// Make sure it exists, if it doesn't reset it.
315
	if (!isset($_SESSION['installer_temp_lang']) || preg_match('~[^\\w_\\-.]~', $_SESSION['installer_temp_lang']) === 1 || !file_exists(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']))
316
	{
317
		// Use the first one...
318
		list ($_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
319
320
		// If we have english and some other language, use the other language.  We Americans hate english :P.
321
		if ($_SESSION['installer_temp_lang'] == 'Install.english.php' && count($incontext['detected_languages']) > 1)
322
			list (, $_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
323
	}
324
325
	// And now include the actual language file itself.
326
	require_once(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']);
327
}
328
329
// This handy function loads some settings and the like.
330
function load_database()
331
{
332
	global $db_prefix, $db_connection, $sourcedir, $smcFunc, $modSettings;
333
	global $db_server, $db_passwd, $db_type, $db_name, $db_user, $db_persist;
334
335
	if (empty($sourcedir))
336
		$sourcedir = dirname(__FILE__) . '/Sources';
337
338
	// Need this to check whether we need the database password.
339
	require(dirname(__FILE__) . '/Settings.php');
340
	if (!defined('SMF'))
341
		define('SMF', 1);
342
	if (empty($smcFunc))
343
		$smcFunc = array();
344
345
	$modSettings['disableQueryCheck'] = true;
346
347
	// Connect the database.
348
	if (!$db_connection)
349
	{
350
		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
351
		if (version_compare(PHP_VERSION, '5', '<'))
352
			require_once($sourcedir . '/Subs-Compat.php');
353
354
		$db_options = array('persist' => $db_persist);
355
		$port = '';
356
357
		// Figure out the port...
358
		if (!empty($_POST['db_port']))
359
		{
360
			if ($db_type == 'mysql')
361
			{
362
				$port = ((int) $_POST['db_port'] == ini_get($db_type . 'default_port')) ? '' : (int) $_POST['db_port'];
363
			}
364 View Code Duplication
			elseif ($db_type == 'postgresql')
365
			{
366
				// PostgreSQL doesn't have a default port setting in php.ini, so just check against the default
367
				$port = ((int) $_POST['db_port'] == 5432) ? '' : (int) $_POST['db_port'];
368
			}
369
		}
370
371
		if (!empty($port))
372
			$db_options['port'] = $port;
373
374
		if (!$db_connection)
375
			$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options);
376
	}
377
}
378
379
// This is called upon exiting the installer, for template etc.
380
function installExit($fallThrough = false)
381
{
382
	global $incontext, $installurl, $txt;
383
384
	// Send character set.
385
	header('Content-Type: text/html; charset=' . (isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8'));
386
387
	// We usually dump our templates out.
388
	if (!$fallThrough)
389
	{
390
		// The top install bit.
391
		template_install_above();
392
393
		// Call the template.
394
		if (isset($incontext['sub_template']))
395
		{
396
			$incontext['form_url'] = $installurl . '?step=' . $incontext['current_step'];
397
398
			call_user_func('template_' . $incontext['sub_template']);
399
		}
400
		// @todo REMOVE THIS!!
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
401
		else
402
		{
403
			if (function_exists('doStep' . $_GET['step']))
404
				call_user_func('doStep' . $_GET['step']);
405
		}
406
		// Show the footer.
407
		template_install_below();
408
	}
409
410
	// Bang - gone!
411
	die();
412
}
413
414
function Welcome()
415
{
416
	global $incontext, $txt, $databases, $installurl;
417
418
	$incontext['page_title'] = $txt['install_welcome'];
419
	$incontext['sub_template'] = 'welcome_message';
420
421
	// Done the submission?
422
	if (isset($_POST['contbutt']))
423
		return true;
424
425
	// See if we think they have already installed it?
426
	if (is_readable(dirname(__FILE__) . '/Settings.php'))
427
	{
428
		$probably_installed = 0;
429
		foreach (file(dirname(__FILE__) . '/Settings.php') as $line)
430
		{
431
			if (preg_match('~^\$db_passwd\s=\s\'([^\']+)\';$~', $line))
432
				$probably_installed++;
433
			if (preg_match('~^\$boardurl\s=\s\'([^\']+)\';~', $line) && !preg_match('~^\$boardurl\s=\s\'http://127\.0\.0\.1/smf\';~', $line))
434
				$probably_installed++;
435
		}
436
437
		if ($probably_installed == 2)
438
			$incontext['warning'] = $txt['error_already_installed'];
439
	}
440
441
	// Is some database support even compiled in?
442
	$incontext['supported_databases'] = array();
443
	foreach ($databases as $key => $db)
444
	{
445
		if ($db['supported'])
446
		{
447
			$type = ($key == 'mysqli') ? 'mysql' : $key;
448
			if (!file_exists(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql'))
449
			{
450
				$databases[$key]['supported'] = false;
451
				$notFoundSQLFile = true;
452
				$txt['error_db_script_missing'] = sprintf($txt['error_db_script_missing'], 'install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
453
			}
454
			else
455
				$incontext['supported_databases'][] = $db;
456
		}
457
	}
458
459
	// Check the PHP version.
460
	if ((!function_exists('version_compare') || version_compare($GLOBALS['required_php_version'], PHP_VERSION, '>=')))
461
		$error = 'error_php_too_low';
462
	// Make sure we have a supported database
463
	elseif (empty($incontext['supported_databases']))
464
		$error = empty($notFoundSQLFile) ? 'error_db_missing' : 'error_db_script_missing';
465
	// How about session support?  Some crazy sysadmin remove it?
466
	elseif (!function_exists('session_start'))
467
		$error = 'error_session_missing';
468
	// Make sure they uploaded all the files.
469
	elseif (!file_exists(dirname(__FILE__) . '/index.php'))
470
		$error = 'error_missing_files';
471
	// Very simple check on the session.save_path for Windows.
472
	// @todo Move this down later if they don't use database-driven sessions?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
473
	elseif (@ini_get('session.save_path') == '/tmp' && substr(__FILE__, 1, 2) == ':\\')
474
		$error = 'error_session_save_path';
475
476
	// Since each of the three messages would look the same, anyway...
477
	if (isset($error))
478
		$incontext['error'] = $txt[$error];
479
480
	// Mod_security blocks everything that smells funny. Let SMF handle security.
481
	if (!fixModSecurity() && !isset($_GET['overmodsecurity']))
482
		$incontext['error'] = $txt['error_mod_security'] . '<br><br><a href="' . $installurl . '?overmodsecurity=true">' . $txt['error_message_click'] . '</a> ' . $txt['error_message_bad_try_again'];
483
484
	// Confirm mbstring is loaded...
485
	if (!extension_loaded('mbstring'))
486
		$incontext['error'] = $txt['install_no_mbstring'];
487
488
	// Check for https stream support.
489
	$supported_streams = stream_get_wrappers();
490
	if (!in_array('https', $supported_streams))
491
		$incontext['warning'] = $txt['install_no_https'];
492
493
	return false;
494
}
495
496
function CheckFilesWritable()
497
{
498
	global $txt, $incontext;
499
500
	$incontext['page_title'] = $txt['ftp_checking_writable'];
501
	$incontext['sub_template'] = 'chmod_files';
502
503
	$writable_files = array(
504
		'attachments',
505
		'avatars',
506
		'custom_avatar',
507
		'cache',
508
		'Packages',
509
		'Smileys',
510
		'Themes',
511
		'agreement.txt',
512
		'Settings.php',
513
		'Settings_bak.php',
514
		'db_last_error.php',
515
	);
516
517
	foreach ($incontext['detected_languages'] as $lang => $temp)
518
		$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...
519
520
	// With mod_security installed, we could attempt to fix it with .htaccess.
521
	if (function_exists('apache_get_modules') && in_array('mod_security', apache_get_modules()))
522
		$writable_files[] = file_exists(dirname(__FILE__) . '/.htaccess') ? '.htaccess' : '.';
523
524
	$failed_files = array();
525
526
	// On linux, it's easy - just use is_writable!
527
	if (substr(__FILE__, 1, 2) != ':\\')
528
	{
529
		$incontext['systemos'] = 'linux';
530
531
		foreach ($writable_files as $file)
532
		{
533
			// Some files won't exist, try to address up front
534
			if (!file_exists(dirname(__FILE__) . '/' . $file))
535
				@touch(dirname(__FILE__) . '/' . $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...
536
			// NOW do the writable check...
537
			if (!is_writable(dirname(__FILE__) . '/' . $file))
538
			{
539
				@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...
540
541
				// 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...
542
				if (!is_writable(dirname(__FILE__) . '/' . $file) && !@chmod(dirname(__FILE__) . '/' . $file, 0777))
543
					$failed_files[] = $file;
544
			}
545
		}
546 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...
547
			@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...
548
	}
549
	// Windows is trickier.  Let's try opening for r+...
550
	else
551
	{
552
		$incontext['systemos'] = 'windows';
553
554
		foreach ($writable_files as $file)
555
		{
556
			// Folders can't be opened for write... but the index.php in them can ;)
557
			if (is_dir(dirname(__FILE__) . '/' . $file))
558
				$file .= '/index.php';
559
560
			// Funny enough, chmod actually does do something on windows - it removes the read only attribute.
561
			@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...
562
			$fp = @fopen(dirname(__FILE__) . '/' . $file, 'r+');
563
564
			// Hmm, okay, try just for write in that case...
565
			if (!is_resource($fp))
566
				$fp = @fopen(dirname(__FILE__) . '/' . $file, 'w');
567
568
			if (!is_resource($fp))
569
				$failed_files[] = $file;
570
571
			@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...
572
		}
573 View Code Duplication
		foreach ($extra_files as $file)
574
			@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...
575
	}
576
577
	$failure = count($failed_files) >= 1;
578
579
	if (!isset($_SERVER))
580
		return !$failure;
581
582
	// Put the list into context.
583
	$incontext['failed_files'] = $failed_files;
584
585
	// It's not going to be possible to use FTP on windows to solve the problem...
586
	if ($failure && substr(__FILE__, 1, 2) == ':\\')
587
	{
588
		$incontext['error'] = $txt['error_windows_chmod'] . '
589
					<ul style="margin: 2.5ex; font-family: monospace;">
590
						<li>' . implode('</li>
591
						<li>', $failed_files) . '</li>
592
					</ul>';
593
594
		return false;
595
	}
596
	// We're going to have to use... FTP!
597
	elseif ($failure)
598
	{
599
		// Load any session data we might have...
600 View Code Duplication
		if (!isset($_POST['ftp_username']) && isset($_SESSION['installer_temp_ftp']))
601
		{
602
			$_POST['ftp_server'] = $_SESSION['installer_temp_ftp']['server'];
603
			$_POST['ftp_port'] = $_SESSION['installer_temp_ftp']['port'];
604
			$_POST['ftp_username'] = $_SESSION['installer_temp_ftp']['username'];
605
			$_POST['ftp_password'] = $_SESSION['installer_temp_ftp']['password'];
606
			$_POST['ftp_path'] = $_SESSION['installer_temp_ftp']['path'];
607
		}
608
609
		$incontext['ftp_errors'] = array();
610
		require_once('Sources/Class-Package.php');
611 View Code Duplication
		if (isset($_POST['ftp_username']))
612
		{
613
			$ftp = new ftp_connection($_POST['ftp_server'], $_POST['ftp_port'], $_POST['ftp_username'], $_POST['ftp_password']);
614
615
			if ($ftp->error === false)
616
			{
617
				// Try it without /home/abc just in case they messed up.
618
				if (!$ftp->chdir($_POST['ftp_path']))
619
				{
620
					$incontext['ftp_errors'][] = $ftp->last_message;
621
					$ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $_POST['ftp_path']));
622
				}
623
			}
624
		}
625
626
		if (!isset($ftp) || $ftp->error !== false)
627
		{
628
			if (!isset($ftp))
629
				$ftp = new ftp_connection(null);
630
			// Save the error so we can mess with listing...
631
			elseif ($ftp->error !== false && empty($incontext['ftp_errors']) && !empty($ftp->last_message))
632
				$incontext['ftp_errors'][] = $ftp->last_message;
633
634
			list ($username, $detect_path, $found_path) = $ftp->detect_path(dirname(__FILE__));
635
636
			if (empty($_POST['ftp_path']) && $found_path)
637
				$_POST['ftp_path'] = $detect_path;
638
639
			if (!isset($_POST['ftp_username']))
640
				$_POST['ftp_username'] = $username;
641
642
			// Set the username etc, into context.
643
			$incontext['ftp'] = array(
644
				'server' => isset($_POST['ftp_server']) ? $_POST['ftp_server'] : 'localhost',
645
				'port' => isset($_POST['ftp_port']) ? $_POST['ftp_port'] : '21',
646
				'username' => isset($_POST['ftp_username']) ? $_POST['ftp_username'] : '',
647
				'path' => isset($_POST['ftp_path']) ? $_POST['ftp_path'] : '/',
648
				'path_msg' => !empty($found_path) ? $txt['ftp_path_found_info'] : $txt['ftp_path_info'],
649
			);
650
651
			return false;
652
		}
653
		else
654
		{
655
			$_SESSION['installer_temp_ftp'] = array(
656
				'server' => $_POST['ftp_server'],
657
				'port' => $_POST['ftp_port'],
658
				'username' => $_POST['ftp_username'],
659
				'password' => $_POST['ftp_password'],
660
				'path' => $_POST['ftp_path']
661
			);
662
663
			$failed_files_updated = array();
664
665
			foreach ($failed_files as $file)
666
			{
667
				if (!is_writable(dirname(__FILE__) . '/' . $file))
668
					$ftp->chmod($file, 0755);
669
				if (!is_writable(dirname(__FILE__) . '/' . $file))
670
					$ftp->chmod($file, 0777);
671
				if (!is_writable(dirname(__FILE__) . '/' . $file))
672
				{
673
					$failed_files_updated[] = $file;
674
					$incontext['ftp_errors'][] = rtrim($ftp->last_message) . ' -> ' . $file . "\n";
675
				}
676
			}
677
678
			$ftp->close();
679
680
			// Are there any errors left?
681
			if (count($failed_files_updated) >= 1)
682
			{
683
				// Guess there are...
684
				$incontext['failed_files'] = $failed_files_updated;
685
686
				// Set the username etc, into context.
687
				$incontext['ftp'] = $_SESSION['installer_temp_ftp'] += array(
688
					'path_msg' => $txt['ftp_path_info'],
689
				);
690
691
				return false;
692
			}
693
		}
694
	}
695
696
	return true;
697
}
698
699
function DatabaseSettings()
700
{
701
	global $txt, $databases, $incontext, $smcFunc, $sourcedir;
702
	global $db_server, $db_name, $db_user, $db_passwd;
703
704
	$incontext['sub_template'] = 'database_settings';
705
	$incontext['page_title'] = $txt['db_settings'];
706
	$incontext['continue'] = 1;
707
708
	// Set up the defaults.
709
	$incontext['db']['server'] = 'localhost';
710
	$incontext['db']['user'] = '';
711
	$incontext['db']['name'] = '';
712
	$incontext['db']['pass'] = '';
713
	$incontext['db']['type'] = '';
714
	$incontext['supported_databases'] = array();
715
716
	$foundOne = false;
717
	foreach ($databases as $key => $db)
718
	{
719
		// Override with the defaults for this DB if appropriate.
720
		if ($db['supported'])
721
		{
722
			$incontext['supported_databases'][$key] = $db;
723
724
			if (!$foundOne)
725
			{
726
				if (isset($db['default_host']))
727
					$incontext['db']['server'] = ini_get($db['default_host']) or $incontext['db']['server'] = 'localhost';
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
728
				if (isset($db['default_user']))
729
				{
730
					$incontext['db']['user'] = ini_get($db['default_user']);
731
					$incontext['db']['name'] = ini_get($db['default_user']);
732
				}
733
				if (isset($db['default_password']))
734
					$incontext['db']['pass'] = ini_get($db['default_password']);
735
736
				// For simplicity and less confusion, leave the port blank by default
737
				$incontext['db']['port'] = '';
738
739
				$incontext['db']['type'] = $key;
740
				$foundOne = true;
741
			}
742
		}
743
	}
744
745
	// Override for repost.
746
	if (isset($_POST['db_user']))
747
	{
748
		$incontext['db']['user'] = $_POST['db_user'];
749
		$incontext['db']['name'] = $_POST['db_name'];
750
		$incontext['db']['server'] = $_POST['db_server'];
751
		$incontext['db']['prefix'] = $_POST['db_prefix'];
752
753
		if (!empty($_POST['db_port']))
754
			$incontext['db']['port'] = $_POST['db_port'];
755
	}
756
	else
757
	{
758
		$incontext['db']['prefix'] = 'smf_';
759
	}
760
761
	// Are we submitting?
762
	if (isset($_POST['db_type']))
763
	{
764
		// What type are they trying?
765
		$db_type = preg_replace('~[^A-Za-z0-9]~', '', $_POST['db_type']);
766
		$db_prefix = $_POST['db_prefix'];
767
		// Validate the prefix.
768
		$valid_prefix = $databases[$db_type]['validate_prefix']($db_prefix);
769
770
		if ($valid_prefix !== true)
771
		{
772
			$incontext['error'] = $valid_prefix;
773
			return false;
774
		}
775
776
		// Take care of these variables...
777
		$vars = array(
778
			'db_type' => $db_type,
779
			'db_name' => $_POST['db_name'],
780
			'db_user' => $_POST['db_user'],
781
			'db_passwd' => isset($_POST['db_passwd']) ? $_POST['db_passwd'] : '',
782
			'db_server' => $_POST['db_server'],
783
			'db_prefix' => $db_prefix,
784
			// The cookiename is special; we want it to be the same if it ever needs to be reinstalled with the same info.
785
			'cookiename' => 'SMFCookie' . abs(crc32($_POST['db_name'] . preg_replace('~[^A-Za-z0-9_$]~', '', $_POST['db_prefix'])) % 1000),
786
		);
787
788
		// Only set the port if we're not using the default
789
		if (!empty($_POST['db_port']))
790
		{
791
			// For MySQL, we can get the "default port" from PHP. PostgreSQL has no such option though.
792
			if (($db_type == 'mysql' || $db_type == 'mysqli') && $_POST['db_port'] != ini_get($db_type . '.default_port'))
793
				$vars['db_port'] = (int) $_POST['db_port'];
794 View Code Duplication
			elseif ($db_type == 'postgresql' && $_POST['db_port'] != 5432)
795
				$vars['db_port'] = (int) $_POST['db_port'];
796
		}
797
798
		// God I hope it saved!
799 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
800
		{
801
			$incontext['error'] = $txt['error_windows_chmod'];
802
			return false;
803
		}
804
805
		// Make sure it works.
806
		require(dirname(__FILE__) . '/Settings.php');
807
808
		if (empty($sourcedir))
809
			$sourcedir = dirname(__FILE__) . '/Sources';
810
811
		// Better find the database file!
812
		if (!file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php'))
813
		{
814
			$incontext['error'] = sprintf($txt['error_db_file'], 'Subs-Db-' . $db_type . '.php');
815
			return false;
816
		}
817
818
		// Now include it for database functions!
819
		if (!defined('SMF'))
820
			define('SMF', 1);
821
822
		$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...
823
		if (empty($smcFunc))
824
			$smcFunc = array();
825
826
			require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
827
828
		// What - running PHP4? The shame!
829
		if (version_compare(PHP_VERSION, '5', '<'))
830
			require_once($sourcedir . '/Subs-Compat.php');
831
832
		// Attempt a connection.
833
		$needsDB = !empty($databases[$db_type]['always_has_db']);
834
		$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('non_fatal' => true, 'dont_select_db' => !$needsDB));
835
836
		// No dice?  Let's try adding the prefix they specified, just in case they misread the instructions ;)
837
		if ($db_connection == null)
838
		{
839
			$db_error = @$smcFunc['db_error']();
840
841
			$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));
842
			if ($db_connection != null)
843
			{
844
				$db_user = $_POST['db_prefix'] . $db_user;
845
				updateSettingsFile(array('db_user' => $db_user));
846
			}
847
		}
848
849
		// Still no connection?  Big fat error message :P.
850
		if (!$db_connection)
851
		{
852
			$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...
853
			return false;
854
		}
855
856
		// Do they meet the install requirements?
857
		// @todo Old client, new server?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
858
		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...
859
		{
860
			$incontext['error'] = $txt['error_db_too_low'];
861
			return false;
862
		}
863
864
		// Let's try that database on for size... assuming we haven't already lost the opportunity.
865
		if ($db_name != '' && !$needsDB)
866
		{
867
			$smcFunc['db_query']('', "
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $db_name instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
868
				CREATE DATABASE IF NOT EXISTS `$db_name`",
869
				array(
870
					'security_override' => true,
871
					'db_error_skip' => true,
872
				),
873
				$db_connection
874
			);
875
876
			// Okay, let's try the prefix if it didn't work...
877
			if (!$smcFunc['db_select_db']($db_name, $db_connection) && $db_name != '')
878
			{
879
				$smcFunc['db_query']('', "
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $_POST instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $db_name instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
880
					CREATE DATABASE IF NOT EXISTS `$_POST[db_prefix]$db_name`",
881
					array(
882
						'security_override' => true,
883
						'db_error_skip' => true,
884
					),
885
					$db_connection
886
				);
887
888
				if ($smcFunc['db_select_db']($_POST['db_prefix'] . $db_name, $db_connection))
889
				{
890
					$db_name = $_POST['db_prefix'] . $db_name;
891
					updateSettingsFile(array('db_name' => $db_name));
892
				}
893
			}
894
895
			// Okay, now let's try to connect...
896
			if (!$smcFunc['db_select_db']($db_name, $db_connection))
897
			{
898
				$incontext['error'] = sprintf($txt['error_db_database'], $db_name);
899
				return false;
900
			}
901
		}
902
903
		return true;
904
	}
905
906
	return false;
907
}
908
909
// Let's start with basic forum type settings.
910
function ForumSettings()
911
{
912
	global $txt, $incontext, $databases, $db_type, $db_connection;
913
914
	$incontext['sub_template'] = 'forum_settings';
915
	$incontext['page_title'] = $txt['install_settings'];
916
917
	// Let's see if we got the database type correct.
918
	if (isset($_POST['db_type'], $databases[$_POST['db_type']]))
919
		$db_type = $_POST['db_type'];
920
921
	// Else we'd better be able to get the connection.
922
	else
923
		load_database();
924
925
	$db_type = isset($_POST['db_type']) ? $_POST['db_type'] : $db_type;
926
927
	// What host and port are we on?
928
	$host = empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST'];
929
930
	// Now, to put what we've learned together... and add a path.
931
	$incontext['detected_url'] = 'http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . $host . substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
932
933
	// Check if the database sessions will even work.
934
	$incontext['test_dbsession'] = (ini_get('session.auto_start') != 1);
935
	$incontext['utf8_default'] = $databases[$db_type]['utf8_default'];
936
	$incontext['utf8_required'] = $databases[$db_type]['utf8_required'];
937
938
	$incontext['continue'] = 1;
939
940
	// Submitting?
941
	if (isset($_POST['boardurl']))
942
	{
943 View Code Duplication
		if (substr($_POST['boardurl'], -10) == '/index.php')
944
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -10);
945
		elseif (substr($_POST['boardurl'], -1) == '/')
946
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -1);
947 View Code Duplication
		if (substr($_POST['boardurl'], 0, 7) != 'http://' && substr($_POST['boardurl'], 0, 7) != 'file://' && substr($_POST['boardurl'], 0, 8) != 'https://')
948
			$_POST['boardurl'] = 'http://' . $_POST['boardurl'];
949
950
		// Save these variables.
951
		$vars = array(
952
			'boardurl' => $_POST['boardurl'],
953
			'boarddir' => addslashes(dirname(__FILE__)),
954
			'sourcedir' => addslashes(dirname(__FILE__)) . '/Sources',
955
			'cachedir' => addslashes(dirname(__FILE__)) . '/cache',
956
			'packagesdir' => addslashes(dirname(__FILE__)) . '/Packages',
957
			'tasksdir' => addslashes(dirname(__FILE__)) . '/Sources/tasks',
958
			'mbname' => strtr($_POST['mbname'], array('\"' => '"')),
959
			'language' => substr($_SESSION['installer_temp_lang'], 8, -4),
960
			'image_proxy_secret' => substr(sha1(mt_rand()), 0, 20),
961
			'image_proxy_enabled' => !empty($_POST['force_ssl']),
962
		);
963
964
		// Must save!
965 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
966
		{
967
			$incontext['error'] = $txt['error_windows_chmod'];
968
			return false;
969
		}
970
971
		// Make sure it works.
972
		require(dirname(__FILE__) . '/Settings.php');
973
974
		// UTF-8 requires a setting to override the language charset.
975
		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'])))
976
		{
977
			if (!$databases[$db_type]['utf8_support']())
978
			{
979
				$incontext['error'] = sprintf($txt['error_utf8_support']);
980
				return false;
981
			}
982
983
			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...
984
			{
985
				$incontext['error'] = sprintf($txt['error_utf8_version'], $databases[$db_type]['utf8_version']);
986
				return false;
987
			}
988
			else
989
				// Set the character set here.
990
				updateSettingsFile(array('db_character_set' => 'utf8'));
991
		}
992
993
		// Good, skip on.
994
		return true;
995
	}
996
997
	return false;
998
}
999
1000
// Step one: Do the SQL thang.
1001
function DatabasePopulation()
1002
{
1003
	global $db_character_set, $txt, $db_connection, $smcFunc, $databases, $modSettings, $db_type, $db_prefix, $incontext, $db_name, $boardurl;
1004
1005
	$incontext['sub_template'] = 'populate_database';
1006
	$incontext['page_title'] = $txt['db_populate'];
1007
	$incontext['continue'] = 1;
1008
1009
	// Already done?
1010
	if (isset($_POST['pop_done']))
1011
		return true;
1012
1013
	// Reload settings.
1014
	require(dirname(__FILE__) . '/Settings.php');
1015
	load_database();
1016
1017
	// Before running any of the queries, let's make sure another version isn't already installed.
1018
	$result = $smcFunc['db_query']('', '
1019
		SELECT variable, value
1020
		FROM {db_prefix}settings',
1021
		array(
1022
			'db_error_skip' => true,
1023
		)
1024
	);
1025
	$newSettings = array();
1026
	$modSettings = array();
1027
	if ($result !== false)
1028
	{
1029 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($result))
1030
			$modSettings[$row['variable']] = $row['value'];
1031
		$smcFunc['db_free_result']($result);
1032
1033
		// Do they match?  If so, this is just a refresh so charge on!
1034
		if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] != $GLOBALS['current_smf_version'])
1035
		{
1036
			$incontext['error'] = $txt['error_versions_do_not_match'];
1037
			return false;
1038
		}
1039
	}
1040
	$modSettings['disableQueryCheck'] = true;
1041
1042
	// If doing UTF8, select it. PostgreSQL requires passing it as a string...
1043 View Code Duplication
	if (!empty($db_character_set) && $db_character_set == 'utf8' && !empty($databases[$db_type]['utf8_support']))
1044
		$smcFunc['db_query']('', '
1045
			SET NAMES {string:utf8}',
1046
			array(
1047
				'db_error_skip' => true,
1048
				'utf8' => 'utf8',
1049
			)
1050
		);
1051
1052
	// Windows likes to leave the trailing slash, which yields to C:\path\to\SMF\/attachments...
1053
	if (substr(__DIR__, -1) == '\\')
1054
		$attachdir = __DIR__ . 'attachments';
1055
	else
1056
		$attachdir = __DIR__ . '/attachments';
1057
1058
	$replaces = array(
1059
		'{$db_prefix}' => $db_prefix,
1060
		'{$attachdir}' => json_encode(array(1 => $smcFunc['db_escape_string']($attachdir))),
1061
		'{$boarddir}' => $smcFunc['db_escape_string'](dirname(__FILE__)),
1062
		'{$boardurl}' => $boardurl,
1063
		'{$enableCompressedOutput}' => isset($_POST['compress']) ? '1' : '0',
1064
		'{$databaseSession_enable}' => isset($_POST['dbsession']) ? '1' : '0',
1065
		'{$smf_version}' => $GLOBALS['current_smf_version'],
1066
		'{$current_time}' => time(),
1067
		'{$sched_task_offset}' => 82800 + mt_rand(0, 86399),
1068
		'{$registration_method}' => isset($_POST['reg_mode']) ? $_POST['reg_mode'] : 0,
1069
	);
1070
1071
	foreach ($txt as $key => $value)
1072
	{
1073
		if (substr($key, 0, 8) == 'default_')
1074
			$replaces['{$' . $key . '}'] = $smcFunc['db_escape_string']($value);
1075
	}
1076
	$replaces['{$default_reserved_names}'] = strtr($replaces['{$default_reserved_names}'], array('\\\\n' => '\\n'));
1077
1078
	// MySQL-specific stuff - storage engine and UTF8 handling
1079
	if (substr($db_type, 0, 5) == 'mysql')
1080
	{
1081
		// Just in case the query fails for some reason...
1082
		$engines = array();
1083
1084
		// Figure out storage engines - what do we have, etc.
1085
		$get_engines = $smcFunc['db_query']('', 'SHOW ENGINES', array());
1086
1087 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($get_engines))
1088
		{
1089
			if ($row['Support'] == 'YES' || $row['Support'] == 'DEFAULT')
1090
				$engines[] = $row['Engine'];
1091
		}
1092
1093
		// Done with this now
1094
		$smcFunc['db_free_result']($get_engines);
1095
1096
		// InnoDB is better, so use it if possible...
1097
		$has_innodb = in_array('InnoDB', $engines);
1098
		$replaces['{$engine}'] = $has_innodb ? 'InnoDB' : 'MyISAM';
1099
		$replaces['{$memory}'] = (!$has_innodb && in_array('MEMORY', $engines)) ? 'MEMORY' : $replaces['{$engine}'];
1100
1101
		// If the UTF-8 setting was enabled, add it to the table definitions.
1102
		if (!empty($databases[$db_type]['utf8_support']) && (!empty($databases[$db_type]['utf8_required']) || isset($_POST['utf8'])))
1103
		{
1104
			$replaces['{$engine}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1105
			$replaces['{$memory}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1106
		}
1107
1108
		// One last thing - if we don't have InnoDB, we can't do transactions...
1109
		if (!$has_innodb)
1110
		{
1111
			$replaces['START TRANSACTION;'] = '';
1112
			$replaces['COMMIT;'] = '';
1113
		}
1114
	}
1115
	else
1116
	{
1117
		$has_innodb = false;
1118
	}
1119
1120
	// Read in the SQL.  Turn this on and that off... internationalize... etc.
1121
	$type = ($db_type == 'mysqli' ? 'mysql' : $db_type);
1122
	$sql_lines = explode("\n", strtr(implode(' ', file(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql')), $replaces));
1123
1124
	// Execute the SQL.
1125
	$current_statement = '';
1126
	$exists = array();
1127
	$incontext['failures'] = array();
1128
	$incontext['sql_results'] = array(
1129
		'tables' => 0,
1130
		'inserts' => 0,
1131
		'table_dups' => 0,
1132
		'insert_dups' => 0,
1133
	);
1134
	foreach ($sql_lines as $count => $line)
1135
	{
1136
		// No comments allowed!
1137
		if (substr(trim($line), 0, 1) != '#')
1138
			$current_statement .= "\n" . rtrim($line);
1139
1140
		// Is this the end of the query string?
1141
		if (empty($current_statement) || (preg_match('~;[\s]*$~s', $line) == 0 && $count != count($sql_lines)))
1142
			continue;
1143
1144
		// Does this table already exist?  If so, don't insert more data into it!
1145
		if (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) != 0 && in_array($match[1], $exists))
1146
		{
1147
			preg_match_all('~\)[,;]~', $current_statement, $matches);
1148 View Code Duplication
			if (!empty($matches[0]))
1149
				$incontext['sql_results']['insert_dups'] += count($matches[0]);
1150
			else
1151
				$incontext['sql_results']['insert_dups']++;
1152
1153
			$current_statement = '';
1154
			continue;
1155
		}
1156
1157
		if ($smcFunc['db_query']('', $current_statement, array('security_override' => true, 'db_error_skip' => true), $db_connection) === false)
1158
		{
1159
			// Use the appropriate function based on the DB type
1160
			if ($db_type == 'mysql' || $db_type == 'mysqli')
1161
				$db_errorno = $db_type . '_errno';
1162
1163
			// Error 1050: Table already exists!
1164
			// @todo Needs to be made better!
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
1165
			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...
1166
			{
1167
				$exists[] = $match[1];
1168
				$incontext['sql_results']['table_dups']++;
1169
			}
1170
			// Don't error on duplicate indexes (or duplicate operators in PostgreSQL.)
1171
			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)))
1172
			{
1173
				// MySQLi requires a connection object. It's optional with MySQL and Postgres
1174
				$incontext['failures'][$count] = $smcFunc['db_error']($db_connection);
1175
			}
1176
		}
1177
		else
1178
		{
1179
			if (preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1180
				$incontext['sql_results']['tables']++;
1181
			elseif (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1182
			{
1183
				preg_match_all('~\)[,;]~', $current_statement, $matches);
1184 View Code Duplication
				if (!empty($matches[0]))
1185
					$incontext['sql_results']['inserts'] += count($matches[0]);
1186
				else
1187
					$incontext['sql_results']['inserts']++;
1188
			}
1189
		}
1190
1191
		$current_statement = '';
1192
1193
		// Wait, wait, I'm still working here!
1194
		set_time_limit(60);
1195
	}
1196
1197
	// Sort out the context for the SQL.
1198
	foreach ($incontext['sql_results'] as $key => $number)
1199
	{
1200
		if ($number == 0)
1201
			unset($incontext['sql_results'][$key]);
1202
		else
1203
			$incontext['sql_results'][$key] = sprintf($txt['db_populate_' . $key], $number);
1204
	}
1205
1206
	// Make sure UTF will be used globally.
1207
	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'])))
1208
		$newSettings[] = array('global_character_set', 'UTF-8');
1209
1210
	// Maybe we can auto-detect better cookie settings?
1211
	preg_match('~^http[s]?://([^\.]+?)([^/]*?)(/.*)?$~', $boardurl, $matches);
1212
	if (!empty($matches))
1213
	{
1214
		// Default = both off.
1215
		$localCookies = false;
1216
		$globalCookies = false;
1217
1218
		// Okay... let's see.  Using a subdomain other than www.? (not a perfect check.)
1219
		if ($matches[2] != '' && (strpos(substr($matches[2], 1), '.') === false || in_array($matches[1], array('forum', 'board', 'community', 'forums', 'support', 'chat', 'help', 'talk', 'boards', 'www'))))
1220
			$globalCookies = true;
1221
		// If there's a / in the middle of the path, or it starts with ~... we want local.
1222
		if (isset($matches[3]) && strlen($matches[3]) > 3 && (substr($matches[3], 0, 2) == '/~' || strpos(substr($matches[3], 1), '/') !== false))
1223
			$localCookies = true;
1224
1225
		if ($globalCookies)
1226
			$newSettings[] = array('globalCookies', '1');
1227
		if ($localCookies)
1228
			$newSettings[] = array('localCookies', '1');
1229
	}
1230
1231
	// Are we allowing stat collection?
1232
	if (!empty($_POST['stats']) && substr($boardurl, 0, 16) != 'http://localhost' && empty($modSettings['allow_sm_stats']) && empty($modSettings['enable_sm_stats']))
1233
	{
1234
		$upcontext['allow_sm_stats'] = true;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$upcontext was never initialized. Although not strictly required by PHP, it is generally a good practice to add $upcontext = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
1235
1236
		// Attempt to register the site etc.
1237
		$fp = @fsockopen('www.simplemachines.org', 80, $errno, $errstr);
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $fp. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
1238 View Code Duplication
		if ($fp)
1239
		{
1240
			$out = 'GET /smf/stats/register_stats.php?site=' . base64_encode($boardurl) . ' HTTP/1.1' . "\r\n";
1241
			$out .= 'Host: www.simplemachines.org' . "\r\n";
1242
			$out .= 'Connection: Close' . "\r\n\r\n";
1243
			fwrite($fp, $out);
1244
1245
			$return_data = '';
1246
			while (!feof($fp))
1247
				$return_data .= fgets($fp, 128);
1248
1249
			fclose($fp);
1250
1251
			// Get the unique site ID.
1252
			preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ID. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
1253
1254
			if (!empty($ID[1]))
1255
				$smcFunc['db_insert']('replace',
1256
					$db_prefix . 'settings',
1257
					array('variable' => 'string', 'value' => 'string'),
1258
					array(
1259
						array('sm_stats_key', $ID[1]),
1260
						array('enable_sm_stats', 1),
1261
					),
1262
					array('variable')
1263
				);
1264
		}
1265
	}
1266
	// Don't remove stat collection unless we unchecked the box for real, not from the loop.
1267 View Code Duplication
	elseif (empty($_POST['stats']) && empty($upcontext['allow_sm_stats']))
0 ignored issues
show
Bug introduced by
The variable $upcontext seems only to be defined at a later point. As such the call to empty() seems to always evaluate to true.

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

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

Loading history...
1268
		$smcFunc['db_query']('', '
1269
			DELETE FROM {db_prefix}settings
1270
			WHERE variable = {string:enable_sm_stats}',
1271
			array(
1272
				'enable_sm_stats' => 'enable_sm_stats',
1273
				'db_error_skip' => true,
1274
			)
1275
		);
1276
1277
	// Are we enabling SSL?
1278
	if (!empty($_POST['force_ssl']))
1279
		$newSettings[] = array('force_ssl', 2);
1280
1281
	// Setting a timezone is required.
1282
	if (!isset($modSettings['default_timezone']) && function_exists('date_default_timezone_set'))
1283
	{
1284
		// Get PHP's default timezone, if set
1285
		$ini_tz = ini_get('date.timezone');
1286
		if (!empty($ini_tz))
1287
			$timezone_id = $ini_tz;
1288
		else
1289
			$timezone_id = '';
1290
1291
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
1292 View Code Duplication
		if (!in_array($timezone_id, timezone_identifiers_list()))
1293
		{
1294
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
1295
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
1296
		}
1297
1298
		if (date_default_timezone_set($timezone_id))
1299
			$newSettings[] = array('default_timezone', $timezone_id);
1300
	}
1301
1302
	if (!empty($newSettings))
1303
	{
1304
		$smcFunc['db_insert']('replace',
1305
			'{db_prefix}settings',
1306
			array('variable' => 'string-255', 'value' => 'string-65534'),
1307
			$newSettings,
1308
			array('variable')
1309
		);
1310
	}
1311
1312
	// Let's optimize those new tables, but not on InnoDB, ok?
1313
	if (!$has_innodb)
1314
	{
1315
		db_extend();
1316
		$tables = $smcFunc['db_list_tables']($db_name, $db_prefix . '%');
1317
		foreach ($tables as $table)
1318
		{
1319
			$smcFunc['db_optimize_table']($table) != -1 or $db_messed = true;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
1320
1321
			if (!empty($db_messed))
1322
			{
1323
				$incontext['failures'][-1] = $smcFunc['db_error']();
1324
				break;
1325
			}
1326
		}
1327
	}
1328
1329
	// MySQL specific stuff
1330
	if (substr($db_type, 0, 5) != 'mysql')
1331
		return false;
1332
1333
	// Find database user privileges.
1334
	$privs = array();
1335
	$get_privs = $smcFunc['db_query']('', 'SHOW PRIVILEGES', array());
1336
	while ($row = $smcFunc['db_fetch_assoc']($get_privs))
1337
	{
1338
		if ($row['Privilege'] == 'Alter')
1339
			$privs[] = $row['Privilege'];
1340
	}
1341
	$smcFunc['db_free_result']($get_privs);
1342
1343
	// Check for the ALTER privilege.
1344
	if (!empty($databases[$db_type]['alter_support']) && !in_array('Alter', $privs))
1345
	{
1346
		$incontext['error'] = $txt['error_db_alter_priv'];
1347
		return false;
1348
	}
1349
1350
	if (!empty($exists))
1351
	{
1352
		$incontext['page_title'] = $txt['user_refresh_install'];
1353
		$incontext['was_refresh'] = true;
1354
	}
1355
1356
	return false;
1357
}
1358
1359
// Ask for the administrator login information.
1360
function AdminAccount()
1361
{
1362
	global $txt, $db_type, $smcFunc, $incontext, $db_prefix, $db_passwd, $sourcedir, $db_character_set, $boardurl, $cachedir;
1363
1364
	$incontext['sub_template'] = 'admin_account';
1365
	$incontext['page_title'] = $txt['user_settings'];
1366
	$incontext['continue'] = 1;
1367
1368
	// Skipping?
1369
	if (!empty($_POST['skip']))
1370
		return true;
1371
1372
	// Need this to check whether we need the database password.
1373
	require(dirname(__FILE__) . '/Settings.php');
1374
	load_database();
1375
1376
	require_once($sourcedir . '/Subs-Auth.php');
1377
1378
	require_once($sourcedir . '/Subs.php');
1379
1380
	// Reload settings & set some global funcs
1381
	require_once($sourcedir . '/Load.php');
1382
	reloadSettings();
1383
1384
	// We need this to properly hash the password for Admin
1385 View Code Duplication
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' : function($string) {
1386
			global $sourcedir;
1387
			if (function_exists('mb_strtolower'))
1388
				return mb_strtolower($string, 'UTF-8');
1389
			require_once($sourcedir . '/Subs-Charset.php');
1390
			return utf8_strtolower($string);
1391
		};
1392
1393
	if (!isset($_POST['username']))
1394
		$_POST['username'] = '';
1395
	if (!isset($_POST['email']))
1396
		$_POST['email'] = '';
1397
	if (!isset($_POST['server_email']))
1398
		$_POST['server_email'] = '';
1399
1400
	$incontext['username'] = htmlspecialchars(stripslashes($_POST['username']));
1401
	$incontext['email'] = htmlspecialchars(stripslashes($_POST['email']));
1402
	$incontext['server_email'] = htmlspecialchars(stripslashes($_POST['server_email']));
1403
1404
	$incontext['require_db_confirm'] = empty($db_type);
1405
1406
	// Only allow skipping if we think they already have an account setup.
1407
	$request = $smcFunc['db_query']('', '
1408
		SELECT id_member
1409
		FROM {db_prefix}members
1410
		WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
1411
		LIMIT 1',
1412
		array(
1413
			'db_error_skip' => true,
1414
			'admin_group' => 1,
1415
		)
1416
	);
1417
	if ($smcFunc['db_num_rows']($request) != 0)
1418
		$incontext['skip'] = 1;
1419
	$smcFunc['db_free_result']($request);
1420
1421
	// Trying to create an account?
1422
	if (isset($_POST['password1']) && !empty($_POST['contbutt']))
1423
	{
1424
		// Wrong password?
1425
		if ($incontext['require_db_confirm'] && $_POST['password3'] != $db_passwd)
1426
		{
1427
			$incontext['error'] = $txt['error_db_connect'];
1428
			return false;
1429
		}
1430
		// Not matching passwords?
1431
		if ($_POST['password1'] != $_POST['password2'])
1432
		{
1433
			$incontext['error'] = $txt['error_user_settings_again_match'];
1434
			return false;
1435
		}
1436
		// No password?
1437
		if (strlen($_POST['password1']) < 4)
1438
		{
1439
			$incontext['error'] = $txt['error_user_settings_no_password'];
1440
			return false;
1441
		}
1442
		if (!file_exists($sourcedir . '/Subs.php'))
1443
		{
1444
			$incontext['error'] = $txt['error_subs_missing'];
1445
			return false;
1446
		}
1447
1448
		// Update the webmaster's email?
1449
		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...
1450
			updateSettingsFile(array('webmaster_email' => $_POST['server_email']));
1451
1452
		// Work out whether we're going to have dodgy characters and remove them.
1453
		$invalid_characters = preg_match('~[<>&"\'=\\\]~', $_POST['username']) != 0;
1454
		$_POST['username'] = preg_replace('~[<>&"\'=\\\]~', '', $_POST['username']);
1455
1456
		$result = $smcFunc['db_query']('', '
1457
			SELECT id_member, password_salt
1458
			FROM {db_prefix}members
1459
			WHERE member_name = {string:username} OR email_address = {string:email}
1460
			LIMIT 1',
1461
			array(
1462
				'username' => stripslashes($_POST['username']),
1463
				'email' => stripslashes($_POST['email']),
1464
				'db_error_skip' => true,
1465
			)
1466
		);
1467
		if ($smcFunc['db_num_rows']($result) != 0)
1468
		{
1469
			list ($incontext['member_id'], $incontext['member_salt']) = $smcFunc['db_fetch_row']($result);
1470
			$smcFunc['db_free_result']($result);
1471
1472
			$incontext['account_existed'] = $txt['error_user_settings_taken'];
1473
		}
1474
		elseif ($_POST['username'] == '' || strlen($_POST['username']) > 25)
1475
		{
1476
			// Try the previous step again.
1477
			$incontext['error'] = $_POST['username'] == '' ? $txt['error_username_left_empty'] : $txt['error_username_too_long'];
1478
			return false;
1479
		}
1480
		elseif ($invalid_characters || $_POST['username'] == '_' || $_POST['username'] == '|' || strpos($_POST['username'], '[code') !== false || strpos($_POST['username'], '[/code') !== false)
1481
		{
1482
			// Try the previous step again.
1483
			$incontext['error'] = $txt['error_invalid_characters_username'];
1484
			return false;
1485
		}
1486 View Code Duplication
		elseif (empty($_POST['email']) || !filter_var(stripslashes($_POST['email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['email'])) > 255)
1487
		{
1488
			// One step back, this time fill out a proper admin email address.
1489
			$incontext['error'] = sprintf($txt['error_valid_admin_email_needed'], $_POST['username']);
1490
			return false;
1491
		}
1492 View Code Duplication
		elseif (empty($_POST['server_email']) || !filter_var(stripslashes($_POST['server_email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['server_email'])) > 255)
1493
		{
1494
			// One step back, this time fill out a proper admin email address.
1495
			$incontext['error'] = $txt['error_valid_server_email_needed'];
1496
			return false;
1497
		}
1498
		elseif ($_POST['username'] != '')
1499
		{
1500
			$incontext['member_salt'] = substr(md5(mt_rand()), 0, 4);
1501
1502
			// Format the username properly.
1503
			$_POST['username'] = preg_replace('~[\t\n\r\x0B\0\xA0]+~', ' ', $_POST['username']);
1504
			$ip = isset($_SERVER['REMOTE_ADDR']) ? substr($_SERVER['REMOTE_ADDR'], 0, 255) : '';
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ip. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
1505
1506
			$_POST['password1'] = hash_password(stripslashes($_POST['username']), stripslashes($_POST['password1']));
1507
1508
			$incontext['member_id'] = $smcFunc['db_insert']('',
1509
				$db_prefix . 'members',
1510
				array(
1511
					'member_name' => 'string-25', 'real_name' => 'string-25', 'passwd' => 'string', 'email_address' => 'string',
1512
					'id_group' => 'int', 'posts' => 'int', 'date_registered' => 'int',
1513
					'password_salt' => 'string', 'lngfile' => 'string', 'personal_text' => 'string', 'avatar' => 'string',
1514
					'member_ip' => 'inet', 'member_ip2' => 'inet', 'buddy_list' => 'string', 'pm_ignore_list' => 'string',
1515
					'website_title' => 'string', 'website_url' => 'string',
1516
					'signature' => 'string', 'usertitle' => 'string', 'secret_question' => 'string',
1517
					'additional_groups' => 'string', 'ignore_boards' => 'string',
1518
				),
1519
				array(
1520
					stripslashes($_POST['username']), stripslashes($_POST['username']), $_POST['password1'], stripslashes($_POST['email']),
1521
					1, 0, time(),
1522
					$incontext['member_salt'], '', '', '',
1523
					$ip, $ip, '', '',
1524
					'', '',
1525
					'', '', '',
1526
					'', '',
1527
				),
1528
				array('id_member'),
1529
				1
1530
			);
1531
		}
1532
1533
		// If we're here we're good.
1534
		return true;
1535
	}
1536
1537
	return false;
1538
}
1539
1540
// Final step, clean up and a complete message!
1541
function DeleteInstall()
1542
{
1543
	global $smcFunc, $db_character_set, $context, $txt, $incontext;
1544
	global $current_smf_version, $databases, $sourcedir, $forum_version, $modSettings, $user_info, $db_type, $boardurl, $cachedir;
1545
1546
	$incontext['page_title'] = $txt['congratulations'];
1547
	$incontext['sub_template'] = 'delete_install';
1548
	$incontext['continue'] = 0;
1549
1550
	require(dirname(__FILE__) . '/Settings.php');
1551
	load_database();
1552
1553
	chdir(dirname(__FILE__));
1554
1555
	require_once($sourcedir . '/Errors.php');
1556
	require_once($sourcedir . '/Logging.php');
1557
	require_once($sourcedir . '/Subs.php');
1558
	require_once($sourcedir . '/Load.php');
1559
	require_once($sourcedir . '/Security.php');
1560
	require_once($sourcedir . '/Subs-Auth.php');
1561
1562
	// Reload settings & set some global funcs
1563
	reloadSettings();
1564
1565
	// Bring a warning over.
1566
	if (!empty($incontext['account_existed']))
1567
		$incontext['warning'] = $incontext['account_existed'];
1568
1569 View Code Duplication
	if (!empty($db_character_set) && !empty($databases[$db_type]['utf8_support']))
1570
		$smcFunc['db_query']('', '
1571
			SET NAMES {string:db_character_set}',
1572
			array(
1573
				'db_character_set' => $db_character_set,
1574
				'db_error_skip' => true,
1575
			)
1576
		);
1577
1578
	// As track stats is by default enabled let's add some activity.
1579
	$smcFunc['db_insert']('ignore',
1580
		'{db_prefix}log_activity',
1581
		array('date' => 'date', 'topics' => 'int', 'posts' => 'int', 'registers' => 'int'),
1582
		array(strftime('%Y-%m-%d', time()), 1, 1, (!empty($incontext['member_id']) ? 1 : 0)),
1583
		array('date')
1584
	);
1585
1586
	// We're going to want our lovely $modSettings now.
1587
	$request = $smcFunc['db_query']('', '
1588
		SELECT variable, value
1589
		FROM {db_prefix}settings',
1590
		array(
1591
			'db_error_skip' => true,
1592
		)
1593
	);
1594
	// Only proceed if we can load the data.
1595
	if ($request)
1596
	{
1597 View Code Duplication
		while ($row = $smcFunc['db_fetch_row']($request))
1598
			$modSettings[$row[0]] = $row[1];
1599
		$smcFunc['db_free_result']($request);
1600
	}
1601
1602
	// Automatically log them in ;)
1603
	if (isset($incontext['member_id']) && isset($incontext['member_salt']))
1604
		setLoginCookie(3153600 * 60, $incontext['member_id'], hash_salt($_POST['password1'], $incontext['member_salt']));
1605
1606
	$result = $smcFunc['db_query']('', '
1607
		SELECT value
1608
		FROM {db_prefix}settings
1609
		WHERE variable = {string:db_sessions}',
1610
		array(
1611
			'db_sessions' => 'databaseSession_enable',
1612
			'db_error_skip' => true,
1613
		)
1614
	);
1615 View Code Duplication
	if ($smcFunc['db_num_rows']($result) != 0)
1616
		list ($db_sessions) = $smcFunc['db_fetch_row']($result);
1617
	$smcFunc['db_free_result']($result);
1618
1619
	if (empty($db_sessions))
1620
		$_SESSION['admin_time'] = time();
1621
	else
1622
	{
1623
		$_SERVER['HTTP_USER_AGENT'] = substr($_SERVER['HTTP_USER_AGENT'], 0, 211);
1624
1625
		$smcFunc['db_insert']('replace',
1626
			'{db_prefix}sessions',
1627
			array(
1628
				'session_id' => 'string', 'last_update' => 'int', 'data' => 'string',
1629
			),
1630
			array(
1631
				session_id(), time(), 'USER_AGENT|s:' . strlen($_SERVER['HTTP_USER_AGENT']) . ':"' . $_SERVER['HTTP_USER_AGENT'] . '";admin_time|i:' . time() . ';',
1632
			),
1633
			array('session_id')
1634
		);
1635
	}
1636
1637
	updateStats('member');
1638
	updateStats('message');
1639
	updateStats('topic');
1640
1641
	// This function is needed to do the updateStats('subject') call.
1642
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' :
1643 View Code Duplication
		function($string){
1644
			global $sourcedir;
1645
			if (function_exists('mb_strtolower'))
1646
				return mb_strtolower($string, 'UTF-8');
1647
			require_once($sourcedir . '/Subs-Charset.php');
1648
			return utf8_strtolower($string);
1649
		};
1650
1651
	$request = $smcFunc['db_query']('', '
1652
		SELECT id_msg
1653
		FROM {db_prefix}messages
1654
		WHERE id_msg = 1
1655
			AND modified_time = 0
1656
		LIMIT 1',
1657
		array(
1658
			'db_error_skip' => true,
1659
		)
1660
	);
1661
	$context['utf8'] = $db_character_set === 'utf8' || $txt['lang_character_set'] === 'UTF-8';
1662
	if ($smcFunc['db_num_rows']($request) > 0)
1663
		updateStats('subject', 1, htmlspecialchars($txt['default_topic_subject']));
1664
	$smcFunc['db_free_result']($request);
1665
1666
	// Now is the perfect time to fetch the SM files.
1667
	require_once($sourcedir . '/ScheduledTasks.php');
1668
	// Sanity check that they loaded earlier!
1669
	if (isset($modSettings['recycle_board']))
1670
	{
1671
		$forum_version = $current_smf_version; // The variable is usually defined in index.php so lets just use our variable to do it for us.
1672
		scheduled_fetchSMfiles(); // Now go get those files!
1673
1674
		// We've just installed!
1675
		$user_info['ip'] = $_SERVER['REMOTE_ADDR'];
1676
		$user_info['id'] = isset($incontext['member_id']) ? $incontext['member_id'] : 0;
1677
		logAction('install', array('version' => $forum_version), 'admin');
1678
	}
1679
1680
	// Check if we need some stupid MySQL fix.
1681
	$server_version = $smcFunc['db_server_info']();
1682 View Code Duplication
	if (($db_type == 'mysql' || $db_type == 'mysqli') && in_array(substr($server_version, 0, 6), array('5.0.50', '5.0.51')))
1683
		updateSettings(array('db_mysql_group_by_fix' => '1'));
1684
1685
	// Some final context for the template.
1686
	$incontext['dir_still_writable'] = is_writable(dirname(__FILE__)) && substr(__FILE__, 1, 2) != ':\\';
1687
	$incontext['probably_delete_install'] = isset($_SESSION['installer_temp_ftp']) || is_writable(dirname(__FILE__)) || is_writable(__FILE__);
1688
1689
	// Update hash's cost to an appropriate setting
1690
	updateSettings(array(
1691
		'bcrypt_hash_cost' => hash_benchmark(),
1692
	));
1693
1694
	return false;
1695
}
1696
1697
function updateSettingsFile($vars)
1698
{
1699
	// Modify Settings.php.
1700
	$settingsArray = file(dirname(__FILE__) . '/Settings.php');
1701
1702
	// @todo Do we just want to read the file in clean, and split it this way always?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
1703
	if (count($settingsArray) == 1)
1704
		$settingsArray = preg_split('~[\r\n]~', $settingsArray[0]);
1705
1706
	for ($i = 0, $n = count($settingsArray); $i < $n; $i++)
1707
	{
1708
		// Remove the redirect...
1709
		if (trim($settingsArray[$i]) == 'if (file_exists(dirname(__FILE__) . \'/install.php\'))' && trim($settingsArray[$i + 1]) == '{' && trim($settingsArray[$i + 3]) == '}')
1710
		{
1711
			// Get the four lines to nothing.
1712
			$settingsArray[$i] = '';
1713
			$settingsArray[++$i] = '';
1714
			$settingsArray[++$i] = '';
1715
			$settingsArray[++$i] = '';
1716
			continue;
1717
		}
1718
1719
		if (trim($settingsArray[$i]) == '?' . '>')
1720
			$settingsArray[$i] = '';
1721
1722
		// Don't trim or bother with it if it's not a variable.
1723
		if (substr($settingsArray[$i], 0, 1) != '$')
1724
			continue;
1725
1726
		$settingsArray[$i] = rtrim($settingsArray[$i]) . "\n";
1727
1728
		foreach ($vars as $var => $val)
1729
			if (strncasecmp($settingsArray[$i], '$' . $var, 1 + strlen($var)) == 0)
1730
			{
1731
				$comment = strstr($settingsArray[$i], '#');
1732
				$settingsArray[$i] = '$' . $var . ' = \'' . $val . '\';' . ($comment != '' ? "\t\t" . $comment : "\n");
1733
				unset($vars[$var]);
1734
			}
1735
	}
1736
1737
	// Uh oh... the file wasn't empty... was it?
1738
	if (!empty($vars))
1739
	{
1740
		$settingsArray[$i++] = '';
1741
		foreach ($vars as $var => $val)
1742
			$settingsArray[$i++] = '$' . $var . ' = \'' . $val . '\';' . "\n";
1743
	}
1744
1745
	// Blank out the file - done to fix a oddity with some servers.
1746
	$fp = @fopen(dirname(__FILE__) . '/Settings.php', 'w');
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $fp. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

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