Completed
Pull Request — release-2.1 (#4857)
by
unknown
07:51
created

other/install.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Simple Machines Forum (SMF)
5
 *
6
 * @package SMF
7
 * @author Simple Machines http://www.simplemachines.org
8
 * @copyright 2018 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.22',
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.22',
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.4',
55
		'function_check' => 'pg_connect',
56
		'version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
57
		'supported' => function_exists('pg_connect'),
58
		'always_has_db' => true,
59
		'utf8_default' => true,
60
		'utf8_required' => true,
61
		'utf8_support' => function() {
62
			$request = pg_query('SHOW SERVER_ENCODING');
63
64
			list ($charcode) = pg_fetch_row($request);
65
66
			if ($charcode == 'UTF8')
67
				return true;
68
			else
69
				return false;
70
		},
71
		'utf8_version' => '8.0',
72
		'utf8_version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
73
		'validate_prefix' => function(&$value) {
74
			global $txt;
75
76
			$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
77
78
			// Is it reserved?
79
			if ($value == 'pg_')
80
				return $txt['error_db_prefix_reserved'];
81
82
			// Is the prefix numeric?
83
			if (preg_match('~^\d~', $value))
84
				return $txt['error_db_prefix_numeric'];
85
86
			return true;
87
		},
88
	),
89
);
90
91
global $txt;
92
93
// Initialize everything and load the language files.
94
initialize_inputs();
95
load_lang_file();
96
97
// This is what we are.
98
$installurl = $_SERVER['PHP_SELF'];
99
100
// All the steps in detail.
101
// Number,Name,Function,Progress Weight.
102
$incontext['steps'] = array(
103
	0 => array(1, $txt['install_step_welcome'], 'Welcome', 0),
104
	1 => array(2, $txt['install_step_writable'], 'CheckFilesWritable', 10),
105
	2 => array(3, $txt['install_step_databaseset'], 'DatabaseSettings', 15),
106
	3 => array(4, $txt['install_step_forum'], 'ForumSettings', 40),
107
	4 => array(5, $txt['install_step_databasechange'], 'DatabasePopulation', 15),
108
	5 => array(6, $txt['install_step_admin'], 'AdminAccount', 20),
109
	6 => array(7, $txt['install_step_delete'], 'DeleteInstall', 0),
110
);
111
112
// Default title...
113
$incontext['page_title'] = $txt['smf_installer'];
114
115
// What step are we on?
116
$incontext['current_step'] = isset($_GET['step']) ? (int) $_GET['step'] : 0;
117
118
// Loop through all the steps doing each one as required.
119
$incontext['overall_percent'] = 0;
120
121
foreach ($incontext['steps'] as $num => $step)
122
{
123
	if ($num >= $incontext['current_step'])
124
	{
125
		// The current weight of this step in terms of overall progress.
126
		$incontext['step_weight'] = $step[3];
127
		// Make sure we reset the skip button.
128
		$incontext['skip'] = false;
129
130
		// Call the step and if it returns false that means pause!
131
		if (function_exists($step[2]) && $step[2]() === false)
132
			break;
133
		elseif (function_exists($step[2]))
134
			$incontext['current_step']++;
135
136
		// No warnings pass on.
137
		$incontext['warning'] = '';
138
	}
139
	$incontext['overall_percent'] += $step[3];
140
}
141
142
// Actually do the template stuff.
143
installExit();
144
145
function initialize_inputs()
146
{
147
	global $databases;
148
149
	// Just so people using older versions of PHP aren't left in the cold.
150
	if (!isset($_SERVER['PHP_SELF']))
151
		$_SERVER['PHP_SELF'] = isset($GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']) ? $GLOBALS['HTTP_SERVER_VARS']['PHP_SELF'] : 'install.php';
152
153
	// Enable error reporting for fatal errors.
154
	error_reporting(E_ERROR | E_PARSE);
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');
169
		if (function_exists('session_start'))
170
			@session_start();
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');
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__);
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');
227
			}
228
		}
229
230
		// Now just redirect to a blank.png...
231
		$secure = false;
232
233 View Code Duplication
		if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on')
234
			$secure = true;
235
		elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on')
236
			$secure = true;
237
238
		header('location: http' . ($secure ? 's' : '') . '://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png');
239
		exit;
240
	}
241
242
	// PHP 5 might cry if we don't do this now.
243
	if (function_exists('date_default_timezone_set'))
244
	{
245
		// Get PHP's default timezone, if set
246
		$ini_tz = ini_get('date.timezone');
247
		if (!empty($ini_tz))
248
			$timezone_id = $ini_tz;
249
		else
250
			$timezone_id = '';
251
252
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
253 View Code Duplication
		if (!in_array($timezone_id, timezone_identifiers_list()))
254
		{
255
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
256
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
257
		}
258
259
		date_default_timezone_set($timezone_id);
260
	}
261
262
	// Force an integer step, defaulting to 0.
263
	$_GET['step'] = (int) @$_GET['step'];
264
}
265
266
// Load the list of language files, and the current language file.
267
function load_lang_file()
268
{
269
	global $txt, $incontext, $user_info;
270
271
	$incontext['detected_languages'] = array();
272
273
	// Make sure the languages directory actually exists.
274 View Code Duplication
	if (file_exists(dirname(__FILE__) . '/Themes/default/languages'))
275
	{
276
		// Find all the "Install" language files in the directory.
277
		$dir = dir(dirname(__FILE__) . '/Themes/default/languages');
278
		while ($entry = $dir->read())
279
		{
280
			if (substr($entry, 0, 8) == 'Install.' && substr($entry, -4) == '.php')
281
				$incontext['detected_languages'][$entry] = ucfirst(substr($entry, 8, strlen($entry) - 12));
282
		}
283
		$dir->close();
284
	}
285
286
	// Didn't find any, show an error message!
287 View Code Duplication
	if (empty($incontext['detected_languages']))
288
	{
289
		// Let's not cache this message, eh?
290
		header('expires: Mon, 26 Jul 1997 05:00:00 GMT');
291
		header('last-modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
292
		header('cache-control: no-cache');
293
294
		echo '<!DOCTYPE html>
295
<html>
296
	<head>
297
		<title>SMF Installer: Error!</title>
298
		<style>
299
			body {
300
				font-family: sans-serif;
301
				max-width: 700px; }
302
		
303
			h1 {
304
				font-size: 14pt; }
305
306
			.directory {
307
				margin: 0.3em;
308
				font-family: monospace;
309
				font-weight: bold; }
310
		</style>
311
	</head>
312
	<body>
313
		<h1>A critical error has occurred.</h1>
314
315
		<p>This installer was unable to find the installer\'s language file or files. They should be found under:</p>
316
317
		<div class="directory">', dirname($_SERVER['PHP_SELF']) != '/' ? dirname($_SERVER['PHP_SELF']) : '', '/Themes/default/languages</div>
0 ignored issues
show
Security Cross-Site Scripting introduced by
dirname($_SERVER['PHP_SE...ERVER['PHP_SELF']) : '' can contain request data and is used in output context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

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

Preventing Cross-Site-Scripting Attacks

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

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

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

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

General Strategies to prevent injection

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

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

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

$sanitized = (integer) $tainted;
Loading history...
318
319
		<p>In some cases, FTP clients do not properly upload files with this many folders. Please double check to make sure you <strong>have uploaded all the files in the distribution</strong>.</p>
320
		<p>If that doesn\'t help, please make sure this install.php file is in the same place as the Themes folder.</p>
321
		<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>
322
	</div></body>
323
</html>';
324
		die;
325
	}
326
327
	// Override the language file?
328 View Code Duplication
	if (isset($_GET['lang_file']))
329
		$_SESSION['installer_temp_lang'] = $_GET['lang_file'];
330
	elseif (isset($GLOBALS['HTTP_GET_VARS']['lang_file']))
331
		$_SESSION['installer_temp_lang'] = $GLOBALS['HTTP_GET_VARS']['lang_file'];
332
333
	// Make sure it exists, if it doesn't reset it.
334
	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']))
335
	{
336
		// Use the first one...
337
		list ($_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
338
339
		// If we have english and some other language, use the other language.  We Americans hate english :P.
340 View Code Duplication
		if ($_SESSION['installer_temp_lang'] == 'Install.english.php' && count($incontext['detected_languages']) > 1)
341
			list (, $_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
342
	}
343
344
	// And now include the actual language file itself.
345
	require_once(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']);
346
347
	// Which language did we load? Assume that he likes his language.
348
	preg_match('~^Install\.(.+[^-utf8])\.php$~', $_SESSION['installer_temp_lang'], $matches);
349
	$user_info['language'] = $matches[1];
350
}
351
352
// This handy function loads some settings and the like.
353
function load_database()
354
{
355
	global $db_prefix, $db_connection, $sourcedir, $smcFunc, $modSettings;
356
	global $db_server, $db_passwd, $db_type, $db_name, $db_user, $db_persist;
357
358
	if (empty($sourcedir))
359
		$sourcedir = dirname(__FILE__) . '/Sources';
360
361
	// Need this to check whether we need the database password.
362
	require(dirname(__FILE__) . '/Settings.php');
363
	if (!defined('SMF'))
364
		define('SMF', 1);
365
	if (empty($smcFunc))
366
		$smcFunc = array();
367
368
	$modSettings['disableQueryCheck'] = true;
369
370
	// Connect the database.
371
	if (!$db_connection)
372
	{
373
		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
374
		if (version_compare(PHP_VERSION, '5', '<'))
375
			require_once($sourcedir . '/Subs-Compat.php');
376
377
		$db_options = array('persist' => $db_persist);
378
		$port = '';
379
380
		// Figure out the port...
381
		if (!empty($_POST['db_port']))
382
		{
383
			if ($db_type == 'mysql')
384
			{
385
				$port = ((int) $_POST['db_port'] == ini_get($db_type . 'default_port')) ? '' : (int) $_POST['db_port'];
386
			}
387 View Code Duplication
			elseif ($db_type == 'postgresql')
388
			{
389
				// PostgreSQL doesn't have a default port setting in php.ini, so just check against the default
390
				$port = ((int) $_POST['db_port'] == 5432) ? '' : (int) $_POST['db_port'];
391
			}
392
		}
393
394
		if (!empty($port))
395
			$db_options['port'] = $port;
396
397
		if (!$db_connection)
398
			$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options);
399
	}
400
}
401
402
// This is called upon exiting the installer, for template etc.
403
function installExit($fallThrough = false)
404
{
405
	global $incontext, $installurl, $txt;
406
407
	// Send character set.
408
	header('content-type: text/html; charset=' . (isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8'));
409
410
	// We usually dump our templates out.
411
	if (!$fallThrough)
412
	{
413
		// The top install bit.
414
		template_install_above();
415
416
		// Call the template.
417
		if (isset($incontext['sub_template']))
418
		{
419
			$incontext['form_url'] = $installurl . '?step=' . $incontext['current_step'];
420
421
			call_user_func('template_' . $incontext['sub_template']);
422
		}
423
		// @todo REMOVE THIS!!
424
		else
425
		{
426
			if (function_exists('doStep' . $_GET['step']))
427
				call_user_func('doStep' . $_GET['step']);
428
		}
429
		// Show the footer.
430
		template_install_below();
431
	}
432
433
	// Bang - gone!
434
	die();
435
}
436
437
function Welcome()
438
{
439
	global $incontext, $txt, $databases, $installurl;
440
441
	$incontext['page_title'] = $txt['install_welcome'];
442
	$incontext['sub_template'] = 'welcome_message';
443
444
	// Done the submission?
445
	if (isset($_POST['contbutt']))
446
		return true;
447
448
	// See if we think they have already installed it?
449
	if (is_readable(dirname(__FILE__) . '/Settings.php'))
450
	{
451
		$probably_installed = 0;
452
		foreach (file(dirname(__FILE__) . '/Settings.php') as $line)
453
		{
454
			if (preg_match('~^\$db_passwd\s=\s\'([^\']+)\';$~', $line))
455
				$probably_installed++;
456
			if (preg_match('~^\$boardurl\s=\s\'([^\']+)\';~', $line) && !preg_match('~^\$boardurl\s=\s\'http://127\.0\.0\.1/smf\';~', $line))
457
				$probably_installed++;
458
		}
459
460
		if ($probably_installed == 2)
461
			$incontext['warning'] = $txt['error_already_installed'];
462
	}
463
464
	// Is some database support even compiled in?
465
	$incontext['supported_databases'] = array();
466
	foreach ($databases as $key => $db)
467
	{
468
		if ($db['supported'])
469
		{
470
			$type = ($key == 'mysqli') ? 'mysql' : $key;
471
			if (!file_exists(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql'))
472
			{
473
				$databases[$key]['supported'] = false;
474
				$notFoundSQLFile = true;
475
				$txt['error_db_script_missing'] = sprintf($txt['error_db_script_missing'], 'install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
476
			}
477
			else
478
				$incontext['supported_databases'][] = $db;
479
		}
480
	}
481
482
	// Check the PHP version.
483
	if ((!function_exists('version_compare') || version_compare($GLOBALS['required_php_version'], PHP_VERSION, '>=')))
484
		$error = 'error_php_too_low';
485
	// Make sure we have a supported database
486
	elseif (empty($incontext['supported_databases']))
487
		$error = empty($notFoundSQLFile) ? 'error_db_missing' : 'error_db_script_missing';
488
	// How about session support?  Some crazy sysadmin remove it?
489
	elseif (!function_exists('session_start'))
490
		$error = 'error_session_missing';
491
	// Make sure they uploaded all the files.
492
	elseif (!file_exists(dirname(__FILE__) . '/index.php'))
493
		$error = 'error_missing_files';
494
	// Very simple check on the session.save_path for Windows.
495
	// @todo Move this down later if they don't use database-driven sessions?
496
	elseif (@ini_get('session.save_path') == '/tmp' && substr(__FILE__, 1, 2) == ':\\')
497
		$error = 'error_session_save_path';
498
499
	// Since each of the three messages would look the same, anyway...
500
	if (isset($error))
501
		$incontext['error'] = $txt[$error];
502
503
	// Mod_security blocks everything that smells funny. Let SMF handle security.
504
	if (!fixModSecurity() && !isset($_GET['overmodsecurity']))
505
		$incontext['error'] = $txt['error_mod_security'] . '<br><br><a href="' . $installurl . '?overmodsecurity=true">' . $txt['error_message_click'] . '</a> ' . $txt['error_message_bad_try_again'];
506
507
	// Confirm mbstring is loaded...
508
	if (!extension_loaded('mbstring'))
509
		$incontext['error'] = $txt['install_no_mbstring'];
510
511
	// Check for https stream support.
512
	$supported_streams = stream_get_wrappers();
513
	if (!in_array('https', $supported_streams))
514
		$incontext['warning'] = $txt['install_no_https'];
515
516
	return false;
517
}
518
519
function CheckFilesWritable()
520
{
521
	global $txt, $incontext;
522
523
	$incontext['page_title'] = $txt['ftp_checking_writable'];
524
	$incontext['sub_template'] = 'chmod_files';
525
526
	$writable_files = array(
527
		'attachments',
528
		'avatars',
529
		'custom_avatar',
530
		'cache',
531
		'Packages',
532
		'Smileys',
533
		'Themes',
534
		'agreement.txt',
535
		'Settings.php',
536
		'Settings_bak.php',
537
	);
538
539
	foreach ($incontext['detected_languages'] as $lang => $temp)
540
		$extra_files[] = 'Themes/default/languages/' . $lang;
541
542
	// With mod_security installed, we could attempt to fix it with .htaccess.
543
	if (function_exists('apache_get_modules') && in_array('mod_security', apache_get_modules()))
544
		$writable_files[] = file_exists(dirname(__FILE__) . '/.htaccess') ? '.htaccess' : '.';
545
546
	$failed_files = array();
547
548
	// On linux, it's easy - just use is_writable!
549
	if (substr(__FILE__, 1, 2) != ':\\')
550
	{
551
		$incontext['systemos'] = 'linux';
552
553
		foreach ($writable_files as $file)
554
		{
555
			// Some files won't exist, try to address up front
556
			if (!file_exists(dirname(__FILE__) . '/' . $file))
557
				@touch(dirname(__FILE__) . '/' . $file);
558
			// NOW do the writable check...
559
			if (!is_writable(dirname(__FILE__) . '/' . $file))
560
			{
561
				@chmod(dirname(__FILE__) . '/' . $file, 0755);
562
563
				// Well, 755 hopefully worked... if not, try 777.
564
				if (!is_writable(dirname(__FILE__) . '/' . $file) && !@chmod(dirname(__FILE__) . '/' . $file, 0777))
565
					$failed_files[] = $file;
566
			}
567
		}
568 View Code Duplication
		foreach ($extra_files as $file)
569
			@chmod(dirname(__FILE__) . (empty($file) ? '' : '/' . $file), 0777);
570
	}
571
	// Windows is trickier.  Let's try opening for r+...
572
	else
573
	{
574
		$incontext['systemos'] = 'windows';
575
576
		foreach ($writable_files as $file)
577
		{
578
			// Folders can't be opened for write... but the index.php in them can ;)
579
			if (is_dir(dirname(__FILE__) . '/' . $file))
580
				$file .= '/index.php';
581
582
			// Funny enough, chmod actually does do something on windows - it removes the read only attribute.
583
			@chmod(dirname(__FILE__) . '/' . $file, 0777);
584
			$fp = @fopen(dirname(__FILE__) . '/' . $file, 'r+');
585
586
			// Hmm, okay, try just for write in that case...
587
			if (!is_resource($fp))
588
				$fp = @fopen(dirname(__FILE__) . '/' . $file, 'w');
589
590
			if (!is_resource($fp))
591
				$failed_files[] = $file;
592
593
			@fclose($fp);
594
		}
595 View Code Duplication
		foreach ($extra_files as $file)
596
			@chmod(dirname(__FILE__) . (empty($file) ? '' : '/' . $file), 0777);
597
	}
598
599
	$failure = count($failed_files) >= 1;
600
601
	if (!isset($_SERVER))
602
		return !$failure;
603
604
	// Put the list into context.
605
	$incontext['failed_files'] = $failed_files;
606
607
	// It's not going to be possible to use FTP on windows to solve the problem...
608
	if ($failure && substr(__FILE__, 1, 2) == ':\\')
609
	{
610
		$incontext['error'] = $txt['error_windows_chmod'] . '
611
					<ul class="error_content">
612
						<li>' . implode('</li>
613
						<li>', $failed_files) . '</li>
614
					</ul>';
615
616
		return false;
617
	}
618
	// We're going to have to use... FTP!
619
	elseif ($failure)
620
	{
621
		// Load any session data we might have...
622 View Code Duplication
		if (!isset($_POST['ftp_username']) && isset($_SESSION['installer_temp_ftp']))
623
		{
624
			$_POST['ftp_server'] = $_SESSION['installer_temp_ftp']['server'];
625
			$_POST['ftp_port'] = $_SESSION['installer_temp_ftp']['port'];
626
			$_POST['ftp_username'] = $_SESSION['installer_temp_ftp']['username'];
627
			$_POST['ftp_password'] = $_SESSION['installer_temp_ftp']['password'];
628
			$_POST['ftp_path'] = $_SESSION['installer_temp_ftp']['path'];
629
		}
630
631
		$incontext['ftp_errors'] = array();
632
		require_once('Sources/Class-Package.php');
633 View Code Duplication
		if (isset($_POST['ftp_username']))
634
		{
635
			$ftp = new ftp_connection($_POST['ftp_server'], $_POST['ftp_port'], $_POST['ftp_username'], $_POST['ftp_password']);
636
637
			if ($ftp->error === false)
638
			{
639
				// Try it without /home/abc just in case they messed up.
640
				if (!$ftp->chdir($_POST['ftp_path']))
641
				{
642
					$incontext['ftp_errors'][] = $ftp->last_message;
643
					$ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $_POST['ftp_path']));
644
				}
645
			}
646
		}
647
648
		if (!isset($ftp) || $ftp->error !== false)
649
		{
650
			if (!isset($ftp))
651
				$ftp = new ftp_connection(null);
652
			// Save the error so we can mess with listing...
653
			elseif ($ftp->error !== false && empty($incontext['ftp_errors']) && !empty($ftp->last_message))
654
				$incontext['ftp_errors'][] = $ftp->last_message;
655
656
			list ($username, $detect_path, $found_path) = $ftp->detect_path(dirname(__FILE__));
657
658
			if (empty($_POST['ftp_path']) && $found_path)
659
				$_POST['ftp_path'] = $detect_path;
660
661
			if (!isset($_POST['ftp_username']))
662
				$_POST['ftp_username'] = $username;
663
664
			// Set the username etc, into context.
665
			$incontext['ftp'] = array(
666
				'server' => isset($_POST['ftp_server']) ? $_POST['ftp_server'] : 'localhost',
667
				'port' => isset($_POST['ftp_port']) ? $_POST['ftp_port'] : '21',
668
				'username' => isset($_POST['ftp_username']) ? $_POST['ftp_username'] : '',
669
				'path' => isset($_POST['ftp_path']) ? $_POST['ftp_path'] : '/',
670
				'path_msg' => !empty($found_path) ? $txt['ftp_path_found_info'] : $txt['ftp_path_info'],
671
			);
672
673
			return false;
674
		}
675
		else
676
		{
677
			$_SESSION['installer_temp_ftp'] = array(
678
				'server' => $_POST['ftp_server'],
679
				'port' => $_POST['ftp_port'],
680
				'username' => $_POST['ftp_username'],
681
				'password' => $_POST['ftp_password'],
682
				'path' => $_POST['ftp_path']
683
			);
684
685
			$failed_files_updated = array();
686
687
			foreach ($failed_files as $file)
688
			{
689
				if (!is_writable(dirname(__FILE__) . '/' . $file))
690
					$ftp->chmod($file, 0755);
691
				if (!is_writable(dirname(__FILE__) . '/' . $file))
692
					$ftp->chmod($file, 0777);
693
				if (!is_writable(dirname(__FILE__) . '/' . $file))
694
				{
695
					$failed_files_updated[] = $file;
696
					$incontext['ftp_errors'][] = rtrim($ftp->last_message) . ' -> ' . $file . "\n";
697
				}
698
			}
699
700
			$ftp->close();
701
702
			// Are there any errors left?
703
			if (count($failed_files_updated) >= 1)
704
			{
705
				// Guess there are...
706
				$incontext['failed_files'] = $failed_files_updated;
707
708
				// Set the username etc, into context.
709
				$incontext['ftp'] = $_SESSION['installer_temp_ftp'] += array(
710
					'path_msg' => $txt['ftp_path_info'],
711
				);
712
713
				return false;
714
			}
715
		}
716
	}
717
718
	return true;
719
}
720
721
function DatabaseSettings()
722
{
723
	global $txt, $databases, $incontext, $smcFunc, $sourcedir;
724
	global $db_server, $db_name, $db_user, $db_passwd;
725
726
	$incontext['sub_template'] = 'database_settings';
727
	$incontext['page_title'] = $txt['db_settings'];
728
	$incontext['continue'] = 1;
729
730
	// Set up the defaults.
731
	$incontext['db']['server'] = 'localhost';
732
	$incontext['db']['user'] = '';
733
	$incontext['db']['name'] = '';
734
	$incontext['db']['pass'] = '';
735
	$incontext['db']['type'] = '';
736
	$incontext['supported_databases'] = array();
737
738
	$foundOne = false;
739
	foreach ($databases as $key => $db)
740
	{
741
		// Override with the defaults for this DB if appropriate.
742
		if ($db['supported'])
743
		{
744
			$incontext['supported_databases'][$key] = $db;
745
746
			if (!$foundOne)
747
			{
748
				if (isset($db['default_host']))
749
					$incontext['db']['server'] = ini_get($db['default_host']) or $incontext['db']['server'] = 'localhost';
750
				if (isset($db['default_user']))
751
				{
752
					$incontext['db']['user'] = ini_get($db['default_user']);
753
					$incontext['db']['name'] = ini_get($db['default_user']);
754
				}
755
				if (isset($db['default_password']))
756
					$incontext['db']['pass'] = ini_get($db['default_password']);
757
758
				// For simplicity and less confusion, leave the port blank by default
759
				$incontext['db']['port'] = '';
760
761
				$incontext['db']['type'] = $key;
762
				$foundOne = true;
763
			}
764
		}
765
	}
766
767
	// Override for repost.
768
	if (isset($_POST['db_user']))
769
	{
770
		$incontext['db']['user'] = $_POST['db_user'];
771
		$incontext['db']['name'] = $_POST['db_name'];
772
		$incontext['db']['server'] = $_POST['db_server'];
773
		$incontext['db']['prefix'] = $_POST['db_prefix'];
774
775
		if (!empty($_POST['db_port']))
776
			$incontext['db']['port'] = $_POST['db_port'];
777
	}
778
	else
779
	{
780
		$incontext['db']['prefix'] = 'smf_';
781
	}
782
783
	// Are we submitting?
784
	if (isset($_POST['db_type']))
785
	{
786
		// What type are they trying?
787
		$db_type = preg_replace('~[^A-Za-z0-9]~', '', $_POST['db_type']);
788
		$db_prefix = $_POST['db_prefix'];
789
		// Validate the prefix.
790
		$valid_prefix = $databases[$db_type]['validate_prefix']($db_prefix);
791
792
		if ($valid_prefix !== true)
793
		{
794
			$incontext['error'] = $valid_prefix;
795
			return false;
796
		}
797
798
		// Take care of these variables...
799
		$vars = array(
800
			'db_type' => $db_type,
801
			'db_name' => $_POST['db_name'],
802
			'db_user' => $_POST['db_user'],
803
			'db_passwd' => isset($_POST['db_passwd']) ? $_POST['db_passwd'] : '',
804
			'db_server' => $_POST['db_server'],
805
			'db_prefix' => $db_prefix,
806
			// The cookiename is special; we want it to be the same if it ever needs to be reinstalled with the same info.
807
			'cookiename' => 'SMFCookie' . abs(crc32($_POST['db_name'] . preg_replace('~[^A-Za-z0-9_$]~', '', $_POST['db_prefix'])) % 1000),
808
		);
809
810
		// Only set the port if we're not using the default
811
		if (!empty($_POST['db_port']))
812
		{
813
			// For MySQL, we can get the "default port" from PHP. PostgreSQL has no such option though.
814
			if (($db_type == 'mysql' || $db_type == 'mysqli') && $_POST['db_port'] != ini_get($db_type . '.default_port'))
815
				$vars['db_port'] = (int) $_POST['db_port'];
816 View Code Duplication
			elseif ($db_type == 'postgresql' && $_POST['db_port'] != 5432)
817
				$vars['db_port'] = (int) $_POST['db_port'];
818
		}
819
820
		// God I hope it saved!
821 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
822
		{
823
			$incontext['error'] = $txt['error_windows_chmod'];
824
			return false;
825
		}
826
827
		// Make sure it works.
828
		require(dirname(__FILE__) . '/Settings.php');
829
830
		if (empty($sourcedir))
831
			$sourcedir = dirname(__FILE__) . '/Sources';
832
833
		// Better find the database file!
834
		if (!file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php'))
835
		{
836
			$incontext['error'] = sprintf($txt['error_db_file'], 'Subs-Db-' . $db_type . '.php');
837
			return false;
838
		}
839
840
		// Now include it for database functions!
841
		if (!defined('SMF'))
842
			define('SMF', 1);
843
844
		$modSettings['disableQueryCheck'] = true;
845
		if (empty($smcFunc))
846
			$smcFunc = array();
847
848
			require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
849
850
		// What - running PHP4? The shame!
851
		if (version_compare(PHP_VERSION, '5', '<'))
852
			require_once($sourcedir . '/Subs-Compat.php');
853
854
		// Attempt a connection.
855
		$needsDB = !empty($databases[$db_type]['always_has_db']);
856
		$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('non_fatal' => true, 'dont_select_db' => !$needsDB));
857
858
		// No dice?  Let's try adding the prefix they specified, just in case they misread the instructions ;)
859
		if ($db_connection == null)
860
		{
861
			$db_error = @$smcFunc['db_error']();
862
863
			$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));
864
			if ($db_connection != null)
865
			{
866
				$db_user = $_POST['db_prefix'] . $db_user;
867
				updateSettingsFile(array('db_user' => $db_user));
868
			}
869
		}
870
871
		// Still no connection?  Big fat error message :P.
872
		if (!$db_connection)
873
		{
874
			$incontext['error'] = $txt['error_db_connect'] . '<div class="error_content"><strong>' . $db_error . '</strong></div>';
0 ignored issues
show
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...
875
			return false;
876
		}
877
878
		// Do they meet the install requirements?
879
		// @todo Old client, new server?
880
		if (version_compare($databases[$db_type]['version'], preg_replace('~^\D*|\-.+?$~', '', eval($databases[$db_type]['version_check']))) > 0)
881
		{
882
			$incontext['error'] = $txt['error_db_too_low'];
883
			return false;
884
		}
885
886
		// Let's try that database on for size... assuming we haven't already lost the opportunity.
887
		if ($db_name != '' && !$needsDB)
888
		{
889
			$smcFunc['db_query']('', "
890
				CREATE DATABASE IF NOT EXISTS `$db_name`",
891
				array(
892
					'security_override' => true,
893
					'db_error_skip' => true,
894
				),
895
				$db_connection
896
			);
897
898
			// Okay, let's try the prefix if it didn't work...
899
			if (!$smcFunc['db_select_db']($db_name, $db_connection) && $db_name != '')
900
			{
901
				$smcFunc['db_query']('', "
902
					CREATE DATABASE IF NOT EXISTS `$_POST[db_prefix]$db_name`",
903
					array(
904
						'security_override' => true,
905
						'db_error_skip' => true,
906
					),
907
					$db_connection
908
				);
909
910
				if ($smcFunc['db_select_db']($_POST['db_prefix'] . $db_name, $db_connection))
911
				{
912
					$db_name = $_POST['db_prefix'] . $db_name;
913
					updateSettingsFile(array('db_name' => $db_name));
914
				}
915
			}
916
917
			// Okay, now let's try to connect...
918
			if (!$smcFunc['db_select_db']($db_name, $db_connection))
919
			{
920
				$incontext['error'] = sprintf($txt['error_db_database'], $db_name);
921
				return false;
922
			}
923
		}
924
925
		return true;
926
	}
927
928
	return false;
929
}
930
931
// Let's start with basic forum type settings.
932
function ForumSettings()
933
{
934
	global $txt, $incontext, $databases, $db_type, $db_connection;
935
936
	$incontext['sub_template'] = 'forum_settings';
937
	$incontext['page_title'] = $txt['install_settings'];
938
939
	// Let's see if we got the database type correct.
940
	if (isset($_POST['db_type'], $databases[$_POST['db_type']]))
941
		$db_type = $_POST['db_type'];
942
943
	// Else we'd better be able to get the connection.
944
	else
945
		load_database();
946
947
	$db_type = isset($_POST['db_type']) ? $_POST['db_type'] : $db_type;
948
949
	// What host and port are we on?
950
	$host = empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST'];
951
952
		$secure = false;
953
954 View Code Duplication
		if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on')
955
			$secure = true;
956
		elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on')
957
			$secure = true;
958
959
	// Now, to put what we've learned together... and add a path.
960
	$incontext['detected_url'] = 'http' . ($secure ? 's' : '') . '://' . $host . substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
961
962
	// Check if the database sessions will even work.
963
	$incontext['test_dbsession'] = (ini_get('session.auto_start') != 1);
964
	$incontext['utf8_default'] = $databases[$db_type]['utf8_default'];
965
	$incontext['utf8_required'] = $databases[$db_type]['utf8_required'];
966
967
	$incontext['continue'] = 1;
968
969
	// Setup the SSL checkbox...
970
	$incontext['ssl_chkbx_protected'] = false;
971
	$incontext['ssl_chkbx_checked'] = false;
972
973
	// If redirect in effect, force ssl ON
974
	require_once(dirname(__FILE__) . '/Sources/Subs.php');
975
	if (https_redirect_active($incontext['detected_url'])) {
976
		$incontext['ssl_chkbx_protected'] = true;
977
		$incontext['ssl_chkbx_checked'] = true;
978
		$_POST['force_ssl'] = true;
979
	}
980
	// If no cert, make sure ssl stays OFF
981
	if (!ssl_cert_found($incontext['detected_url'])) {
982
		$incontext['ssl_chkbx_protected'] = true;
983
		$incontext['ssl_chkbx_checked'] = false;
984
	}
985
986
	// Submitting?
987
	if (isset($_POST['boardurl']))
988
	{
989 View Code Duplication
		if (substr($_POST['boardurl'], -10) == '/index.php')
990
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -10);
991
		elseif (substr($_POST['boardurl'], -1) == '/')
992
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -1);
993 View Code Duplication
		if (substr($_POST['boardurl'], 0, 7) != 'http://' && substr($_POST['boardurl'], 0, 7) != 'file://' && substr($_POST['boardurl'], 0, 8) != 'https://')
994
			$_POST['boardurl'] = 'http://' . $_POST['boardurl'];
995
996
		//Make sure boardurl is aligned with ssl setting
997
		if (empty($_POST['force_ssl']))
998
			$_POST['boardurl'] = strtr($_POST['boardurl'], array('https://' => 'http://'));
999
		else
1000
			$_POST['boardurl'] = strtr($_POST['boardurl'], array('http://' => 'https://'));
1001
1002
		// Save these variables.
1003
		$vars = array(
1004
			'boardurl' => $_POST['boardurl'],
1005
			'boarddir' => addslashes(dirname(__FILE__)),
1006
			'sourcedir' => addslashes(dirname(__FILE__)) . '/Sources',
1007
			'cachedir' => addslashes(dirname(__FILE__)) . '/cache',
1008
			'packagesdir' => addslashes(dirname(__FILE__)) . '/Packages',
1009
			'tasksdir' => addslashes(dirname(__FILE__)) . '/Sources/tasks',
1010
			'mbname' => strtr($_POST['mbname'], array('\"' => '"')),
1011
			'language' => substr($_SESSION['installer_temp_lang'], 8, -4),
1012
			'image_proxy_secret' => substr(sha1(mt_rand()), 0, 20),
1013
			'image_proxy_enabled' => !empty($_POST['force_ssl']),
1014
		);
1015
1016
		// Must save!
1017 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
1018
		{
1019
			$incontext['error'] = $txt['error_windows_chmod'];
1020
			return false;
1021
		}
1022
1023
		// Make sure it works.
1024
		require(dirname(__FILE__) . '/Settings.php');
1025
1026
		// UTF-8 requires a setting to override the language charset.
1027
		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'])))
1028
		{
1029
			if (!$databases[$db_type]['utf8_support']())
1030
			{
1031
				$incontext['error'] = sprintf($txt['error_utf8_support']);
1032
				return false;
1033
			}
1034
1035
			if (!empty($databases[$db_type]['utf8_version_check']) && version_compare($databases[$db_type]['utf8_version'], preg_replace('~\-.+?$~', '', eval($databases[$db_type]['utf8_version_check'])), '>'))
1036
			{
1037
				$incontext['error'] = sprintf($txt['error_utf8_version'], $databases[$db_type]['utf8_version']);
1038
				return false;
1039
			}
1040
			else
1041
				// Set the character set here.
1042
				updateSettingsFile(array('db_character_set' => 'utf8'));
1043
		}
1044
1045
		// Good, skip on.
1046
		return true;
1047
	}
1048
1049
	return false;
1050
}
1051
1052
// Step one: Do the SQL thang.
1053
function DatabasePopulation()
1054
{
1055
	global $db_character_set, $txt, $db_connection, $smcFunc, $databases, $modSettings, $db_type, $db_prefix, $incontext, $db_name, $boardurl;
1056
1057
	$incontext['sub_template'] = 'populate_database';
1058
	$incontext['page_title'] = $txt['db_populate'];
1059
	$incontext['continue'] = 1;
1060
1061
	// Already done?
1062
	if (isset($_POST['pop_done']))
1063
		return true;
1064
1065
	// Reload settings.
1066
	require(dirname(__FILE__) . '/Settings.php');
1067
	load_database();
1068
1069
	// Before running any of the queries, let's make sure another version isn't already installed.
1070
	$result = $smcFunc['db_query']('', '
1071
		SELECT variable, value
1072
		FROM {db_prefix}settings',
1073
		array(
1074
			'db_error_skip' => true,
1075
		)
1076
	);
1077
	$newSettings = array();
1078
	$modSettings = array();
1079
	if ($result !== false)
1080
	{
1081 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($result))
1082
			$modSettings[$row['variable']] = $row['value'];
1083
		$smcFunc['db_free_result']($result);
1084
1085
		// Do they match?  If so, this is just a refresh so charge on!
1086
		if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] != $GLOBALS['current_smf_version'])
1087
		{
1088
			$incontext['error'] = $txt['error_versions_do_not_match'];
1089
			return false;
1090
		}
1091
	}
1092
	$modSettings['disableQueryCheck'] = true;
1093
1094
	// If doing UTF8, select it. PostgreSQL requires passing it as a string...
1095 View Code Duplication
	if (!empty($db_character_set) && $db_character_set == 'utf8' && !empty($databases[$db_type]['utf8_support']))
1096
		$smcFunc['db_query']('', '
1097
			SET NAMES {string:utf8}',
1098
			array(
1099
				'db_error_skip' => true,
1100
				'utf8' => 'utf8',
1101
			)
1102
		);
1103
1104
	// Windows likes to leave the trailing slash, which yields to C:\path\to\SMF\/attachments...
1105
	if (substr(__DIR__, -1) == '\\')
1106
		$attachdir = __DIR__ . 'attachments';
1107
	else
1108
		$attachdir = __DIR__ . '/attachments';
1109
1110
	$replaces = array(
1111
		'{$db_prefix}' => $db_prefix,
1112
		'{$attachdir}' => json_encode(array(1 => $smcFunc['db_escape_string']($attachdir))),
1113
		'{$boarddir}' => $smcFunc['db_escape_string'](dirname(__FILE__)),
1114
		'{$boardurl}' => $boardurl,
1115
		'{$enableCompressedOutput}' => isset($_POST['compress']) ? '1' : '0',
1116
		'{$databaseSession_enable}' => isset($_POST['dbsession']) ? '1' : '0',
1117
		'{$smf_version}' => $GLOBALS['current_smf_version'],
1118
		'{$current_time}' => time(),
1119
		'{$sched_task_offset}' => 82800 + mt_rand(0, 86399),
1120
		'{$registration_method}' => isset($_POST['reg_mode']) ? $_POST['reg_mode'] : 0,
1121
	);
1122
1123
	foreach ($txt as $key => $value)
1124
	{
1125
		if (substr($key, 0, 8) == 'default_')
1126
			$replaces['{$' . $key . '}'] = $smcFunc['db_escape_string']($value);
1127
	}
1128
	$replaces['{$default_reserved_names}'] = strtr($replaces['{$default_reserved_names}'], array('\\\\n' => '\\n'));
1129
1130
	// MySQL-specific stuff - storage engine and UTF8 handling
1131
	if (substr($db_type, 0, 5) == 'mysql')
1132
	{
1133
		// Just in case the query fails for some reason...
1134
		$engines = array();
1135
1136
		// Figure out storage engines - what do we have, etc.
1137
		$get_engines = $smcFunc['db_query']('', 'SHOW ENGINES', array());
1138
1139 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($get_engines))
1140
		{
1141
			if ($row['Support'] == 'YES' || $row['Support'] == 'DEFAULT')
1142
				$engines[] = $row['Engine'];
1143
		}
1144
1145
		// Done with this now
1146
		$smcFunc['db_free_result']($get_engines);
1147
1148
		// InnoDB is better, so use it if possible...
1149
		$has_innodb = in_array('InnoDB', $engines);
1150
		$replaces['{$engine}'] = $has_innodb ? 'InnoDB' : 'MyISAM';
1151
		$replaces['{$memory}'] = (!$has_innodb && in_array('MEMORY', $engines)) ? 'MEMORY' : $replaces['{$engine}'];
1152
1153
		// If the UTF-8 setting was enabled, add it to the table definitions.
1154
		if (!empty($databases[$db_type]['utf8_support']) && (!empty($databases[$db_type]['utf8_required']) || isset($_POST['utf8'])))
1155
		{
1156
			$replaces['{$engine}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1157
			$replaces['{$memory}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1158
		}
1159
1160
		// One last thing - if we don't have InnoDB, we can't do transactions...
1161
		if (!$has_innodb)
1162
		{
1163
			$replaces['START TRANSACTION;'] = '';
1164
			$replaces['COMMIT;'] = '';
1165
		}
1166
	}
1167
	else
1168
	{
1169
		$has_innodb = false;
1170
	}
1171
1172
	// Read in the SQL.  Turn this on and that off... internationalize... etc.
1173
	$type = ($db_type == 'mysqli' ? 'mysql' : $db_type);
1174
	$sql_lines = explode("\n", strtr(implode(' ', file(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql')), $replaces));
1175
1176
	// Execute the SQL.
1177
	$current_statement = '';
1178
	$exists = array();
1179
	$incontext['failures'] = array();
1180
	$incontext['sql_results'] = array(
1181
		'tables' => 0,
1182
		'inserts' => 0,
1183
		'table_dups' => 0,
1184
		'insert_dups' => 0,
1185
	);
1186
	foreach ($sql_lines as $count => $line)
1187
	{
1188
		// No comments allowed!
1189
		if (substr(trim($line), 0, 1) != '#')
1190
			$current_statement .= "\n" . rtrim($line);
1191
1192
		// Is this the end of the query string?
1193
		if (empty($current_statement) || (preg_match('~;[\s]*$~s', $line) == 0 && $count != count($sql_lines)))
1194
			continue;
1195
1196
		// Does this table already exist?  If so, don't insert more data into it!
1197
		if (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) != 0 && in_array($match[1], $exists))
1198
		{
1199
			preg_match_all('~\)[,;]~', $current_statement, $matches);
1200 View Code Duplication
			if (!empty($matches[0]))
1201
				$incontext['sql_results']['insert_dups'] += count($matches[0]);
1202
			else
1203
				$incontext['sql_results']['insert_dups']++;
1204
1205
			$current_statement = '';
1206
			continue;
1207
		}
1208
1209
		if ($smcFunc['db_query']('', $current_statement, array('security_override' => true, 'db_error_skip' => true), $db_connection) === false)
1210
		{
1211
			// Use the appropriate function based on the DB type
1212
			if ($db_type == 'mysql' || $db_type == 'mysqli')
1213
				$db_errorno = $db_type . '_errno';
1214
1215
			// Error 1050: Table already exists!
1216
			// @todo Needs to be made better!
1217
			if ((($db_type != 'mysql' && $db_type != 'mysqli') || $db_errorno($db_connection) == 1050) && preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1218
			{
1219
				$exists[] = $match[1];
1220
				$incontext['sql_results']['table_dups']++;
1221
			}
1222
			// Don't error on duplicate indexes (or duplicate operators in PostgreSQL.)
1223
			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)))
1224
			{
1225
				// MySQLi requires a connection object. It's optional with MySQL and Postgres
1226
				$incontext['failures'][$count] = $smcFunc['db_error']($db_connection);
1227
			}
1228
		}
1229
		else
1230
		{
1231
			if (preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1232
				$incontext['sql_results']['tables']++;
1233
			elseif (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1234
			{
1235
				preg_match_all('~\)[,;]~', $current_statement, $matches);
1236 View Code Duplication
				if (!empty($matches[0]))
1237
					$incontext['sql_results']['inserts'] += count($matches[0]);
1238
				else
1239
					$incontext['sql_results']['inserts']++;
1240
			}
1241
		}
1242
1243
		$current_statement = '';
1244
1245
		// Wait, wait, I'm still working here!
1246
		set_time_limit(60);
1247
	}
1248
1249
	// Sort out the context for the SQL.
1250
	foreach ($incontext['sql_results'] as $key => $number)
1251
	{
1252
		if ($number == 0)
1253
			unset($incontext['sql_results'][$key]);
1254
		else
1255
			$incontext['sql_results'][$key] = sprintf($txt['db_populate_' . $key], $number);
1256
	}
1257
1258
	// Make sure UTF will be used globally.
1259
	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'])))
1260
		$newSettings[] = array('global_character_set', 'UTF-8');
1261
1262
	// Auto-detect local & global cookie settings
1263
	$url_parts = parse_url($boardurl);
1264
	if ($url_parts !== false)
1265
	{
1266
		unset($globalCookies, $globalCookiesDomain, $localCookies);
1267
1268
		// Look for subdomain, if found, set globalCookie settings
1269
		// Don't bother looking if you have an ip address for host
1270
		if (!empty($url_parts['host']) && (filter_var($url_parts['host'], FILTER_VALIDATE_IP) === false))
1271
		{
1272
			// www isn't really a subdomain in this sense, so strip it out
1273
			$url_parts['host'] = str_ireplace('www.', '', $url_parts['host']);
1274
			$pos1 = strrpos($url_parts['host'], '.');
1275
			if ($pos1 !== false)
1276
			{
1277
				// 2nd period from the right indicates you have a subdomain
1278
				$pos2 = strrpos(substr($url_parts['host'], 0, $pos1 - 1), '.');
1279
				if ($pos2 !== false)
1280
				{
1281
					$globalCookies = '1';
1282
					$globalCookiesDomain = substr($url_parts['host'], $pos2 + 1);
1283
				}
1284
			}
1285
		}
1286
1287
		// Look for subfolder, if found, set localCookie
1288
		// Checking for len > 1 ensures you don't have just a slash...
1289
		if (!empty($url_parts['path']) && strlen($url_parts['path']) > 1)
1290
			$localCookies = '1';
1291
1292
		if (isset($globalCookies))
1293
			$newSettings[] = array('globalCookies', $globalCookies);
1294
		if (isset($globalCookiesDomain))
1295
			$newSettings[] = array('globalCookiesDomain', $globalCookiesDomain);
1296
		if (isset($localCookies))
1297
			$newSettings[] = array('localCookies', $localCookies);
1298
	}
1299
1300
	// Are we allowing stat collection?
1301
	if (!empty($_POST['stats']) && substr($boardurl, 0, 16) != 'http://localhost' && empty($modSettings['allow_sm_stats']) && empty($modSettings['enable_sm_stats']))
1302
	{
1303
		$upcontext['allow_sm_stats'] = true;
1304
1305
		// Attempt to register the site etc.
1306
		$fp = @fsockopen('www.simplemachines.org', 80, $errno, $errstr);
1307 View Code Duplication
		if ($fp)
1308
		{
1309
			$out = 'GET /smf/stats/register_stats.php?site=' . base64_encode($boardurl) . ' HTTP/1.1' . "\r\n";
1310
			$out .= 'Host: www.simplemachines.org' . "\r\n";
1311
			$out .= 'Connection: Close' . "\r\n\r\n";
1312
			fwrite($fp, $out);
1313
1314
			$return_data = '';
1315
			while (!feof($fp))
1316
				$return_data .= fgets($fp, 128);
1317
1318
			fclose($fp);
1319
1320
			// Get the unique site ID.
1321
			preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1322
1323
			if (!empty($ID[1]))
1324
				$smcFunc['db_insert']('replace',
1325
					$db_prefix . 'settings',
1326
					array('variable' => 'string', 'value' => 'string'),
1327
					array(
1328
						array('sm_stats_key', $ID[1]),
1329
						array('enable_sm_stats', 1),
1330
					),
1331
					array('variable')
1332
				);
1333
		}
1334
	}
1335
	// Don't remove stat collection unless we unchecked the box for real, not from the loop.
1336 View Code Duplication
	elseif (empty($_POST['stats']) && empty($upcontext['allow_sm_stats']))
1337
		$smcFunc['db_query']('', '
1338
			DELETE FROM {db_prefix}settings
1339
			WHERE variable = {string:enable_sm_stats}',
1340
			array(
1341
				'enable_sm_stats' => 'enable_sm_stats',
1342
				'db_error_skip' => true,
1343
			)
1344
		);
1345
1346
	// Are we enabling SSL?
1347
	if (!empty($_POST['force_ssl']))
1348
		$newSettings[] = array('force_ssl', 1);
1349
1350
	// Setting a timezone is required.
1351
	if (!isset($modSettings['default_timezone']) && function_exists('date_default_timezone_set'))
1352
	{
1353
		// Get PHP's default timezone, if set
1354
		$ini_tz = ini_get('date.timezone');
1355
		if (!empty($ini_tz))
1356
			$timezone_id = $ini_tz;
1357
		else
1358
			$timezone_id = '';
1359
1360
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
1361 View Code Duplication
		if (!in_array($timezone_id, timezone_identifiers_list()))
1362
		{
1363
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
1364
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
1365
		}
1366
1367
		if (date_default_timezone_set($timezone_id))
1368
			$newSettings[] = array('default_timezone', $timezone_id);
1369
	}
1370
1371
	if (!empty($newSettings))
1372
	{
1373
		$smcFunc['db_insert']('replace',
1374
			'{db_prefix}settings',
1375
			array('variable' => 'string-255', 'value' => 'string-65534'),
1376
			$newSettings,
1377
			array('variable')
1378
		);
1379
	}
1380
1381
	// Let's optimize those new tables, but not on InnoDB, ok?
1382
	if (!$has_innodb)
1383
	{
1384
		db_extend();
1385
		$tables = $smcFunc['db_list_tables']($db_name, $db_prefix . '%');
1386
		foreach ($tables as $table)
1387
		{
1388
			$smcFunc['db_optimize_table']($table) != -1 or $db_messed = true;
1389
1390
			if (!empty($db_messed))
1391
			{
1392
				$incontext['failures'][-1] = $smcFunc['db_error']();
1393
				break;
1394
			}
1395
		}
1396
	}
1397
1398
	// MySQL specific stuff
1399
	if (substr($db_type, 0, 5) != 'mysql')
1400
		return false;
1401
1402
	// Find database user privileges.
1403
	$privs = array();
1404
	$get_privs = $smcFunc['db_query']('', 'SHOW PRIVILEGES', array());
1405
	while ($row = $smcFunc['db_fetch_assoc']($get_privs))
1406
	{
1407
		if ($row['Privilege'] == 'Alter')
1408
			$privs[] = $row['Privilege'];
1409
	}
1410
	$smcFunc['db_free_result']($get_privs);
1411
1412
	// Check for the ALTER privilege.
1413
	if (!empty($databases[$db_type]['alter_support']) && !in_array('Alter', $privs))
1414
	{
1415
		$incontext['error'] = $txt['error_db_alter_priv'];
1416
		return false;
1417
	}
1418
1419
	if (!empty($exists))
1420
	{
1421
		$incontext['page_title'] = $txt['user_refresh_install'];
1422
		$incontext['was_refresh'] = true;
1423
	}
1424
1425
	return false;
1426
}
1427
1428
// Ask for the administrator login information.
1429
function AdminAccount()
1430
{
1431
	global $txt, $db_type, $smcFunc, $incontext, $db_prefix, $db_passwd, $sourcedir, $db_character_set, $boardurl, $cachedir;
1432
1433
	$incontext['sub_template'] = 'admin_account';
1434
	$incontext['page_title'] = $txt['user_settings'];
1435
	$incontext['continue'] = 1;
1436
1437
	// Skipping?
1438
	if (!empty($_POST['skip']))
1439
		return true;
1440
1441
	// Need this to check whether we need the database password.
1442
	require(dirname(__FILE__) . '/Settings.php');
1443
	load_database();
1444
1445
	require_once($sourcedir . '/Subs-Auth.php');
1446
1447
	require_once($sourcedir . '/Subs.php');
1448
1449
	// Reload settings & set some global funcs
1450
	require_once($sourcedir . '/Load.php');
1451
	reloadSettings();
1452
1453
	// We need this to properly hash the password for Admin
1454 View Code Duplication
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' : function($string) {
1455
			global $sourcedir;
1456
			if (function_exists('mb_strtolower'))
1457
				return mb_strtolower($string, 'UTF-8');
1458
			require_once($sourcedir . '/Subs-Charset.php');
1459
			return utf8_strtolower($string);
1460
		};
1461
1462
	if (!isset($_POST['username']))
1463
		$_POST['username'] = '';
1464
	if (!isset($_POST['email']))
1465
		$_POST['email'] = '';
1466
	if (!isset($_POST['server_email']))
1467
		$_POST['server_email'] = '';
1468
1469
	$incontext['username'] = htmlspecialchars(stripslashes($_POST['username']));
1470
	$incontext['email'] = htmlspecialchars(stripslashes($_POST['email']));
1471
	$incontext['server_email'] = htmlspecialchars(stripslashes($_POST['server_email']));
1472
1473
	$incontext['require_db_confirm'] = empty($db_type);
1474
1475
	// Only allow skipping if we think they already have an account setup.
1476
	$request = $smcFunc['db_query']('', '
1477
		SELECT id_member
1478
		FROM {db_prefix}members
1479
		WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
1480
		LIMIT 1',
1481
		array(
1482
			'db_error_skip' => true,
1483
			'admin_group' => 1,
1484
		)
1485
	);
1486
	if ($smcFunc['db_num_rows']($request) != 0)
1487
		$incontext['skip'] = 1;
1488
	$smcFunc['db_free_result']($request);
1489
1490
	// Trying to create an account?
1491
	if (isset($_POST['password1']) && !empty($_POST['contbutt']))
1492
	{
1493
		// Wrong password?
1494
		if ($incontext['require_db_confirm'] && $_POST['password3'] != $db_passwd)
1495
		{
1496
			$incontext['error'] = $txt['error_db_connect'];
1497
			return false;
1498
		}
1499
		// Not matching passwords?
1500
		if ($_POST['password1'] != $_POST['password2'])
1501
		{
1502
			$incontext['error'] = $txt['error_user_settings_again_match'];
1503
			return false;
1504
		}
1505
		// No password?
1506
		if (strlen($_POST['password1']) < 4)
1507
		{
1508
			$incontext['error'] = $txt['error_user_settings_no_password'];
1509
			return false;
1510
		}
1511
		if (!file_exists($sourcedir . '/Subs.php'))
1512
		{
1513
			$incontext['error'] = $txt['error_subs_missing'];
1514
			return false;
1515
		}
1516
1517
		// Update the webmaster's email?
1518
		if (!empty($_POST['server_email']) && (empty($webmaster_email) || $webmaster_email == '[email protected]'))
1519
			updateSettingsFile(array('webmaster_email' => $_POST['server_email']));
1520
1521
		// Work out whether we're going to have dodgy characters and remove them.
1522
		$invalid_characters = preg_match('~[<>&"\'=\\\]~', $_POST['username']) != 0;
1523
		$_POST['username'] = preg_replace('~[<>&"\'=\\\]~', '', $_POST['username']);
1524
1525
		$result = $smcFunc['db_query']('', '
1526
			SELECT id_member, password_salt
1527
			FROM {db_prefix}members
1528
			WHERE member_name = {string:username} OR email_address = {string:email}
1529
			LIMIT 1',
1530
			array(
1531
				'username' => stripslashes($_POST['username']),
1532
				'email' => stripslashes($_POST['email']),
1533
				'db_error_skip' => true,
1534
			)
1535
		);
1536
		if ($smcFunc['db_num_rows']($result) != 0)
1537
		{
1538
			list ($incontext['member_id'], $incontext['member_salt']) = $smcFunc['db_fetch_row']($result);
1539
			$smcFunc['db_free_result']($result);
1540
1541
			$incontext['account_existed'] = $txt['error_user_settings_taken'];
1542
		}
1543
		elseif ($_POST['username'] == '' || strlen($_POST['username']) > 25)
1544
		{
1545
			// Try the previous step again.
1546
			$incontext['error'] = $_POST['username'] == '' ? $txt['error_username_left_empty'] : $txt['error_username_too_long'];
1547
			return false;
1548
		}
1549
		elseif ($invalid_characters || $_POST['username'] == '_' || $_POST['username'] == '|' || strpos($_POST['username'], '[code') !== false || strpos($_POST['username'], '[/code') !== false)
1550
		{
1551
			// Try the previous step again.
1552
			$incontext['error'] = $txt['error_invalid_characters_username'];
1553
			return false;
1554
		}
1555 View Code Duplication
		elseif (empty($_POST['email']) || !filter_var(stripslashes($_POST['email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['email'])) > 255)
1556
		{
1557
			// One step back, this time fill out a proper admin email address.
1558
			$incontext['error'] = sprintf($txt['error_valid_admin_email_needed'], $_POST['username']);
1559
			return false;
1560
		}
1561 View Code Duplication
		elseif (empty($_POST['server_email']) || !filter_var(stripslashes($_POST['server_email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['server_email'])) > 255)
1562
		{
1563
			// One step back, this time fill out a proper admin email address.
1564
			$incontext['error'] = $txt['error_valid_server_email_needed'];
1565
			return false;
1566
		}
1567
		elseif ($_POST['username'] != '')
1568
		{
1569
			$incontext['member_salt'] = substr(md5(mt_rand()), 0, 4);
1570
1571
			// Format the username properly.
1572
			$_POST['username'] = preg_replace('~[\t\n\r\x0B\0\xA0]+~', ' ', $_POST['username']);
1573
			$ip = isset($_SERVER['REMOTE_ADDR']) ? substr($_SERVER['REMOTE_ADDR'], 0, 255) : '';
1574
1575
			$_POST['password1'] = hash_password(stripslashes($_POST['username']), stripslashes($_POST['password1']));
1576
1577
			$incontext['member_id'] = $smcFunc['db_insert']('',
1578
				$db_prefix . 'members',
1579
				array(
1580
					'member_name' => 'string-25', 'real_name' => 'string-25', 'passwd' => 'string', 'email_address' => 'string',
1581
					'id_group' => 'int', 'posts' => 'int', 'date_registered' => 'int',
1582
					'password_salt' => 'string', 'lngfile' => 'string', 'personal_text' => 'string', 'avatar' => 'string',
1583
					'member_ip' => 'inet', 'member_ip2' => 'inet', 'buddy_list' => 'string', 'pm_ignore_list' => 'string',
1584
					'website_title' => 'string', 'website_url' => 'string',
1585
					'signature' => 'string', 'usertitle' => 'string', 'secret_question' => 'string',
1586
					'additional_groups' => 'string', 'ignore_boards' => 'string',
1587
				),
1588
				array(
1589
					stripslashes($_POST['username']), stripslashes($_POST['username']), $_POST['password1'], stripslashes($_POST['email']),
1590
					1, 0, time(),
1591
					$incontext['member_salt'], '', '', '',
1592
					$ip, $ip, '', '',
1593
					'', '',
1594
					'', '', '',
1595
					'', '',
1596
				),
1597
				array('id_member'),
1598
				1
1599
			);
1600
		}
1601
1602
		// If we're here we're good.
1603
		return true;
1604
	}
1605
1606
	return false;
1607
}
1608
1609
// Final step, clean up and a complete message!
1610
function DeleteInstall()
1611
{
1612
	global $smcFunc, $db_character_set, $context, $txt, $incontext;
1613
	global $current_smf_version, $databases, $sourcedir, $forum_version, $modSettings, $user_info, $db_type, $boardurl, $cachedir, $cookiename;
1614
1615
	$incontext['page_title'] = $txt['congratulations'];
1616
	$incontext['sub_template'] = 'delete_install';
1617
	$incontext['continue'] = 0;
1618
1619
	require(dirname(__FILE__) . '/Settings.php');
1620
	load_database();
1621
1622
	chdir(dirname(__FILE__));
1623
1624
	require_once($sourcedir . '/Errors.php');
1625
	require_once($sourcedir . '/Logging.php');
1626
	require_once($sourcedir . '/Subs.php');
1627
	require_once($sourcedir . '/Load.php');
1628
	require_once($sourcedir . '/Security.php');
1629
	require_once($sourcedir . '/Subs-Auth.php');
1630
1631
	// Reload settings & set some global funcs
1632
	reloadSettings();
1633
1634
	// Bring a warning over.
1635
	if (!empty($incontext['account_existed']))
1636
		$incontext['warning'] = $incontext['account_existed'];
1637
1638 View Code Duplication
	if (!empty($db_character_set) && !empty($databases[$db_type]['utf8_support']))
1639
		$smcFunc['db_query']('', '
1640
			SET NAMES {string:db_character_set}',
1641
			array(
1642
				'db_character_set' => $db_character_set,
1643
				'db_error_skip' => true,
1644
			)
1645
		);
1646
1647
	// As track stats is by default enabled let's add some activity.
1648
	$smcFunc['db_insert']('ignore',
1649
		'{db_prefix}log_activity',
1650
		array('date' => 'date', 'topics' => 'int', 'posts' => 'int', 'registers' => 'int'),
1651
		array(strftime('%Y-%m-%d', time()), 1, 1, (!empty($incontext['member_id']) ? 1 : 0)),
1652
		array('date')
1653
	);
1654
1655
	// We're going to want our lovely $modSettings now.
1656
	$request = $smcFunc['db_query']('', '
1657
		SELECT variable, value
1658
		FROM {db_prefix}settings',
1659
		array(
1660
			'db_error_skip' => true,
1661
		)
1662
	);
1663
	// Only proceed if we can load the data.
1664
	if ($request)
1665
	{
1666 View Code Duplication
		while ($row = $smcFunc['db_fetch_row']($request))
1667
			$modSettings[$row[0]] = $row[1];
1668
		$smcFunc['db_free_result']($request);
1669
	}
1670
1671
	// Automatically log them in ;)
1672
	if (isset($incontext['member_id']) && isset($incontext['member_salt']))
1673
		setLoginCookie(3153600 * 60, $incontext['member_id'], hash_salt($_POST['password1'], $incontext['member_salt']));
1674
1675
	$result = $smcFunc['db_query']('', '
1676
		SELECT value
1677
		FROM {db_prefix}settings
1678
		WHERE variable = {string:db_sessions}',
1679
		array(
1680
			'db_sessions' => 'databaseSession_enable',
1681
			'db_error_skip' => true,
1682
		)
1683
	);
1684 View Code Duplication
	if ($smcFunc['db_num_rows']($result) != 0)
1685
		list ($db_sessions) = $smcFunc['db_fetch_row']($result);
1686
	$smcFunc['db_free_result']($result);
1687
1688
	if (empty($db_sessions))
1689
		$_SESSION['admin_time'] = time();
1690
	else
1691
	{
1692
		$_SERVER['HTTP_USER_AGENT'] = substr($_SERVER['HTTP_USER_AGENT'], 0, 211);
1693
1694
		$smcFunc['db_insert']('replace',
1695
			'{db_prefix}sessions',
1696
			array(
1697
				'session_id' => 'string', 'last_update' => 'int', 'data' => 'string',
1698
			),
1699
			array(
1700
				session_id(), time(), 'USER_AGENT|s:' . strlen($_SERVER['HTTP_USER_AGENT']) . ':"' . $_SERVER['HTTP_USER_AGENT'] . '";admin_time|i:' . time() . ';',
1701
			),
1702
			array('session_id')
1703
		);
1704
	}
1705
1706
	updateStats('member');
1707
	updateStats('message');
1708
	updateStats('topic');
1709
1710
	// This function is needed to do the updateStats('subject') call.
1711
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' :
1712 View Code Duplication
		function($string){
1713
			global $sourcedir;
1714
			if (function_exists('mb_strtolower'))
1715
				return mb_strtolower($string, 'UTF-8');
1716
			require_once($sourcedir . '/Subs-Charset.php');
1717
			return utf8_strtolower($string);
1718
		};
1719
1720
	$request = $smcFunc['db_query']('', '
1721
		SELECT id_msg
1722
		FROM {db_prefix}messages
1723
		WHERE id_msg = 1
1724
			AND modified_time = 0
1725
		LIMIT 1',
1726
		array(
1727
			'db_error_skip' => true,
1728
		)
1729
	);
1730
	$context['utf8'] = $db_character_set === 'utf8' || $txt['lang_character_set'] === 'UTF-8';
1731
	if ($smcFunc['db_num_rows']($request) > 0)
1732
		updateStats('subject', 1, htmlspecialchars($txt['default_topic_subject']));
1733
	$smcFunc['db_free_result']($request);
1734
1735
	// Now is the perfect time to fetch the SM files.
1736
	require_once($sourcedir . '/ScheduledTasks.php');
1737
	// Sanity check that they loaded earlier!
1738
	if (isset($modSettings['recycle_board']))
1739
	{
1740
		$forum_version = $current_smf_version; // The variable is usually defined in index.php so lets just use our variable to do it for us.
1741
		scheduled_fetchSMfiles(); // Now go get those files!
1742
1743
		// We've just installed!
1744
		$user_info['ip'] = $_SERVER['REMOTE_ADDR'];
1745
		$user_info['id'] = isset($incontext['member_id']) ? $incontext['member_id'] : 0;
1746
		logAction('install', array('version' => $forum_version), 'admin');
1747
	}
1748
1749
	// Check if we need some stupid MySQL fix.
1750
	$server_version = $smcFunc['db_server_info']();
1751 View Code Duplication
	if (($db_type == 'mysql' || $db_type == 'mysqli') && in_array(substr($server_version, 0, 6), array('5.0.50', '5.0.51')))
1752
		updateSettings(array('db_mysql_group_by_fix' => '1'));
1753
1754
	// Some final context for the template.
1755
	$incontext['dir_still_writable'] = is_writable(dirname(__FILE__)) && substr(__FILE__, 1, 2) != ':\\';
1756
	$incontext['probably_delete_install'] = isset($_SESSION['installer_temp_ftp']) || is_writable(dirname(__FILE__)) || is_writable(__FILE__);
1757
1758
	// Update hash's cost to an appropriate setting
1759
	updateSettings(array(
1760
		'bcrypt_hash_cost' => hash_benchmark(),
1761
	));
1762
1763
	return false;
1764
}
1765
1766
function updateSettingsFile($vars)
1767
{
1768
	// Modify Settings.php.
1769
	$settingsArray = file(dirname(__FILE__) . '/Settings.php');
1770
1771
	// @todo Do we just want to read the file in clean, and split it this way always?
1772
	if (count($settingsArray) == 1)
1773
		$settingsArray = preg_split('~[\r\n]~', $settingsArray[0]);
1774
1775
	for ($i = 0, $n = count($settingsArray); $i < $n; $i++)
1776
	{
1777
		// Remove the redirect...
1778
		if (trim($settingsArray[$i]) == 'if (file_exists(dirname(__FILE__) . \'/install.php\'))' && trim($settingsArray[$i + 1]) == '{' && trim($settingsArray[$i + 9]) == '}')
1779
		{
1780
			// Set the ten lines to nothing.
1781
			for ($j=0; $j < 10; $j++)
1782
				$settingsArray[$i++] = '';
1783
1784
			continue;
1785
		}
1786
1787
		if (trim($settingsArray[$i]) == '?' . '>')
1788
			$settingsArray[$i] = '';
1789
1790
		// Don't trim or bother with it if it's not a variable.
1791
		if (substr($settingsArray[$i], 0, 1) != '$')
1792
			continue;
1793
1794
		$settingsArray[$i] = rtrim($settingsArray[$i]) . "\n";
1795
1796
		foreach ($vars as $var => $val)
1797
			if (strncasecmp($settingsArray[$i], '$' . $var, 1 + strlen($var)) == 0)
1798
			{
1799
				$comment = strstr($settingsArray[$i], '#');
1800
				$settingsArray[$i] = '$' . $var . ' = \'' . $val . '\';' . ($comment != '' ? "\t\t" . $comment : "\n");
1801
				unset($vars[$var]);
1802
			}
1803
	}
1804
1805
	// Uh oh... the file wasn't empty... was it?
1806
	if (!empty($vars))
1807
	{
1808
		$settingsArray[$i++] = '';
1809
		foreach ($vars as $var => $val)
1810
			$settingsArray[$i++] = '$' . $var . ' = \'' . $val . '\';' . "\n";
1811
	}
1812
1813
	// Blank out the file - done to fix a oddity with some servers.
1814
	$fp = @fopen(dirname(__FILE__) . '/Settings.php', 'w');
1815
	if (!$fp)
1816
		return false;
1817
	fclose($fp);
1818
1819
	$fp = fopen(dirname(__FILE__) . '/Settings.php', 'r+');
1820
1821
	// Gotta have one of these ;)
1822
	if (trim($settingsArray[0]) != '<?php')
1823
		fwrite($fp, "<?php\n");
1824
1825
	$lines = count($settingsArray);
1826
	for ($i = 0; $i < $lines - 1; $i++)
1827
	{
1828
		// Don't just write a bunch of blank lines.
1829
		if ($settingsArray[$i] != '' || @$settingsArray[$i - 1] != '')
1830
			fwrite($fp, strtr($settingsArray[$i], "\r", ''));
1831
	}
1832
	fwrite($fp, $settingsArray[$i] . '?' . '>');
1833
	fclose($fp);
1834
1835
	// Even though on normal installations the filemtime should prevent this being used by the installer incorrectly
1836
	// it seems that there are times it might not. So let's MAKE it dump the cache.
1837
	if (function_exists('opcache_invalidate'))
1838
		opcache_invalidate(dirname(__FILE__) . '/Settings.php', true);
1839
1840
	return true;
1841
}
1842
1843
function updateDbLastError()
1844
{
1845
	global $cachedir;
1846
1847
	// Write out the db_last_error file with the error timestamp
1848
	if (!empty($cachedir) && is_writable($cachedir))
1849
		file_put_contents($cachedir . '/db_last_error.php', '<' . '?' . "php\n" . '$db_last_error = 0;' . "\n" . '?' . '>');
1850
	else
1851
		file_put_contents(dirname(__FILE__) . '/cache/db_last_error.php', '<' . '?' . "php\n" . '$db_last_error = 0;' . "\n" . '?' . '>');
1852
1853
	return true;
1854
}
1855
1856
// Create an .htaccess file to prevent mod_security. SMF has filtering built-in.
1857
function fixModSecurity()
1858
{
1859
	$htaccess_addition = '
1860
<IfModule mod_security.c>
1861
	# Turn off mod_security filtering.  SMF is a big boy, it doesn\'t need its hands held.
1862
	SecFilterEngine Off
1863
1864
	# The below probably isn\'t needed, but better safe than sorry.
1865
	SecFilterScanPOST Off
1866
</IfModule>';
1867
1868
	if (!function_exists('apache_get_modules') || !in_array('mod_security', apache_get_modules()))
1869
		return true;
1870
	elseif (file_exists(dirname(__FILE__) . '/.htaccess') && is_writable(dirname(__FILE__) . '/.htaccess'))
1871
	{
1872
		$current_htaccess = implode('', file(dirname(__FILE__) . '/.htaccess'));
1873
1874
		// Only change something if mod_security hasn't been addressed yet.
1875
		if (strpos($current_htaccess, '<IfModule mod_security.c>') === false)
1876
		{
1877 View Code Duplication
			if ($ht_handle = fopen(dirname(__FILE__) . '/.htaccess', 'a'))
1878
			{
1879
				fwrite($ht_handle, $htaccess_addition);
1880
				fclose($ht_handle);
1881
				return true;
1882
			}
1883
			else
1884
				return false;
1885
		}
1886
		else
1887
			return true;
1888
	}
1889
	elseif (file_exists(dirname(__FILE__) . '/.htaccess'))
1890
		return strpos(implode('', file(dirname(__FILE__) . '/.htaccess')), '<IfModule mod_security.c>') !== false;
1891
	elseif (is_writable(dirname(__FILE__)))
1892
	{
1893 View Code Duplication
		if ($ht_handle = fopen(dirname(__FILE__) . '/.htaccess', 'w'))
1894
		{
1895
			fwrite($ht_handle, $htaccess_addition);
1896
			fclose($ht_handle);
1897
			return true;
1898
		}
1899
		else
1900
			return false;
1901
	}
1902
	else
1903
		return false;
1904
}
1905
1906
function template_install_above()
1907
{
1908
	global $incontext, $txt, $installurl;
1909
1910
	echo '<!DOCTYPE html>
1911
<html', $txt['lang_rtl'] == true ? ' dir="rtl"' : '', '>
1912
<head>
1913
	<meta charset="', isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8', '">
1914
	<meta name="robots" content="noindex">
1915
	<title>', $txt['smf_installer'], '</title>
1916
	<link rel="stylesheet" href="Themes/default/css/index.css?alp21">
1917
	<link rel="stylesheet" href="Themes/default/css/install.css?alp21">
1918
	', $txt['lang_rtl'] == true ? '<link rel="stylesheet" href="Themes/default/css/rtl.css?alp21">' : '', '
1919
1920
	<script src="Themes/default/scripts/jquery-3.2.1.min.js"></script>
1921
	<script src="Themes/default/scripts/script.js"></script>
1922
</head>
1923
<body>
1924
	<div id="footerfix">
1925
	<div id="header">
1926
		<h1 class="forumtitle">', $txt['smf_installer'], '</h1>
1927
		<img id="smflogo" src="Themes/default/images/smflogo.svg" alt="Simple Machines Forum" title="Simple Machines Forum">
1928
	</div>
1929
	<div id="wrapper">
1930
		<div id="upper_section">
1931
			<div id="inner_section">
1932
				<div id="inner_wrap">';
1933
1934
	// Have we got a language drop down - if so do it on the first step only.
1935
	if (!empty($incontext['detected_languages']) && count($incontext['detected_languages']) > 1 && $incontext['current_step'] == 0)
1936
	{
1937
		echo '
1938
					<div class="news">
1939
						<form action="', $installurl, '" method="get">
1940
							<label for="installer_language">', $txt['installer_language'], ':</label>
1941
							<select id="installer_language" name="lang_file" onchange="location.href = \'', $installurl, '?lang_file=\' + this.options[this.selectedIndex].value;">';
1942
1943
		foreach ($incontext['detected_languages'] as $lang => $name)
1944
			echo '
1945
								<option', isset($_SESSION['installer_temp_lang']) && $_SESSION['installer_temp_lang'] == $lang ? ' selected' : '', ' value="', $lang, '">', $name, '</option>';
1946
1947
		echo '
1948
							</select>
1949
							<noscript><input type="submit" value="', $txt['installer_language_set'], '" class="button"></noscript>
1950
						</form>
1951
					</div><!-- .news -->
1952
					<hr class="clear">';
1953
	}
1954
1955
	echo '
1956
				</div><!-- #inner_wrap -->
1957
			</div><!-- #inner_section -->
1958
		</div><!-- #upper_section -->
1959
		<div id="content_section">
1960
			<div id="main_content_section">
1961
				<div id="main_steps">
1962
					<h2>', $txt['upgrade_progress'], '</h2>
1963
					<ul>';
1964
1965 View Code Duplication
	foreach ($incontext['steps'] as $num => $step)
1966
		echo '
1967
						<li class="', $num < $incontext['current_step'] ? 'stepdone' : ($num == $incontext['current_step'] ? 'stepcurrent' : 'stepwaiting'), '">', $txt['upgrade_step'], ' ', $step[0], ': ', $step[1], '</li>';
1968
1969
	echo '
1970
					</ul>
1971
				</div>
1972
				<div id="install_progress">
1973
					<div id="progress_bar" class="progress_bar progress_green">
1974
						<h3>'. $txt['upgrade_overall_progress'], '</h3>
1975
						<span id="overall_text">', $incontext['overall_percent'], '%</span>
1976
						<div id="overall_progress" class="bar" style="width: ', $incontext['overall_percent'], '%;"></div>
1977
					</div>
1978
				</div>
1979
				<div id="main_screen" class="clear">
1980
					<h2>', $incontext['page_title'], '</h2>
1981
					<div class="panel">';
1982
}
1983
1984
function template_install_below()
1985
{
1986
	global $incontext, $txt;
1987
1988
	if (!empty($incontext['continue']) || !empty($incontext['skip']))
1989
	{
1990
		echo '
1991
							<div class="floatright">';
1992
1993
		if (!empty($incontext['continue']))
1994
			echo '
1995
								<input type="submit" id="contbutt" name="contbutt" value="', $txt['upgrade_continue'], '" onclick="return submitThisOnce(this);" class="button">';
1996
		if (!empty($incontext['skip']))
1997
			echo '
1998
								<input type="submit" id="skip" name="skip" value="', $txt['upgrade_skip'], '" onclick="return submitThisOnce(this);" class="button">';
1999
		echo '
2000
							</div>';
2001
	}
2002
2003
	// Show the closing form tag and other data only if not in the last step
2004
	if (count($incontext['steps']) - 1 !== (int) $incontext['current_step'])
2005
		echo '
2006
						</form>';
2007
2008
	echo '
2009
					</div><!-- .panel -->
2010
				</div><!-- #main_screen -->
2011
			</div><!-- #main_content_section -->
2012
		</div><!-- #content_section -->
2013
	</div><!-- #wrapper -->
2014
	</div><!-- #footerfix -->
2015
	<div id="footer">
2016
		<ul>
2017
			<li class="copyright"><a href="https://www.simplemachines.org/" title="Simple Machines Forum" target="_blank" rel="noopener">SMF &copy; 2018, Simple Machines</a></li>
2018
		</ul>
2019
	</div>
2020
</body>
2021
</html>';
2022
}
2023
2024
// Welcome them to the wonderful world of SMF!
2025
function template_welcome_message()
2026
{
2027
	global $incontext, $txt;
2028
2029
	echo '
2030
	<script src="https://www.simplemachines.org/smf/current-version.js?version=' . $GLOBALS['current_smf_version'] . '"></script>
2031
	<form action="', $incontext['form_url'], '" method="post">
2032
		<p>', sprintf($txt['install_welcome_desc'], $GLOBALS['current_smf_version']), '</p>
2033
		<div id="version_warning" class="noticebox" style="display: none;">
2034
			<h3>', $txt['error_warning_notice'], '</h3>
2035
			', 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>'), '
2036
		</div>';
2037
2038
	// Show the warnings, or not.
2039
	if (template_warning_divs())
2040
		echo '
2041
		<h3>', $txt['install_all_lovely'], '</h3>';
2042
2043
	// Say we want the continue button!
2044
	if (empty($incontext['error']))
2045
		$incontext['continue'] = 1;
2046
2047
	// For the latest version stuff.
2048
	echo '
2049
		<script>
2050
			// Latest version?
2051
			function smfCurrentVersion()
2052
			{
2053
				var smfVer, yourVer;
2054
2055
				if (!(\'smfVersion\' in window))
2056
					return;
2057
2058
				window.smfVersion = window.smfVersion.replace(/SMF\s?/g, \'\');
2059
2060
				smfVer = document.getElementById("smfVersion");
2061
				yourVer = document.getElementById("yourVersion");
2062
2063
				setInnerHTML(smfVer, window.smfVersion);
2064
2065
				var currentVersion = getInnerHTML(yourVer);
2066
				if (currentVersion < window.smfVersion)
2067
					document.getElementById(\'version_warning\').style.display = \'\';
2068
			}
2069
			addLoadEvent(smfCurrentVersion);
2070
		</script>';
2071
}
2072
2073
// A shortcut for any warning stuff.
2074
function template_warning_divs()
2075
{
2076
	global $txt, $incontext;
2077
2078
	// Errors are very serious..
2079
	if (!empty($incontext['error']))
2080
		echo '
2081
		<div class="errorbox">
2082
			<h3>', $txt['upgrade_critical_error'], '</h3>
2083
			', $incontext['error'], '
2084
		</div>';
2085
	// A warning message?
2086
	elseif (!empty($incontext['warning']))
2087
		echo '
2088
		<div class="errorbox">
2089
			<h3>', $txt['upgrade_warning'], '</h3>
2090
			', $incontext['warning'], '
2091
		</div>';
2092
2093
	return empty($incontext['error']) && empty($incontext['warning']);
2094
}
2095
2096
function template_chmod_files()
2097
{
2098
	global $txt, $incontext;
2099
2100
	echo '
2101
		<p>', $txt['ftp_setup_why_info'], '</p>
2102
		<ul class="error_content">
2103
			<li>', implode('</li>
2104
			<li>', $incontext['failed_files']), '</li>
2105
		</ul>';
2106
2107
	if (isset($incontext['systemos'], $incontext['detected_path']) && $incontext['systemos'] == 'linux')
2108
		echo '
2109
		<hr>
2110
		<p>', $txt['chmod_linux_info'], '</p>
2111
		<tt># chmod a+w ', implode(' ' . $incontext['detected_path'] . '/', $incontext['failed_files']), '</tt>';
2112
2113
	// This is serious!
2114
	if (!template_warning_divs())
2115
		return;
2116
2117
	echo '
2118
		<hr>
2119
		<p>', $txt['ftp_setup_info'], '</p>';
2120
2121
	if (!empty($incontext['ftp_errors']))
2122
		echo '
2123
		<div class="error_message">
2124
			', $txt['error_ftp_no_connect'], '<br><br>
2125
			<code>', implode('<br>', $incontext['ftp_errors']), '</code>
2126
		</div>';
2127
2128
	echo '
2129
		<form action="', $incontext['form_url'], '" method="post">
2130
			<dl class="settings">
2131
				<dt>
2132
					<label for="ftp_server">', $txt['ftp_server'], ':</label>
2133
				</dt>
2134
				<dd>
2135
					<div class="floatright">
2136
						<label for="ftp_port" class="textbox"><strong>', $txt['ftp_port'], ':&nbsp;</strong></label>
2137
						<input type="text" size="3" name="ftp_port" id="ftp_port" value="', $incontext['ftp']['port'], '">
2138
					</div>
2139
					<input type="text" size="30" name="ftp_server" id="ftp_server" value="', $incontext['ftp']['server'], '">
2140
					<div class="smalltext block">', $txt['ftp_server_info'], '</div>
2141
				</dd>
2142
				<dt>
2143
					<label for="ftp_username">', $txt['ftp_username'], ':</label>
2144
				</dt>
2145
				<dd>
2146
					<input type="text" size="30" name="ftp_username" id="ftp_username" value="', $incontext['ftp']['username'], '">
2147
					<div class="smalltext block">', $txt['ftp_username_info'], '</div>
2148
				</dd>
2149
				<dt>
2150
					<label for="ftp_password">', $txt['ftp_password'], ':</label>
2151
				</dt>
2152
				<dd>
2153
					<input type="password" size="30" name="ftp_password" id="ftp_password">
2154
					<div class="smalltext block">', $txt['ftp_password_info'], '</div>
2155
				</dd>
2156
				<dt>
2157
					<label for="ftp_path">', $txt['ftp_path'], ':</label>
2158
				</dt>
2159
				<dd>
2160
					<input type="text" size="30" name="ftp_path" id="ftp_path" value="', $incontext['ftp']['path'], '">
2161
					<div class="smalltext block">', $incontext['ftp']['path_msg'], '</div>
2162
				</dd>
2163
			</dl>
2164
			<div class="righttext buttons">
2165
				<input type="submit" value="', $txt['ftp_connect'], '" onclick="return submitThisOnce(this);" class="button">
2166
			</div>
2167
		</form>
2168
		<a href="', $incontext['form_url'], '">', $txt['error_message_click'], '</a> ', $txt['ftp_setup_again'];
2169
}
2170
2171
// Get the database settings prepared.
2172
function template_database_settings()
2173
{
2174
	global $incontext, $txt;
2175
2176
	echo '
2177
	<form action="', $incontext['form_url'], '" method="post">
2178
		<p>', $txt['db_settings_info'], '</p>';
2179
2180
	template_warning_divs();
2181
2182
	echo '
2183
		<dl class="settings">';
2184
2185
	// More than one database type?
2186
	if (count($incontext['supported_databases']) > 1)
2187
	{
2188
		echo '
2189
			<dt>
2190
				<label for="db_type_input">', $txt['db_settings_type'], ':</label>
2191
			</dt>
2192
			<dd>
2193
				<select name="db_type" id="db_type_input" onchange="toggleDBInput();">';
2194
2195
	foreach ($incontext['supported_databases'] as $key => $db)
2196
			echo '
2197
					<option value="', $key, '"', isset($_POST['db_type']) && $_POST['db_type'] == $key ? ' selected' : '', '>', $db['name'], '</option>';
2198
2199
	echo '
2200
				</select>
2201
				<div class="smalltext">', $txt['db_settings_type_info'], '</div>
2202
			</dd>';
2203
	}
2204
	else
2205
	{
2206
		echo '
2207
			<dd>
2208
				<input type="hidden" name="db_type" value="', $incontext['db']['type'], '">
2209
			</dd>';
2210
	}
2211
2212
	echo '
2213
			<dt>
2214
				<label for="db_server_input">', $txt['db_settings_server'], ':</label>
2215
			</dt>
2216
			<dd>
2217
				<input type="text" name="db_server" id="db_server_input" value="', $incontext['db']['server'], '" size="30">
2218
				<div class="smalltext">', $txt['db_settings_server_info'], '</div>
2219
			</dd>
2220
			<dt>
2221
				<label for="db_port_input">', $txt['db_settings_port'], ':</label>
2222
			</dt>
2223
			<dd>
2224
				<input type="text" name="db_port" id="db_port_input" value="', $incontext['db']['port'], '">
2225
				<div class="smalltext">', $txt['db_settings_port_info'], '</div>
2226
			</dd>
2227
			<dt>
2228
				<label for="db_user_input">', $txt['db_settings_username'], ':</label>
2229
			</dt>
2230
			<dd>
2231
				<input type="text" name="db_user" id="db_user_input" value="', $incontext['db']['user'], '" size="30">
2232
				<div class="smalltext">', $txt['db_settings_username_info'], '</div>
2233
			</dd>
2234
			<dt>
2235
				<label for="db_passwd_input">', $txt['db_settings_password'], ':</label>
2236
			</dt>
2237
			<dd>
2238
				<input type="password" name="db_passwd" id="db_passwd_input" value="', $incontext['db']['pass'], '" size="30">
2239
				<div class="smalltext">', $txt['db_settings_password_info'], '</div>
2240
			</dd>
2241
			<dt>
2242
				<label for="db_name_input">', $txt['db_settings_database'], ':</label>
2243
			</dt>
2244
			<dd>
2245
				<input type="text" name="db_name" id="db_name_input" value="', empty($incontext['db']['name']) ? 'smf' : $incontext['db']['name'], '" size="30">
2246
				<div class="smalltext">
2247
					', $txt['db_settings_database_info'], '
2248
					<span id="db_name_info_warning">', $txt['db_settings_database_info_note'], '</span>
2249
				</div>
2250
			</dd>
2251
			<dt style="display: none;">
2252
				<label for="db_filename_input">', $txt['db_settings_database_file'], ':</label>
2253
			</dt>
2254
			<dd style="display: none;">
2255
				<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">
2256
				<div class="smalltext">', $txt['db_settings_database_file_info'], '</div>
2257
			</dd>
2258
			<dt>
2259
				<label for="db_prefix_input">', $txt['db_settings_prefix'], ':</label>
2260
			</dt>
2261
			<dd>
2262
				<input type="text" name="db_prefix" id="db_prefix_input" value="', $incontext['db']['prefix'], '" size="30">
2263
				<div class="smalltext">', $txt['db_settings_prefix_info'], '</div>
2264
			</dd>
2265
		</dl>';
2266
2267
	// Toggles a warning related to db names in PostgreSQL
2268
	echo '
2269
		<script>
2270
			function toggleDBInput()
2271
			{
2272
				if (document.getElementById(\'db_type_input\').value == \'postgresql\')
2273
					document.getElementById(\'db_name_info_warning\').style.display = \'none\';
2274
				else
2275
					document.getElementById(\'db_name_info_warning\').style.display = \'\';
2276
			}
2277
			toggleDBInput();
2278
		</script>';
2279
}
2280
2281
// Stick in their forum settings.
2282
function template_forum_settings()
2283
{
2284
	global $incontext, $txt;
2285
2286
	echo '
2287
	<form action="', $incontext['form_url'], '" method="post">
2288
		<h3>', $txt['install_settings_info'], '</h3>';
2289
2290
	template_warning_divs();
2291
2292
	echo '
2293
		<dl class="settings">
2294
			<dt>
2295
				<label for="mbname_input">', $txt['install_settings_name'], ':</label>
2296
			</dt>
2297
			<dd>
2298
				<input type="text" name="mbname" id="mbname_input" value="', $txt['install_settings_name_default'], '" size="65">
2299
				<div class="smalltext">', $txt['install_settings_name_info'], '</div>
2300
			</dd>
2301
			<dt>
2302
				<label for="boardurl_input">', $txt['install_settings_url'], ':</label>
2303
			</dt>
2304
			<dd>
2305
				<input type="text" name="boardurl" id="boardurl_input" value="', $incontext['detected_url'], '" size="65">
2306
				<div class="smalltext">', $txt['install_settings_url_info'], '</div>
2307
			</dd>
2308
			<dt>
2309
				<label for="reg_mode">', $txt['install_settings_reg_mode'], ':</label>
2310
			</dt>
2311
			<dd>
2312
				<select name="reg_mode" id="reg_mode">
2313
					<optgroup label="', $txt['install_settings_reg_modes'], ':">
2314
						<option value="0" selected>', $txt['install_settings_reg_immediate'], '</option>
2315
						<option value="1">', $txt['install_settings_reg_email'], '</option>
2316
						<option value="2">', $txt['install_settings_reg_admin'], '</option>
2317
						<option value="3">', $txt['install_settings_reg_disabled'], '</option>
2318
					</optgroup>
2319
				</select>
2320
				<div class="smalltext">', $txt['install_settings_reg_mode_info'], '</div>
2321
			</dd>
2322
			<dt>', $txt['install_settings_compress'], ':</dt>
2323
			<dd>
2324
				<input type="checkbox" name="compress" id="compress_check" checked>
2325
				<label for="compress_check">', $txt['install_settings_compress_title'], '</label>
2326
				<div class="smalltext">', $txt['install_settings_compress_info'], '</div>
2327
			</dd>
2328
			<dt>', $txt['install_settings_dbsession'], ':</dt>
2329
			<dd>
2330
				<input type="checkbox" name="dbsession" id="dbsession_check" checked>
2331
				<label for="dbsession_check">', $txt['install_settings_dbsession_title'], '</label>
2332
				<div class="smalltext">', $incontext['test_dbsession'] ? $txt['install_settings_dbsession_info1'] : $txt['install_settings_dbsession_info2'], '</div>
2333
			</dd>
2334
			<dt>', $txt['install_settings_utf8'], ':</dt>
2335
			<dd>
2336
				<input type="checkbox" name="utf8" id="utf8_check"', $incontext['utf8_default'] ? ' checked' : '', '', $incontext['utf8_required'] ? ' disabled' : '', '>
2337
				<label for="utf8_check">', $txt['install_settings_utf8_title'], '</label>
2338
				<div class="smalltext">', $txt['install_settings_utf8_info'], '</div>
2339
			</dd>
2340
			<dt>', $txt['install_settings_stats'], ':</dt>
2341
			<dd>
2342
				<input type="checkbox" name="stats" id="stats_check" checked="checked">
2343
				<label for="stats_check">', $txt['install_settings_stats_title'], '</label>
2344
				<div class="smalltext">', $txt['install_settings_stats_info'], '</div>
2345
			</dd>
2346
			<dt>', $txt['force_ssl'], ':</dt>
2347
			<dd>
2348
				<input type="checkbox" name="force_ssl" id="force_ssl"', $incontext['ssl_chkbx_checked'] ? ' checked' : '',
2349
					$incontext['ssl_chkbx_protected'] ? ' disabled' : '', '>
2350
				<label for="force_ssl">', $txt['force_ssl_label'], '</label>
2351
				<div class="smalltext"><strong>', $txt['force_ssl_info'], '</strong></div>
2352
			</dd>
2353
		</dl>';
2354
}
2355
2356
// Show results of the database population.
2357
function template_populate_database()
2358
{
2359
	global $incontext, $txt;
2360
2361
	echo '
2362
	<form action="', $incontext['form_url'], '" method="post">
2363
		<p>', !empty($incontext['was_refresh']) ? $txt['user_refresh_install_desc'] : $txt['db_populate_info'], '</p>';
2364
2365
	if (!empty($incontext['sql_results']))
2366
	{
2367
		echo '
2368
		<ul>
2369
			<li>', implode('</li><li>', $incontext['sql_results']), '</li>
2370
		</ul>';
2371
	}
2372
2373
	if (!empty($incontext['failures']))
2374
	{
2375
		echo '
2376
		<div class="red">', $txt['error_db_queries'], '</div>
2377
		<ul>';
2378
2379
		foreach ($incontext['failures'] as $line => $fail)
2380
			echo '
2381
			<li><strong>', $txt['error_db_queries_line'], $line + 1, ':</strong> ', nl2br(htmlspecialchars($fail)), '</li>';
2382
2383
		echo '
2384
		</ul>';
2385
	}
2386
2387
	echo '
2388
		<p>', $txt['db_populate_info2'], '</p>';
2389
2390
	template_warning_divs();
2391
2392
	echo '
2393
		<input type="hidden" name="pop_done" value="1">';
2394
}
2395
2396
// Create the admin account.
2397
function template_admin_account()
2398
{
2399
	global $incontext, $txt;
2400
2401
	echo '
2402
	<form action="', $incontext['form_url'], '" method="post">
2403
		<p>', $txt['user_settings_info'], '</p>';
2404
2405
	template_warning_divs();
2406
2407
	echo '
2408
		<dl class="settings">
2409
			<dt>
2410
				<label for="username">', $txt['user_settings_username'], ':</label>
2411
			</dt>
2412
			<dd>
2413
				<input type="text" name="username" id="username" value="', $incontext['username'], '" size="40">
2414
				<div class="smalltext">', $txt['user_settings_username_info'], '</div>
2415
			</dd>
2416
			<dt>
2417
				<label for="password1">', $txt['user_settings_password'], ':</label>
2418
			</dt>
2419
			<dd>
2420
				<input type="password" name="password1" id="password1" size="40">
2421
				<div class="smalltext">', $txt['user_settings_password_info'], '</div>
2422
			</dd>
2423
			<dt>
2424
				<label for="password2">', $txt['user_settings_again'], ':</label>
2425
			</dt>
2426
			<dd>
2427
				<input type="password" name="password2" id="password2" size="40">
2428
				<div class="smalltext">', $txt['user_settings_again_info'], '</div>
2429
			</dd>
2430
			<dt>
2431
				<label for="email">', $txt['user_settings_admin_email'], ':</label>
2432
			</dt>
2433
			<dd>
2434
				<input type="text" name="email" id="email" value="', $incontext['email'], '" size="40">
2435
				<div class="smalltext">', $txt['user_settings_admin_email_info'], '</div>
2436
			</dd>
2437
			<dt>
2438
				<label for="server_email">', $txt['user_settings_server_email'], ':</label>
2439
			</dt>
2440
			<dd>
2441
				<input type="text" name="server_email" id="server_email" value="', $incontext['server_email'], '" size="40">
2442
				<div class="smalltext">', $txt['user_settings_server_email_info'], '</div>
2443
			</dd>
2444
		</dl>';
2445
2446
	if ($incontext['require_db_confirm'])
2447
		echo '
2448
		<h2>', $txt['user_settings_database'], '</h2>
2449
		<p>', $txt['user_settings_database_info'], '</p>
2450
2451
		<div class="lefttext">
2452
			<input type="password" name="password3" size="30">
2453
		</div>';
2454
}
2455
2456
// Tell them it's done, and to delete.
2457
function template_delete_install()
2458
{
2459
	global $incontext, $installurl, $txt, $boardurl;
2460
2461
	echo '
2462
		<p>', $txt['congratulations_help'], '</p>';
2463
2464
	template_warning_divs();
2465
2466
	// Install directory still writable?
2467
	if ($incontext['dir_still_writable'])
2468
		echo '
2469
		<p><em>', $txt['still_writable'], '</em></p>';
2470
2471
	// Don't show the box if it's like 99% sure it won't work :P.
2472
	if ($incontext['probably_delete_install'])
2473
		echo '
2474
		<label>
2475
			<input type="checkbox" id="delete_self" onclick="doTheDelete();">
2476
			<strong>', $txt['delete_installer'], !isset($_SESSION['installer_temp_ftp']) ? ' ' . $txt['delete_installer_maybe'] : '', '</strong>
2477
		</label>
2478
		<script>
2479
			function doTheDelete()
2480
			{
2481
				var theCheck = document.getElementById ? document.getElementById("delete_self") : document.all.delete_self;
2482
				var tempImage = new Image();
2483
2484
				tempImage.src = "', $installurl, '?delete=1&ts_" + (new Date().getTime());
2485
				tempImage.width = 0;
2486
				theCheck.disabled = true;
2487
			}
2488
		</script>';
2489
2490
	echo '
2491
		<p>', sprintf($txt['go_to_your_forum'], $boardurl . '/index.php'), '</p>
2492
		<br>
2493
		', $txt['good_luck'];
2494
}
2495
2496
?>
2497