Completed
Pull Request — release-2.1 (#4069)
by Jeremy
14:22 queued 05:31
created

other/install.php (3 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 2017 Simple Machines and individual contributors
9
 * @license http://www.simplemachines.org/about/smf/license.php BSD
10
 *
11
 * @version 2.1 Beta 3
12
 */
13
14
$GLOBALS['current_smf_version'] = '2.1 Beta 3';
15
$GLOBALS['db_script_version'] = '2-1';
16
17
$GLOBALS['required_php_version'] = '5.4.45';
18
19
// Don't have PHP support, do you?
20
// ><html dir="ltr"><head><title>Error!</title></head><body>Sorry, this installer requires PHP!<div style="display: none;">
21
22
// Let's pull in useful classes
23
if (!defined('SMF'))
24
	define('SMF', 1);
25
26
require_once('Sources/Class-Package.php');
27
28
// Database info.
29
$databases = array(
30
	'mysql' => array(
31
		'name' => 'MySQL',
32
		'version' => '5.0.3',
33
		'version_check' => 'return min(mysqli_get_server_info($db_connection), mysqli_get_client_info());',
34
		'supported' => function_exists('mysqli_connect'),
35
		'default_user' => 'mysql.default_user',
36
		'default_password' => 'mysql.default_password',
37
		'default_host' => 'mysql.default_host',
38
		'default_port' => 'mysql.default_port',
39
		'utf8_support' => function() {
40
			return true;
41
		},
42
		'utf8_version' => '5.0.3',
43
		'utf8_version_check' => 'return mysqli_get_server_info($db_connection);',
44
		'utf8_default' => true,
45
		'utf8_required' => true,
46
		'alter_support' => true,
47
		'validate_prefix' => function(&$value) {
48
			$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
49
			return true;
50
		},
51
	),
52
	'postgresql' => array(
53
		'name' => 'PostgreSQL',
54
		'version' => '9.1',
55
		'function_check' => 'pg_connect',
56
		'version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
57
		'supported' => function_exists('pg_connect'),
58
		'always_has_db' => true,
59
		'utf8_default' => true,
60
		'utf8_required' => true,
61
		'utf8_support' => function() {
62
			$request = pg_query('SHOW SERVER_ENCODING');
63
64
			list ($charcode) = pg_fetch_row($request);
65
66
			if ($charcode == 'UTF8')
67
				return true;
68
			else
69
				return false;
70
		},
71
		'utf8_version' => '8.0',
72
		'utf8_version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
73
		'validate_prefix' => function(&$value) {
74
			global $txt;
75
76
			$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
77
78
			// Is it reserved?
79
			if ($value == 'pg_')
80
				return $txt['error_db_prefix_reserved'];
81
82
			// Is the prefix numeric?
83
			if (preg_match('~^\d~', $value))
84
				return $txt['error_db_prefix_numeric'];
85
86
			return true;
87
		},
88
	),
89
);
90
91
global $txt;
92
93
// Initialize everything and load the language files.
94
initialize_inputs();
95
load_lang_file();
96
97
// This is what we are.
98
$installurl = $_SERVER['PHP_SELF'];
99
100
// All the steps in detail.
101
// Number,Name,Function,Progress Weight.
102
$incontext['steps'] = array(
103
	0 => array(1, $txt['install_step_welcome'], 'Welcome', 0),
104
	1 => array(2, $txt['install_step_writable'], 'CheckFilesWritable', 10),
105
	2 => array(3, $txt['install_step_databaseset'], 'DatabaseSettings', 15),
106
	3 => array(4, $txt['install_step_forum'], 'ForumSettings', 40),
107
	4 => array(5, $txt['install_step_databasechange'], 'DatabasePopulation', 15),
108
	5 => array(6, $txt['install_step_admin'], 'AdminAccount', 20),
109
	6 => array(7, $txt['install_step_delete'], 'DeleteInstall', 0),
110
);
111
112
// Default title...
113
$incontext['page_title'] = $txt['smf_installer'];
114
115
// What step are we on?
116
$incontext['current_step'] = isset($_GET['step']) ? (int) $_GET['step'] : 0;
117
118
// Loop through all the steps doing each one as required.
119
$incontext['overall_percent'] = 0;
120
121
foreach ($incontext['steps'] as $num => $step)
122
{
123
	if ($num >= $incontext['current_step'])
124
	{
125
		// The current weight of this step in terms of overall progress.
126
		$incontext['step_weight'] = $step[3];
127
		// Make sure we reset the skip button.
128
		$incontext['skip'] = false;
129
130
		// Call the step and if it returns false that means pause!
131
		if (function_exists($step[2]) && $step[2]() === false)
132
			break;
133
		elseif (function_exists($step[2]))
134
			$incontext['current_step']++;
135
136
		// No warnings pass on.
137
		$incontext['warning'] = '';
138
	}
139
	$incontext['overall_percent'] += $step[3];
140
}
141
142
// Actually do the template stuff.
143
installExit();
144
145
function initialize_inputs()
146
{
147
	global $databases;
148
149
	// Just so people using older versions of PHP aren't left in the cold.
150
	if (!isset($_SERVER['PHP_SELF']))
151
		$_SERVER['PHP_SELF'] = isset($GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']) ? $GLOBALS['HTTP_SERVER_VARS']['PHP_SELF'] : 'install.php';
152
153
	// Enable error reporting.
154
	error_reporting(E_ALL);
155
156
	// Fun.  Low PHP version...
157
	if (!isset($_GET))
158
	{
159
		$GLOBALS['_GET']['step'] = 0;
160
		return;
161
	}
162
163
	if (!isset($_GET['obgz']))
164
	{
165
		ob_start();
166
167
		if (ini_get('session.save_handler') == 'user')
168
			@ini_set('session.save_handler', 'files');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
169
		if (function_exists('session_start'))
170
			@session_start();
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
		header('Location: http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png');
232
		exit;
233
	}
234
235
	// PHP 5 might cry if we don't do this now.
236
	if (function_exists('date_default_timezone_set'))
237
	{
238
		// Get PHP's default timezone, if set
239
		$ini_tz = ini_get('date.timezone');
240
		if (!empty($ini_tz))
241
			$timezone_id = $ini_tz;
242
		else
243
			$timezone_id = '';
244
245
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
246 View Code Duplication
		if (!in_array($timezone_id, timezone_identifiers_list()))
247
		{
248
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
249
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
250
		}
251
252
		date_default_timezone_set($timezone_id);
253
	}
254
255
	// Force an integer step, defaulting to 0.
256
	$_GET['step'] = (int) @$_GET['step'];
257
}
258
259
// Load the list of language files, and the current language file.
260
function load_lang_file()
261
{
262
	global $incontext;
263
264
	$incontext['detected_languages'] = array();
265
266
	// Make sure the languages directory actually exists.
267
	if (file_exists(dirname(__FILE__) . '/Themes/default/languages'))
268
	{
269
		// Find all the "Install" language files in the directory.
270
		$dir = dir(dirname(__FILE__) . '/Themes/default/languages');
271
		while ($entry = $dir->read())
272
		{
273
			if (substr($entry, 0, 8) == 'Install.' && substr($entry, -4) == '.php')
274
				$incontext['detected_languages'][$entry] = ucfirst(substr($entry, 8, strlen($entry) - 12));
275
		}
276
		$dir->close();
277
	}
278
279
	// Didn't find any, show an error message!
280
	if (empty($incontext['detected_languages']))
281
	{
282
		// Let's not cache this message, eh?
283
		header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
284
		header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
285
		header('Cache-Control: no-cache');
286
287
		echo '<!DOCTYPE html>
288
<html>
289
	<head>
290
		<title>SMF Installer: Error!</title>
291
	</head>
292
	<body style="font-family: sans-serif;"><div style="width: 600px;">
293
		<h1 style="font-size: 14pt;">A critical error has occurred.</h1>
294
295
		<p>This installer was unable to find the installer\'s language file or files.  They should be found under:</p>
296
297
		<div style="margin: 1ex; font-family: monospace; font-weight: bold;">', dirname($_SERVER['PHP_SELF']) != '/' ? dirname($_SERVER['PHP_SELF']) : '', '/Themes/default/languages</div>
298
299
		<p>In some cases, FTP clients do not properly upload files with this many folders.  Please double check to make sure you <span style="font-weight: 600;">have uploaded all the files in the distribution</span>.</p>
300
		<p>If that doesn\'t help, please make sure this install.php file is in the same place as the Themes folder.</p>
301
302
		<p>If you continue to get this error message, feel free to <a href="https://support.simplemachines.org/">look to us for support</a>.</p>
303
	</div></body>
304
</html>';
305
		die;
306
	}
307
308
	// Override the language file?
309
	if (isset($_GET['lang_file']))
310
		$_SESSION['installer_temp_lang'] = $_GET['lang_file'];
311
	elseif (isset($GLOBALS['HTTP_GET_VARS']['lang_file']))
312
		$_SESSION['installer_temp_lang'] = $GLOBALS['HTTP_GET_VARS']['lang_file'];
313
314
	// Make sure it exists, if it doesn't reset it.
315
	if (!isset($_SESSION['installer_temp_lang']) || preg_match('~[^\\w_\\-.]~', $_SESSION['installer_temp_lang']) === 1 || !file_exists(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']))
316
	{
317
		// Use the first one...
318
		list ($_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
319
320
		// If we have english and some other language, use the other language.  We Americans hate english :P.
321
		if ($_SESSION['installer_temp_lang'] == 'Install.english.php' && count($incontext['detected_languages']) > 1)
322
			list (, $_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
323
	}
324
325
	// And now include the actual language file itself.
326
	require_once(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']);
327
}
328
329
// This handy function loads some settings and the like.
330
function load_database()
331
{
332
	global $db_prefix, $db_connection, $sourcedir, $smcFunc, $modSettings;
333
	global $db_server, $db_passwd, $db_type, $db_name, $db_user, $db_persist;
334
335
	if (empty($sourcedir))
336
		$sourcedir = dirname(__FILE__) . '/Sources';
337
338
	// Need this to check whether we need the database password.
339
	require(dirname(__FILE__) . '/Settings.php');
340
	if (!defined('SMF'))
341
		define('SMF', 1);
342
	if (empty($smcFunc))
343
		$smcFunc = array();
344
345
	$modSettings['disableQueryCheck'] = true;
346
347
	// Connect the database.
348
	if (!$db_connection)
349
	{
350
		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
351
		if (version_compare(PHP_VERSION, '5', '<'))
352
			require_once($sourcedir . '/Subs-Compat.php');
353
354
		$db_options = array('persist' => $db_persist);
355
		$port = '';
356
357
		// Figure out the port...
358
		if (!empty($_POST['db_port']))
359
		{
360
			if ($db_type == 'mysql')
361
			{
362
				$port = ((int) $_POST['db_port'] == ini_get($db_type . 'default_port')) ? '' : (int) $_POST['db_port'];
363
			}
364 View Code Duplication
			elseif ($db_type == 'postgresql')
365
			{
366
				// PostgreSQL doesn't have a default port setting in php.ini, so just check against the default
367
				$port = ((int) $_POST['db_port'] == 5432) ? '' : (int) $_POST['db_port'];
368
			}
369
		}
370
371
		if (!empty($port))
372
			$db_options['port'] = $port;
373
374
		if (!$db_connection)
375
			$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options);
376
	}
377
}
378
379
// This is called upon exiting the installer, for template etc.
380
function installExit($fallThrough = false)
381
{
382
	global $incontext, $installurl, $txt;
383
384
	// Send character set.
385
	header('Content-Type: text/html; charset=' . (isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8'));
386
387
	// We usually dump our templates out.
388
	if (!$fallThrough)
389
	{
390
		// The top install bit.
391
		template_install_above();
392
393
		// Call the template.
394
		if (isset($incontext['sub_template']))
395
		{
396
			$incontext['form_url'] = $installurl . '?step=' . $incontext['current_step'];
397
398
			call_user_func('template_' . $incontext['sub_template']);
399
		}
400
		// @todo REMOVE THIS!!
401
		else
402
		{
403
			if (function_exists('doStep' . $_GET['step']))
404
				call_user_func('doStep' . $_GET['step']);
405
		}
406
		// Show the footer.
407
		template_install_below();
408
	}
409
410
	// Bang - gone!
411
	die();
412
}
413
414
function Welcome()
415
{
416
	global $incontext, $txt, $databases, $installurl;
417
418
	$incontext['page_title'] = $txt['install_welcome'];
419
	$incontext['sub_template'] = 'welcome_message';
420
421
	// Done the submission?
422
	if (isset($_POST['contbutt']))
423
		return true;
424
425
	// See if we think they have already installed it?
426
	if (is_readable(dirname(__FILE__) . '/Settings.php'))
427
	{
428
		$probably_installed = 0;
429
		foreach (file(dirname(__FILE__) . '/Settings.php') as $line)
430
		{
431
			if (preg_match('~^\$db_passwd\s=\s\'([^\']+)\';$~', $line))
432
				$probably_installed++;
433
			if (preg_match('~^\$boardurl\s=\s\'([^\']+)\';~', $line) && !preg_match('~^\$boardurl\s=\s\'http://127\.0\.0\.1/smf\';~', $line))
434
				$probably_installed++;
435
		}
436
437
		if ($probably_installed == 2)
438
			$incontext['warning'] = $txt['error_already_installed'];
439
	}
440
441
	// Is some database support even compiled in?
442
	$incontext['supported_databases'] = array();
443
	foreach ($databases as $key => $db)
444
	{
445
		if ($db['supported'])
446
		{
447
			$type = ($key == 'mysqli') ? 'mysql' : $key;
448
			if (!file_exists(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql'))
449
			{
450
				$databases[$key]['supported'] = false;
451
				$notFoundSQLFile = true;
452
				$txt['error_db_script_missing'] = sprintf($txt['error_db_script_missing'], 'install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
453
			}
454
			else
455
				$incontext['supported_databases'][] = $db;
456
		}
457
	}
458
459
	// Check the PHP version.
460
	if ((!function_exists('version_compare') || version_compare($GLOBALS['required_php_version'], PHP_VERSION, '>')))
461
		$error = 'error_php_too_low';
462
	// Make sure we have a supported database
463
	elseif (empty($incontext['supported_databases']))
464
		$error = empty($notFoundSQLFile) ? 'error_db_missing' : 'error_db_script_missing';
465
	// How about session support?  Some crazy sysadmin remove it?
466
	elseif (!function_exists('session_start'))
467
		$error = 'error_session_missing';
468
	// Make sure they uploaded all the files.
469
	elseif (!file_exists(dirname(__FILE__) . '/index.php'))
470
		$error = 'error_missing_files';
471
	// Very simple check on the session.save_path for Windows.
472
	// @todo Move this down later if they don't use database-driven sessions?
473
	elseif (@ini_get('session.save_path') == '/tmp' && substr(__FILE__, 1, 2) == ':\\')
474
		$error = 'error_session_save_path';
475
476
	// Since each of the three messages would look the same, anyway...
477
	if (isset($error))
478
		$incontext['error'] = $txt[$error];
479
480
	// Mod_security blocks everything that smells funny. Let SMF handle security.
481
	if (!fixModSecurity() && !isset($_GET['overmodsecurity']))
482
		$incontext['error'] = $txt['error_mod_security'] . '<br><br><a href="' . $installurl . '?overmodsecurity=true">' . $txt['error_message_click'] . '</a> ' . $txt['error_message_bad_try_again'];
483
484
	return false;
485
}
486
487
function CheckFilesWritable()
488
{
489
	global $txt, $incontext;
490
491
	$incontext['page_title'] = $txt['ftp_checking_writable'];
492
	$incontext['sub_template'] = 'chmod_files';
493
494
	$writable_files = array(
495
		'attachments',
496
		'avatars',
497
		'custom_avatar',
498
		'cache',
499
		'Packages',
500
		'Smileys',
501
		'Themes',
502
		'agreement.txt',
503
		'Settings.php',
504
		'Settings_bak.php',
505
		'db_last_error.php',
506
	);
507
508
	foreach ($incontext['detected_languages'] as $lang => $temp)
509
		$extra_files[] = 'Themes/default/languages/' . $lang;
510
511
	// With mod_security installed, we could attempt to fix it with .htaccess.
512
	if (function_exists('apache_get_modules') && in_array('mod_security', apache_get_modules()))
513
		$writable_files[] = file_exists(dirname(__FILE__) . '/.htaccess') ? '.htaccess' : '.';
514
515
	$failed_files = array();
516
517
	// On linux, it's easy - just use is_writable!
518
	if (substr(__FILE__, 1, 2) != ':\\')
519
	{
520
		$incontext['systemos'] = 'linux';
521
522
		foreach ($writable_files as $file)
523
		{
524
			if (!is_writable(dirname(__FILE__) . '/' . $file))
525
			{
526
				@chmod(dirname(__FILE__) . '/' . $file, 0755);
527
528
				// Well, 755 hopefully worked... if not, try 777.
529
				if (!is_writable(dirname(__FILE__) . '/' . $file) && !@chmod(dirname(__FILE__) . '/' . $file, 0777))
530
					$failed_files[] = $file;
531
			}
532
		}
533 View Code Duplication
		foreach ($extra_files as $file)
534
			@chmod(dirname(__FILE__) . (empty($file) ? '' : '/' . $file), 0777);
535
	}
536
	// Windows is trickier.  Let's try opening for r+...
537
	else
538
	{
539
		$incontext['systemos'] = 'windows';
540
541
		foreach ($writable_files as $file)
542
		{
543
			// Folders can't be opened for write... but the index.php in them can ;)
544
			if (is_dir(dirname(__FILE__) . '/' . $file))
545
				$file .= '/index.php';
546
547
			// Funny enough, chmod actually does do something on windows - it removes the read only attribute.
548
			@chmod(dirname(__FILE__) . '/' . $file, 0777);
549
			$fp = @fopen(dirname(__FILE__) . '/' . $file, 'r+');
550
551
			// Hmm, okay, try just for write in that case...
552
			if (!is_resource($fp))
553
				$fp = @fopen(dirname(__FILE__) . '/' . $file, 'w');
554
555
			if (!is_resource($fp))
556
				$failed_files[] = $file;
557
558
			@fclose($fp);
559
		}
560 View Code Duplication
		foreach ($extra_files as $file)
561
			@chmod(dirname(__FILE__) . (empty($file) ? '' : '/' . $file), 0777);
562
	}
563
564
	$failure = count($failed_files) >= 1;
565
566
	if (!isset($_SERVER))
567
		return !$failure;
568
569
	// Put the list into context.
570
	$incontext['failed_files'] = $failed_files;
571
572
	// It's not going to be possible to use FTP on windows to solve the problem...
573
	if ($failure && substr(__FILE__, 1, 2) == ':\\')
574
	{
575
		$incontext['error'] = $txt['error_windows_chmod'] . '
576
					<ul style="margin: 2.5ex; font-family: monospace;">
577
						<li>' . implode('</li>
578
						<li>', $failed_files) . '</li>
579
					</ul>';
580
581
		return false;
582
	}
583
	// We're going to have to use... FTP!
584
	elseif ($failure)
585
	{
586
		// Load any session data we might have...
587
		if (!isset($_POST['ftp_username']) && isset($_SESSION['installer_temp_ftp']))
588
		{
589
			$_POST['ftp_server'] = $_SESSION['installer_temp_ftp']['server'];
590
			$_POST['ftp_port'] = $_SESSION['installer_temp_ftp']['port'];
591
			$_POST['ftp_username'] = $_SESSION['installer_temp_ftp']['username'];
592
			$_POST['ftp_password'] = $_SESSION['installer_temp_ftp']['password'];
593
			$_POST['ftp_path'] = $_SESSION['installer_temp_ftp']['path'];
594
		}
595
596
		$incontext['ftp_errors'] = array();
597
		require_once('Sources/Class-Package.php');
598 View Code Duplication
		if (isset($_POST['ftp_username']))
599
		{
600
			$ftp = new ftp_connection($_POST['ftp_server'], $_POST['ftp_port'], $_POST['ftp_username'], $_POST['ftp_password']);
601
602
			if ($ftp->error === false)
603
			{
604
				// Try it without /home/abc just in case they messed up.
605
				if (!$ftp->chdir($_POST['ftp_path']))
606
				{
607
					$incontext['ftp_errors'][] = $ftp->last_message;
608
					$ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $_POST['ftp_path']));
609
				}
610
			}
611
		}
612
613
		if (!isset($ftp) || $ftp->error !== false)
614
		{
615
			if (!isset($ftp))
616
				$ftp = new ftp_connection(null);
617
			// Save the error so we can mess with listing...
618
			elseif ($ftp->error !== false && empty($incontext['ftp_errors']) && !empty($ftp->last_message))
619
				$incontext['ftp_errors'][] = $ftp->last_message;
620
621
			list ($username, $detect_path, $found_path) = $ftp->detect_path(dirname(__FILE__));
622
623
			if (empty($_POST['ftp_path']) && $found_path)
624
				$_POST['ftp_path'] = $detect_path;
625
626
			if (!isset($_POST['ftp_username']))
627
				$_POST['ftp_username'] = $username;
628
629
			// Set the username etc, into context.
630
			$incontext['ftp'] = array(
631
				'server' => isset($_POST['ftp_server']) ? $_POST['ftp_server'] : 'localhost',
632
				'port' => isset($_POST['ftp_port']) ? $_POST['ftp_port'] : '21',
633
				'username' => isset($_POST['ftp_username']) ? $_POST['ftp_username'] : '',
634
				'path' => isset($_POST['ftp_path']) ? $_POST['ftp_path'] : '/',
635
				'path_msg' => !empty($found_path) ? $txt['ftp_path_found_info'] : $txt['ftp_path_info'],
636
			);
637
638
			return false;
639
		}
640
		else
641
		{
642
			$_SESSION['installer_temp_ftp'] = array(
643
				'server' => $_POST['ftp_server'],
644
				'port' => $_POST['ftp_port'],
645
				'username' => $_POST['ftp_username'],
646
				'password' => $_POST['ftp_password'],
647
				'path' => $_POST['ftp_path']
648
			);
649
650
			$failed_files_updated = array();
651
652
			foreach ($failed_files as $file)
653
			{
654
				if (!is_writable(dirname(__FILE__) . '/' . $file))
655
					$ftp->chmod($file, 0755);
656
				if (!is_writable(dirname(__FILE__) . '/' . $file))
657
					$ftp->chmod($file, 0777);
658
				if (!is_writable(dirname(__FILE__) . '/' . $file))
659
				{
660
					$failed_files_updated[] = $file;
661
					$incontext['ftp_errors'][] = rtrim($ftp->last_message) . ' -> ' . $file . "\n";
662
				}
663
			}
664
665
			$ftp->close();
666
667
			// Are there any errors left?
668
			if (count($failed_files_updated) >= 1)
669
			{
670
				// Guess there are...
671
				$incontext['failed_files'] = $failed_files_updated;
672
673
				// Set the username etc, into context.
674
				$incontext['ftp'] = $_SESSION['installer_temp_ftp'] += array(
675
					'path_msg' => $txt['ftp_path_info'],
676
				);
677
678
				return false;
679
			}
680
		}
681
	}
682
683
	return true;
684
}
685
686
function DatabaseSettings()
687
{
688
	global $txt, $databases, $incontext, $smcFunc, $sourcedir;
689
	global $db_server, $db_name, $db_user, $db_passwd;
690
691
	$incontext['sub_template'] = 'database_settings';
692
	$incontext['page_title'] = $txt['db_settings'];
693
	$incontext['continue'] = 1;
694
695
	// Set up the defaults.
696
	$incontext['db']['server'] = 'localhost';
697
	$incontext['db']['user'] = '';
698
	$incontext['db']['name'] = '';
699
	$incontext['db']['pass'] = '';
700
	$incontext['db']['type'] = '';
701
	$incontext['supported_databases'] = array();
702
703
	$foundOne = false;
704
	foreach ($databases as $key => $db)
705
	{
706
		// Override with the defaults for this DB if appropriate.
707
		if ($db['supported'])
708
		{
709
			$incontext['supported_databases'][$key] = $db;
710
711
			if (!$foundOne)
712
			{
713
				if (isset($db['default_host']))
714
					$incontext['db']['server'] = ini_get($db['default_host']) or $incontext['db']['server'] = 'localhost';
715
				if (isset($db['default_user']))
716
				{
717
					$incontext['db']['user'] = ini_get($db['default_user']);
718
					$incontext['db']['name'] = ini_get($db['default_user']);
719
				}
720
				if (isset($db['default_password']))
721
					$incontext['db']['pass'] = ini_get($db['default_password']);
722
723
				// For simplicity and less confusion, leave the port blank by default
724
				$incontext['db']['port'] = '';
725
726
				$incontext['db']['type'] = $key;
727
				$foundOne = true;
728
			}
729
		}
730
	}
731
732
	// Override for repost.
733
	if (isset($_POST['db_user']))
734
	{
735
		$incontext['db']['user'] = $_POST['db_user'];
736
		$incontext['db']['name'] = $_POST['db_name'];
737
		$incontext['db']['server'] = $_POST['db_server'];
738
		$incontext['db']['prefix'] = $_POST['db_prefix'];
739
740
		if (!empty($_POST['db_port']))
741
			$incontext['db']['port'] = $_POST['db_port'];
742
	}
743
	else
744
	{
745
		$incontext['db']['prefix'] = 'smf_';
746
	}
747
748
	// Are we submitting?
749
	if (isset($_POST['db_type']))
750
	{
751
		// What type are they trying?
752
		$db_type = preg_replace('~[^A-Za-z0-9]~', '', $_POST['db_type']);
753
		$db_prefix = $_POST['db_prefix'];
754
		// Validate the prefix.
755
		$valid_prefix = $databases[$db_type]['validate_prefix']($db_prefix);
756
757
		if ($valid_prefix !== true)
758
		{
759
			$incontext['error'] = $valid_prefix;
760
			return false;
761
		}
762
763
		// Take care of these variables...
764
		$vars = array(
765
			'db_type' => $db_type,
766
			'db_name' => $_POST['db_name'],
767
			'db_user' => $_POST['db_user'],
768
			'db_passwd' => isset($_POST['db_passwd']) ? $_POST['db_passwd'] : '',
769
			'db_server' => $_POST['db_server'],
770
			'db_prefix' => $db_prefix,
771
			// The cookiename is special; we want it to be the same if it ever needs to be reinstalled with the same info.
772
			'cookiename' => 'SMFCookie' . abs(crc32($_POST['db_name'] . preg_replace('~[^A-Za-z0-9_$]~', '', $_POST['db_prefix'])) % 1000),
773
		);
774
775
		// Only set the port if we're not using the default
776
		if (!empty($_POST['db_port']))
777
		{
778
			// For MySQL, we can get the "default port" from PHP. PostgreSQL has no such option though.
779
			if (($db_type == 'mysql' || $db_type == 'mysqli') && $_POST['db_port'] != ini_get($db_type . '.default_port'))
780
				$vars['db_port'] = (int) $_POST['db_port'];
781 View Code Duplication
			elseif ($db_type == 'postgresql' && $_POST['db_port'] != 5432)
782
				$vars['db_port'] = (int) $_POST['db_port'];
783
		}
784
785
		// God I hope it saved!
786 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
787
		{
788
			$incontext['error'] = $txt['error_windows_chmod'];
789
			return false;
790
		}
791
792
		// Make sure it works.
793
		require(dirname(__FILE__) . '/Settings.php');
794
795
		if (empty($sourcedir))
796
			$sourcedir = dirname(__FILE__) . '/Sources';
797
798
		// Better find the database file!
799
		if (!file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php'))
800
		{
801
			$incontext['error'] = sprintf($txt['error_db_file'], 'Subs-Db-' . $db_type . '.php');
802
			return false;
803
		}
804
805
		// Now include it for database functions!
806
		if (!defined('SMF'))
807
			define('SMF', 1);
808
809
		$modSettings['disableQueryCheck'] = true;
810
		if (empty($smcFunc))
811
			$smcFunc = array();
812
813
			require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
814
815
		// What - running PHP4? The shame!
816
		if (version_compare(PHP_VERSION, '5', '<'))
817
			require_once($sourcedir . '/Subs-Compat.php');
818
819
		// Attempt a connection.
820
		$needsDB = !empty($databases[$db_type]['always_has_db']);
821
		$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('non_fatal' => true, 'dont_select_db' => !$needsDB));
822
823
		// No dice?  Let's try adding the prefix they specified, just in case they misread the instructions ;)
824
		if ($db_connection == null)
825
		{
826
			$db_error = @$smcFunc['db_error']();
827
828
			$db_connection = smf_db_initiate($db_server, $db_name, $_POST['db_prefix'] . $db_user, $db_passwd, $db_prefix, array('non_fatal' => true, 'dont_select_db' => !$needsDB));
829
			if ($db_connection != null)
830
			{
831
				$db_user = $_POST['db_prefix'] . $db_user;
832
				updateSettingsFile(array('db_user' => $db_user));
833
			}
834
		}
835
836
		// Still no connection?  Big fat error message :P.
837
		if (!$db_connection)
838
		{
839
			$incontext['error'] = $txt['error_db_connect'] . '<div style="margin: 2.5ex; font-family: monospace;"><strong>' . $db_error . '</strong></div>';
840
			return false;
841
		}
842
843
		// Do they meet the install requirements?
844
		// @todo Old client, new server?
845
		if (version_compare($databases[$db_type]['version'], preg_replace('~^\D*|\-.+?$~', '', eval($databases[$db_type]['version_check']))) > 0)
846
		{
847
			$incontext['error'] = $txt['error_db_too_low'];
848
			return false;
849
		}
850
851
		// Let's try that database on for size... assuming we haven't already lost the opportunity.
852
		if ($db_name != '' && !$needsDB)
853
		{
854
			$smcFunc['db_query']('', "
855
				CREATE DATABASE IF NOT EXISTS `$db_name`",
856
				array(
857
					'security_override' => true,
858
					'db_error_skip' => true,
859
				),
860
				$db_connection
861
			);
862
863
			// Okay, let's try the prefix if it didn't work...
864
			if (!$smcFunc['db_select_db']($db_name, $db_connection) && $db_name != '')
865
			{
866
				$smcFunc['db_query']('', "
867
					CREATE DATABASE IF NOT EXISTS `$_POST[db_prefix]$db_name`",
868
					array(
869
						'security_override' => true,
870
						'db_error_skip' => true,
871
					),
872
					$db_connection
873
				);
874
875
				if ($smcFunc['db_select_db']($_POST['db_prefix'] . $db_name, $db_connection))
876
				{
877
					$db_name = $_POST['db_prefix'] . $db_name;
878
					updateSettingsFile(array('db_name' => $db_name));
879
				}
880
			}
881
882
			// Okay, now let's try to connect...
883
			if (!$smcFunc['db_select_db']($db_name, $db_connection))
884
			{
885
				$incontext['error'] = sprintf($txt['error_db_database'], $db_name);
886
				return false;
887
			}
888
		}
889
890
		return true;
891
	}
892
893
	return false;
894
}
895
896
// Let's start with basic forum type settings.
897
function ForumSettings()
898
{
899
	global $txt, $incontext, $databases, $db_type;
900
901
	$incontext['sub_template'] = 'forum_settings';
902
	$incontext['page_title'] = $txt['install_settings'];
903
904
	// Let's see if we got the database type correct.
905
	if (isset($_POST['db_type'], $databases[$_POST['db_type']]))
906
		$db_type = $_POST['db_type'];
907
908
	// Else we'd better be able to get the connection.
909
	else
910
		load_database();
911
912
	$db_type = isset($_POST['db_type']) ? $_POST['db_type'] : $db_type;
913
914
	// What host and port are we on?
915
	$host = empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST'];
916
917
	// Now, to put what we've learned together... and add a path.
918
	$incontext['detected_url'] = 'http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . $host . substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
919
920
	// Check if the database sessions will even work.
921
	$incontext['test_dbsession'] = (ini_get('session.auto_start') != 1);
922
	$incontext['utf8_default'] = $databases[$db_type]['utf8_default'];
923
	$incontext['utf8_required'] = $databases[$db_type]['utf8_required'];
924
925
	$incontext['continue'] = 1;
926
927
	// Submitting?
928
	if (isset($_POST['boardurl']))
929
	{
930 View Code Duplication
		if (substr($_POST['boardurl'], -10) == '/index.php')
931
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -10);
932
		elseif (substr($_POST['boardurl'], -1) == '/')
933
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -1);
934 View Code Duplication
		if (substr($_POST['boardurl'], 0, 7) != 'http://' && substr($_POST['boardurl'], 0, 7) != 'file://' && substr($_POST['boardurl'], 0, 8) != 'https://')
935
			$_POST['boardurl'] = 'http://' . $_POST['boardurl'];
936
937
		// Save these variables.
938
		$vars = array(
939
			'boardurl' => $_POST['boardurl'],
940
			'boarddir' => addslashes(dirname(__FILE__)),
941
			'sourcedir' => addslashes(dirname(__FILE__)) . '/Sources',
942
			'cachedir' => addslashes(dirname(__FILE__)) . '/cache',
943
			'packagesdir' => addslashes(dirname(__FILE__)) . '/Packages',
944
			'tasksdir' => addslashes(dirname(__FILE__)) . '/Sources/tasks',
945
			'mbname' => strtr($_POST['mbname'], array('\"' => '"')),
946
			'language' => substr($_SESSION['installer_temp_lang'], 8, -4),
947
			'image_proxy_secret' => substr(sha1(mt_rand()), 0, 20),
948
			'image_proxy_enabled' => !empty($_POST['force_ssl']),
949
		);
950
951
		// Must save!
952 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
953
		{
954
			$incontext['error'] = $txt['error_windows_chmod'];
955
			return false;
956
		}
957
958
		// Make sure it works.
959
		require(dirname(__FILE__) . '/Settings.php');
960
961
		// UTF-8 requires a setting to override the language charset.
962
		if ((!empty($databases[$db_type]['utf8_support']) && !empty($databases[$db_type]['utf8_required'])) || (empty($databases[$db_type]['utf8_required']) && !empty($databases[$db_type]['utf8_support']) && isset($_POST['utf8'])))
963
		{
964
			if (!$databases[$db_type]['utf8_support']())
965
			{
966
				$incontext['error'] = sprintf($txt['error_utf8_support']);
967
				return false;
968
			}
969
970
			if (!empty($databases[$db_type]['utf8_version_check']) && version_compare($databases[$db_type]['utf8_version'], preg_replace('~\-.+?$~', '', eval($databases[$db_type]['utf8_version_check'])), '>'))
971
			{
972
				$incontext['error'] = sprintf($txt['error_utf8_version'], $databases[$db_type]['utf8_version']);
973
				return false;
974
			}
975
			else
976
				// Set the character set here.
977
				updateSettingsFile(array('db_character_set' => 'utf8'));
978
		}
979
980
		// Good, skip on.
981
		return true;
982
	}
983
984
	return false;
985
}
986
987
// Step one: Do the SQL thang.
988
function DatabasePopulation()
989
{
990
	global $db_character_set, $txt, $db_connection, $smcFunc, $databases, $modSettings, $db_type, $db_prefix, $incontext, $db_name, $boardurl;
991
992
	$incontext['sub_template'] = 'populate_database';
993
	$incontext['page_title'] = $txt['db_populate'];
994
	$incontext['continue'] = 1;
995
996
	// Already done?
997
	if (isset($_POST['pop_done']))
998
		return true;
999
1000
	// Reload settings.
1001
	require(dirname(__FILE__) . '/Settings.php');
1002
	load_database();
1003
1004
	// Before running any of the queries, let's make sure another version isn't already installed.
1005
	$result = $smcFunc['db_query']('', '
1006
		SELECT variable, value
1007
		FROM {db_prefix}settings',
1008
		array(
1009
			'db_error_skip' => true,
1010
		)
1011
	);
1012
	$newSettings = array();
1013
	$modSettings = array();
1014
	if ($result !== false)
1015
	{
1016 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($result))
1017
			$modSettings[$row['variable']] = $row['value'];
1018
		$smcFunc['db_free_result']($result);
1019
1020
		// Do they match?  If so, this is just a refresh so charge on!
1021
		if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] != $GLOBALS['current_smf_version'])
1022
		{
1023
			$incontext['error'] = $txt['error_versions_do_not_match'];
1024
			return false;
1025
		}
1026
	}
1027
	$modSettings['disableQueryCheck'] = true;
1028
1029
	// If doing UTF8, select it. PostgreSQL requires passing it as a string...
1030 View Code Duplication
	if (!empty($db_character_set) && $db_character_set == 'utf8' && !empty($databases[$db_type]['utf8_support']))
1031
		$smcFunc['db_query']('', '
1032
			SET NAMES {string:utf8}',
1033
			array(
1034
				'db_error_skip' => true,
1035
				'utf8' => 'utf8',
1036
			)
1037
		);
1038
1039
	// Windows likes to leave the trailing slash, which yields to C:\path\to\SMF\/attachments...
1040
	if (substr(__DIR__, -1) == '\\')
1041
		$attachdir = __DIR__ . 'attachments';
1042
	else
1043
		$attachdir = __DIR__ . '/attachments';
1044
1045
	$replaces = array(
1046
		'{$db_prefix}' => $db_prefix,
1047
		'{$attachdir}' => json_encode(array(1 => $smcFunc['db_escape_string']($attachdir))),
1048
		'{$boarddir}' => $smcFunc['db_escape_string'](dirname(__FILE__)),
1049
		'{$boardurl}' => $boardurl,
1050
		'{$enableCompressedOutput}' => isset($_POST['compress']) ? '1' : '0',
1051
		'{$databaseSession_enable}' => isset($_POST['dbsession']) ? '1' : '0',
1052
		'{$smf_version}' => $GLOBALS['current_smf_version'],
1053
		'{$current_time}' => time(),
1054
		'{$sched_task_offset}' => 82800 + mt_rand(0, 86399),
1055
		'{$registration_method}' => isset($_POST['reg_mode']) ? $_POST['reg_mode'] : 0,
1056
	);
1057
1058
	foreach ($txt as $key => $value)
1059
	{
1060
		if (substr($key, 0, 8) == 'default_')
1061
			$replaces['{$' . $key . '}'] = $smcFunc['db_escape_string']($value);
1062
	}
1063
	$replaces['{$default_reserved_names}'] = strtr($replaces['{$default_reserved_names}'], array('\\\\n' => '\\n'));
1064
1065
	// MySQL-specific stuff - storage engine and UTF8 handling
1066
	if (substr($db_type, 0, 5) == 'mysql')
1067
	{
1068
		// Just in case the query fails for some reason...
1069
		$engines = array();
1070
1071
		// Figure out storage engines - what do we have, etc.
1072
		$get_engines = $smcFunc['db_query']('', 'SHOW ENGINES', array());
1073
1074 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($get_engines))
1075
		{
1076
			if ($row['Support'] == 'YES' || $row['Support'] == 'DEFAULT')
1077
				$engines[] = $row['Engine'];
1078
		}
1079
1080
		// Done with this now
1081
		$smcFunc['db_free_result']($get_engines);
1082
1083
		// InnoDB is better, so use it if possible...
1084
		$has_innodb = in_array('InnoDB', $engines);
1085
		$replaces['{$engine}'] = $has_innodb ? 'InnoDB' : 'MyISAM';
1086
		$replaces['{$memory}'] = (!$has_innodb && in_array('MEMORY', $engines)) ? 'MEMORY' : $replaces['{$engine}'];
1087
1088
		// If the UTF-8 setting was enabled, add it to the table definitions.
1089
		if (!empty($databases[$db_type]['utf8_support']) && (!empty($databases[$db_type]['utf8_required']) || isset($_POST['utf8'])))
1090
		{
1091
			$replaces['{$engine}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1092
			$replaces['{$memory}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1093
		}
1094
1095
		// One last thing - if we don't have InnoDB, we can't do transactions...
1096
		if (!$has_innodb)
1097
		{
1098
			$replaces['START TRANSACTION;'] = '';
1099
			$replaces['COMMIT;'] = '';
1100
		}
1101
	}
1102
	else
1103
	{
1104
		$has_innodb = false;
1105
	}
1106
1107
	// Read in the SQL.  Turn this on and that off... internationalize... etc.
1108
	$type = ($db_type == 'mysqli' ? 'mysql' : $db_type);
1109
	$sql_lines = explode("\n", strtr(implode(' ', file(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql')), $replaces));
1110
1111
	// Execute the SQL.
1112
	$current_statement = '';
1113
	$exists = array();
1114
	$incontext['failures'] = array();
1115
	$incontext['sql_results'] = array(
1116
		'tables' => 0,
1117
		'inserts' => 0,
1118
		'table_dups' => 0,
1119
		'insert_dups' => 0,
1120
	);
1121
	foreach ($sql_lines as $count => $line)
1122
	{
1123
		// No comments allowed!
1124
		if (substr(trim($line), 0, 1) != '#')
1125
			$current_statement .= "\n" . rtrim($line);
1126
1127
		// Is this the end of the query string?
1128
		if (empty($current_statement) || (preg_match('~;[\s]*$~s', $line) == 0 && $count != count($sql_lines)))
1129
			continue;
1130
1131
		// Does this table already exist?  If so, don't insert more data into it!
1132
		if (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) != 0 && in_array($match[1], $exists))
1133
		{
1134
			preg_match_all('~\)[,;]~', $current_statement, $matches);
1135 View Code Duplication
			if (!empty($matches[0]))
1136
				$incontext['sql_results']['insert_dups'] += count($matches[0]);
1137
			else
1138
				$incontext['sql_results']['insert_dups']++;
1139
1140
			$current_statement = '';
1141
			continue;
1142
		}
1143
1144
		if ($smcFunc['db_query']('', $current_statement, array('security_override' => true, 'db_error_skip' => true), $db_connection) === false)
1145
		{
1146
			// Use the appropriate function based on the DB type
1147
			if ($db_type == 'mysql' || $db_type == 'mysqli')
1148
				$db_errorno = $db_type . '_errno';
1149
1150
			// Error 1050: Table already exists!
1151
			// @todo Needs to be made better!
1152
			if ((($db_type != 'mysql' && $db_type != 'mysqli') || $db_errorno($db_connection) == 1050) && preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1153
			{
1154
				$exists[] = $match[1];
1155
				$incontext['sql_results']['table_dups']++;
1156
			}
1157
			// Don't error on duplicate indexes (or duplicate operators in PostgreSQL.)
1158
			elseif (!preg_match('~^\s*CREATE( UNIQUE)? INDEX ([^\n\r]+?)~', $current_statement, $match) && !($db_type == 'postgresql' && preg_match('~^\s*CREATE OPERATOR (^\n\r]+?)~', $current_statement, $match)))
1159
			{
1160
				// MySQLi requires a connection object. It's optional with MySQL and Postgres
1161
				$incontext['failures'][$count] = $smcFunc['db_error']($db_connection);
1162
			}
1163
		}
1164
		else
1165
		{
1166
			if (preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1167
				$incontext['sql_results']['tables']++;
1168
			elseif (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1169
			{
1170
				preg_match_all('~\)[,;]~', $current_statement, $matches);
1171 View Code Duplication
				if (!empty($matches[0]))
1172
					$incontext['sql_results']['inserts'] += count($matches[0]);
1173
				else
1174
					$incontext['sql_results']['inserts']++;
1175
			}
1176
		}
1177
1178
		$current_statement = '';
1179
1180
		// Wait, wait, I'm still working here!
1181
		set_time_limit(60);
1182
	}
1183
1184
	// Sort out the context for the SQL.
1185
	foreach ($incontext['sql_results'] as $key => $number)
1186
	{
1187
		if ($number == 0)
1188
			unset($incontext['sql_results'][$key]);
1189
		else
1190
			$incontext['sql_results'][$key] = sprintf($txt['db_populate_' . $key], $number);
1191
	}
1192
1193
	// Make sure UTF will be used globally.
1194
	if ((!empty($databases[$db_type]['utf8_support']) && !empty($databases[$db_type]['utf8_required'])) || (empty($databases[$db_type]['utf8_required']) && !empty($databases[$db_type]['utf8_support']) && isset($_POST['utf8'])))
1195
		$newSettings[] = array('global_character_set', 'UTF-8');
1196
1197
	// Maybe we can auto-detect better cookie settings?
1198
	preg_match('~^http[s]?://([^\.]+?)([^/]*?)(/.*)?$~', $boardurl, $matches);
1199
	if (!empty($matches))
1200
	{
1201
		// Default = both off.
1202
		$localCookies = false;
1203
		$globalCookies = false;
1204
1205
		// Okay... let's see.  Using a subdomain other than www.? (not a perfect check.)
1206
		if ($matches[2] != '' && (strpos(substr($matches[2], 1), '.') === false || in_array($matches[1], array('forum', 'board', 'community', 'forums', 'support', 'chat', 'help', 'talk', 'boards', 'www'))))
1207
			$globalCookies = true;
1208
		// If there's a / in the middle of the path, or it starts with ~... we want local.
1209
		if (isset($matches[3]) && strlen($matches[3]) > 3 && (substr($matches[3], 0, 2) == '/~' || strpos(substr($matches[3], 1), '/') !== false))
1210
			$localCookies = true;
1211
1212
		if ($globalCookies)
1213
			$newSettings[] = array('globalCookies', '1');
1214
		if ($localCookies)
1215
			$newSettings[] = array('localCookies', '1');
1216
	}
1217
1218
	// Are we allowing stat collection?
1219
	if (!empty($_POST['stats']) && substr($boardurl, 0, 16) != 'http://localhost' && empty($modSettings['allow_sm_stats']) && empty($modSettings['enable_sm_stats']))
1220
	{
1221
		$upcontext['allow_sm_stats'] = true;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$upcontext was never initialized. Although not strictly required by PHP, it is generally a good practice to add $upcontext = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
1222
1223
		// Attempt to register the site etc.
1224
		$fp = @fsockopen('www.simplemachines.org', 80, $errno, $errstr);
1225 View Code Duplication
		if ($fp)
1226
		{
1227
			$out = 'GET /smf/stats/register_stats.php?site=' . base64_encode($boardurl) . ' HTTP/1.1' . "\r\n";
1228
			$out .= 'Host: www.simplemachines.org' . "\r\n";
1229
			$out .= 'Connection: Close' . "\r\n\r\n";
1230
			fwrite($fp, $out);
1231
1232
			$return_data = '';
1233
			while (!feof($fp))
1234
				$return_data .= fgets($fp, 128);
1235
1236
			fclose($fp);
1237
1238
			// Get the unique site ID.
1239
			preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1240
1241
			if (!empty($ID[1]))
1242
				$smcFunc['db_insert']('replace',
1243
					$db_prefix . 'settings',
1244
					array('variable' => 'string', 'value' => 'string'),
1245
					array(
1246
						array('sm_stats_key', $ID[1]),
1247
						array('enable_sm_stats', 1),
1248
					),
1249
					array('variable')
1250
				);
1251
		}
1252
	}
1253
	// Don't remove stat collection unless we unchecked the box for real, not from the loop.
1254 View Code Duplication
	elseif (empty($_POST['stats']) && empty($upcontext['allow_sm_stats']))
0 ignored issues
show
The variable $upcontext seems only to be defined at a later point. As such the call to empty() seems to always evaluate to true.

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

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

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