Completed
Push — release-2.1 ( e55abf...f15ab1 )
by
unknown
08:31
created

other/install.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

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

1
<?php
2
3
/**
4
 * Simple Machines Forum (SMF)
5
 *
6
 * @package SMF
7
 * @author Simple Machines http://www.simplemachines.org
8
 * @copyright 2018 Simple Machines and individual contributors
9
 * @license http://www.simplemachines.org/about/smf/license.php BSD
10
 *
11
 * @version 2.1 Beta 4
12
 */
13
14
$GLOBALS['current_smf_version'] = '2.1 Beta 4';
15
$GLOBALS['db_script_version'] = '2-1';
16
17
$GLOBALS['required_php_version'] = '5.4.0';
18
19
// Don't have PHP support, do you?
20
// ><html dir="ltr"><head><title>Error!</title></head><body>Sorry, this installer requires PHP!<div style="display: none;">
21
22
// Let's pull in useful classes
23
if (!defined('SMF'))
24
	define('SMF', 1);
25
26
require_once('Sources/Class-Package.php');
27
28
// Database info.
29
$databases = array(
30
	'mysql' => array(
31
		'name' => 'MySQL',
32
		'version' => '5.0.22',
33
		'version_check' => 'return min(mysqli_get_server_info($db_connection), mysqli_get_client_info());',
34
		'supported' => function_exists('mysqli_connect'),
35
		'default_user' => 'mysql.default_user',
36
		'default_password' => 'mysql.default_password',
37
		'default_host' => 'mysql.default_host',
38
		'default_port' => 'mysql.default_port',
39
		'utf8_support' => function() {
40
			return true;
41
		},
42
		'utf8_version' => '5.0.22',
43
		'utf8_version_check' => 'return mysqli_get_server_info($db_connection);',
44
		'utf8_default' => true,
45
		'utf8_required' => true,
46
		'alter_support' => true,
47
		'validate_prefix' => function(&$value) {
48
			$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
49
			return true;
50
		},
51
	),
52
	'postgresql' => array(
53
		'name' => 'PostgreSQL',
54
		'version' => '9.2',
55
		'function_check' => 'pg_connect',
56
		'version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
57
		'supported' => function_exists('pg_connect'),
58
		'always_has_db' => true,
59
		'utf8_default' => true,
60
		'utf8_required' => true,
61
		'utf8_support' => function() {
62
			$request = pg_query('SHOW SERVER_ENCODING');
63
64
			list ($charcode) = pg_fetch_row($request);
65
66
			if ($charcode == 'UTF8')
67
				return true;
68
			else
69
				return false;
70
		},
71
		'utf8_version' => '8.0',
72
		'utf8_version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
73
		'validate_prefix' => function(&$value) {
74
			global $txt;
75
76
			$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
77
78
			// Is it reserved?
79
			if ($value == 'pg_')
80
				return $txt['error_db_prefix_reserved'];
81
82
			// Is the prefix numeric?
83
			if (preg_match('~^\d~', $value))
84
				return $txt['error_db_prefix_numeric'];
85
86
			return true;
87
		},
88
	),
89
);
90
91
global $txt;
92
93
// Initialize everything and load the language files.
94
initialize_inputs();
95
load_lang_file();
96
97
// This is what we are.
98
$installurl = $_SERVER['PHP_SELF'];
99
100
// All the steps in detail.
101
// Number,Name,Function,Progress Weight.
102
$incontext['steps'] = array(
103
	0 => array(1, $txt['install_step_welcome'], 'Welcome', 0),
104
	1 => array(2, $txt['install_step_writable'], 'CheckFilesWritable', 10),
105
	2 => array(3, $txt['install_step_databaseset'], 'DatabaseSettings', 15),
106
	3 => array(4, $txt['install_step_forum'], 'ForumSettings', 40),
107
	4 => array(5, $txt['install_step_databasechange'], 'DatabasePopulation', 15),
108
	5 => array(6, $txt['install_step_admin'], 'AdminAccount', 20),
109
	6 => array(7, $txt['install_step_delete'], 'DeleteInstall', 0),
110
);
111
112
// Default title...
113
$incontext['page_title'] = $txt['smf_installer'];
114
115
// What step are we on?
116
$incontext['current_step'] = isset($_GET['step']) ? (int) $_GET['step'] : 0;
117
118
// Loop through all the steps doing each one as required.
119
$incontext['overall_percent'] = 0;
120
121
foreach ($incontext['steps'] as $num => $step)
122
{
123
	if ($num >= $incontext['current_step'])
124
	{
125
		// The current weight of this step in terms of overall progress.
126
		$incontext['step_weight'] = $step[3];
127
		// Make sure we reset the skip button.
128
		$incontext['skip'] = false;
129
130
		// Call the step and if it returns false that means pause!
131
		if (function_exists($step[2]) && $step[2]() === false)
132
			break;
133
		elseif (function_exists($step[2]))
134
			$incontext['current_step']++;
135
136
		// No warnings pass on.
137
		$incontext['warning'] = '';
138
	}
139
	$incontext['overall_percent'] += $step[3];
140
}
141
142
// Actually do the template stuff.
143
installExit();
144
145
function initialize_inputs()
146
{
147
	global $databases;
148
149
	// Just so people using older versions of PHP aren't left in the cold.
150
	if (!isset($_SERVER['PHP_SELF']))
151
		$_SERVER['PHP_SELF'] = isset($GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']) ? $GLOBALS['HTTP_SERVER_VARS']['PHP_SELF'] : 'install.php';
152
153
	// Enable error reporting for fatal errors.
154
	error_reporting(E_ERROR | E_PARSE);
155
156
	// Fun.  Low PHP version...
157
	if (!isset($_GET))
158
	{
159
		$GLOBALS['_GET']['step'] = 0;
160
		return;
161
	}
162
163
	if (!isset($_GET['obgz']))
164
	{
165
		ob_start();
166
167
		if (ini_get('session.save_handler') == 'user')
168
			@ini_set('session.save_handler', 'files');
169
		if (function_exists('session_start'))
170
			@session_start();
171
	}
172
	else
173
	{
174
		ob_start('ob_gzhandler');
175
176
		if (ini_get('session.save_handler') == 'user')
177
			@ini_set('session.save_handler', 'files');
178
		session_start();
179
180
		if (!headers_sent())
181
			echo '<!DOCTYPE html>
182
<html>
183
	<head>
184
		<title>', htmlspecialchars($_GET['pass_string']), '</title>
185
	</head>
186
	<body style="background-color: #d4d4d4; margin-top: 16%; text-align: center; font-size: 16pt;">
187
		<strong>', htmlspecialchars($_GET['pass_string']), '</strong>
188
	</body>
189
</html>';
190
		exit;
191
	}
192
193
	// Add slashes, as long as they aren't already being added.
194
	if (!function_exists('get_magic_quotes_gpc') || @get_magic_quotes_gpc() == 0)
195
		foreach ($_POST as $k => $v)
196
			if (strpos($k, 'password') === false && strpos($k, 'db_passwd') === false)
197
				$_POST[$k] = addslashes($v);
198
199
	// This is really quite simple; if ?delete is on the URL, delete the installer...
200
	if (isset($_GET['delete']))
201
	{
202
		if (isset($_SESSION['installer_temp_ftp']))
203
		{
204
			$ftp = new ftp_connection($_SESSION['installer_temp_ftp']['server'], $_SESSION['installer_temp_ftp']['port'], $_SESSION['installer_temp_ftp']['username'], $_SESSION['installer_temp_ftp']['password']);
205
			$ftp->chdir($_SESSION['installer_temp_ftp']['path']);
206
207
			$ftp->unlink('install.php');
208
209
			foreach ($databases as $key => $dummy)
210
			{
211
				$type = ($key == 'mysqli') ? 'mysql' : $key;
212
				$ftp->unlink('install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
213
			}
214
215
			$ftp->close();
216
217
			unset($_SESSION['installer_temp_ftp']);
218
		}
219
		else
220
		{
221
			@unlink(__FILE__);
222
223
			foreach ($databases as $key => $dummy)
224
			{
225
				$type = ($key == 'mysqli') ? 'mysql' : $key;
226
				@unlink(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
227
			}
228
		}
229
230
		// Now just redirect to a blank.png...
231
		$secure = false;
232
233 View Code Duplication
		if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on')
234
			$secure = true;
235
		elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on')
236
			$secure = true;
237
238
		header('location: http' . ($secure ? 's' : '') . '://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png');
0 ignored issues
show
Security Response Splitting introduced by
'location: http' . ($sec...fault/images/blank.png' can contain request data and is used in response header context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Fetching key HTTP_HOST from $_SERVER
    in other/install.php on line 238

Response Splitting Attacks

Allowing an attacker to set a response header, opens your application to response splitting attacks; effectively allowing an attacker to send any response, he would like.

General Strategies to prevent injection

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

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

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

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