Completed
Push — release-2.1 ( e6c696...22bfba )
by Mathias
07:04
created

other/install.php (3 issues)

Upgrade to new PHP Analysis Engine

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

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

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

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

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1273
		{	
1274
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
1275
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
1276
		}
1277
1278
		if (date_default_timezone_set($timezone_id))
1279
			$newSettings[] = array('default_timezone', $timezone_id);
1280
	}
1281
1282
	if (!empty($newSettings))
1283
	{
1284
		$smcFunc['db_insert']('replace',
1285
			'{db_prefix}settings',
1286
			array('variable' => 'string-255', 'value' => 'string-65534'),
1287
			$newSettings,
1288
			array('variable')
1289
		);
1290
	}
1291
1292
	// Let's optimize those new tables, but not on InnoDB, ok?
1293
	if (!$has_innodb)
1294
	{
1295
		db_extend();
1296
		$tables = $smcFunc['db_list_tables']($db_name, $db_prefix . '%');
1297
		foreach ($tables as $table)
1298
		{
1299
			$smcFunc['db_optimize_table']($table) != -1 or $db_messed = true;
1300
1301
			if (!empty($db_messed))
1302
			{
1303
				$incontext['failures'][-1] = $smcFunc['db_error']();
1304
				break;
1305
			}
1306
		}
1307
	}
1308
1309
	// MySQL specific stuff
1310
	if (substr($db_type, 0, 5) != 'mysql')
1311
		return false;
1312
1313
	// Find database user privileges.
1314
	$privs = array();
1315
	$get_privs = $smcFunc['db_query']('', 'SHOW PRIVILEGES', array());
1316
	while ($row = $smcFunc['db_fetch_assoc']($get_privs))
1317
	{
1318
		if ($row['Privilege'] == 'Alter')
1319
			$privs[] = $row['Privilege'];
1320
	}
1321
	$smcFunc['db_free_result']($get_privs);
1322
1323
	// Check for the ALTER privilege.
1324
	if (!empty($databases[$db_type]['alter_support']) && !in_array('Alter', $privs))
1325
	{
1326
		$incontext['error'] = $txt['error_db_alter_priv'];
1327
		return false;
1328
	}
1329
1330
	if (!empty($exists))
1331
	{
1332
		$incontext['page_title'] = $txt['user_refresh_install'];
1333
		$incontext['was_refresh'] = true;
1334
	}
1335
1336
	return false;
1337
}
1338
1339
// Ask for the administrator login information.
1340
function AdminAccount()
1341
{
1342
	global $txt, $db_type, $db_connection, $smcFunc, $incontext, $db_prefix, $db_passwd, $sourcedir, $db_character_set;
1343
1344
	$incontext['sub_template'] = 'admin_account';
1345
	$incontext['page_title'] = $txt['user_settings'];
1346
	$incontext['continue'] = 1;
1347
1348
	// Skipping?
1349
	if (!empty($_POST['skip']))
1350
		return true;
1351
1352
	// Need this to check whether we need the database password.
1353
	require(dirname(__FILE__) . '/Settings.php');
1354
	load_database();
1355
1356
	require_once($sourcedir . '/Subs-Auth.php');
1357
1358
	require_once($sourcedir . '/Subs.php');
1359
1360
	// We need this to properly hash the password for Admin
1361
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' :
1362 View Code Duplication
		function($string){
1363
			global $sourcedir;
1364
			if (function_exists('mb_strtolower'))
1365
				return mb_strtolower($string, 'UTF-8');
1366
			require_once($sourcedir . '/Subs-Charset.php');
1367
			return utf8_strtolower($string);
1368
		};
1369
1370
	if (!isset($_POST['username']))
1371
		$_POST['username'] = '';
1372
	if (!isset($_POST['email']))
1373
		$_POST['email'] = '';
1374
	if (!isset($_POST['server_email']))
1375
		$_POST['server_email'] = '';
1376
1377
	$incontext['username'] = htmlspecialchars(stripslashes($_POST['username']));
1378
	$incontext['email'] = htmlspecialchars(stripslashes($_POST['email']));
1379
	$incontext['server_email'] = htmlspecialchars(stripslashes($_POST['server_email']));
1380
1381
	$incontext['require_db_confirm'] = empty($db_type);
1382
1383
	// Only allow skipping if we think they already have an account setup.
1384
	$request = $smcFunc['db_query']('', '
1385
		SELECT id_member
1386
		FROM {db_prefix}members
1387
		WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
1388
		LIMIT 1',
1389
		array(
1390
			'db_error_skip' => true,
1391
			'admin_group' => 1,
1392
		)
1393
	);
1394
	if ($smcFunc['db_num_rows']($request) != 0)
1395
		$incontext['skip'] = 1;
1396
	$smcFunc['db_free_result']($request);
1397
1398
	// Trying to create an account?
1399
	if (isset($_POST['password1']) && !empty($_POST['contbutt']))
1400
	{
1401
		// Wrong password?
1402
		if ($incontext['require_db_confirm'] && $_POST['password3'] != $db_passwd)
1403
		{
1404
			$incontext['error'] = $txt['error_db_connect'];
1405
			return false;
1406
		}
1407
		// Not matching passwords?
1408
		if ($_POST['password1'] != $_POST['password2'])
1409
		{
1410
			$incontext['error'] = $txt['error_user_settings_again_match'];
1411
			return false;
1412
		}
1413
		// No password?
1414
		if (strlen($_POST['password1']) < 4)
1415
		{
1416
			$incontext['error'] = $txt['error_user_settings_no_password'];
1417
			return false;
1418
		}
1419
		if (!file_exists($sourcedir . '/Subs.php'))
1420
		{
1421
			$incontext['error'] = $txt['error_subs_missing'];
1422
			return false;
1423
		}
1424
1425
		// Update the webmaster's email?
1426
		if (!empty($_POST['server_email']) && (empty($webmaster_email) || $webmaster_email == '[email protected]'))
1427
			updateSettingsFile(array('webmaster_email' => $_POST['server_email']));
1428
1429
		// Work out whether we're going to have dodgy characters and remove them.
1430
		$invalid_characters = preg_match('~[<>&"\'=\\\]~', $_POST['username']) != 0;
1431
		$_POST['username'] = preg_replace('~[<>&"\'=\\\]~', '', $_POST['username']);
1432
1433
		$result = $smcFunc['db_query']('', '
1434
			SELECT id_member, password_salt
1435
			FROM {db_prefix}members
1436
			WHERE member_name = {string:username} OR email_address = {string:email}
1437
			LIMIT 1',
1438
			array(
1439
				'username' => stripslashes($_POST['username']),
1440
				'email' => stripslashes($_POST['email']),
1441
				'db_error_skip' => true,
1442
			)
1443
		);
1444
		if ($smcFunc['db_num_rows']($result) != 0)
1445
		{
1446
			list ($incontext['member_id'], $incontext['member_salt']) = $smcFunc['db_fetch_row']($result);
1447
			$smcFunc['db_free_result']($result);
1448
1449
			$incontext['account_existed'] = $txt['error_user_settings_taken'];
1450
		}
1451
		elseif ($_POST['username'] == '' || strlen($_POST['username']) > 25)
1452
		{
1453
			// Try the previous step again.
1454
			$incontext['error'] = $_POST['username'] == '' ? $txt['error_username_left_empty'] : $txt['error_username_too_long'];
1455
			return false;
1456
		}
1457
		elseif ($invalid_characters || $_POST['username'] == '_' || $_POST['username'] == '|' || strpos($_POST['username'], '[code') !== false || strpos($_POST['username'], '[/code') !== false)
1458
		{
1459
			// Try the previous step again.
1460
			$incontext['error'] = $txt['error_invalid_characters_username'];
1461
			return false;
1462
		}
1463 View Code Duplication
		elseif (empty($_POST['email']) || !filter_var(stripslashes($_POST['email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['email'])) > 255)
1464
		{
1465
			// One step back, this time fill out a proper admin email address.
1466
			$incontext['error'] = sprintf($txt['error_valid_admin_email_needed'], $_POST['username']);
1467
			return false;
1468
		}
1469 View Code Duplication
		elseif (empty($_POST['server_email']) || !filter_var(stripslashes($_POST['server_email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['server_email'])) > 255)
1470
		{
1471
			// One step back, this time fill out a proper admin email address.
1472
			$incontext['error'] = $txt['error_valid_server_email_needed'];
1473
			return false;
1474
		}
1475
		elseif ($_POST['username'] != '')
1476
		{
1477
			$incontext['member_salt'] = substr(md5(mt_rand()), 0, 4);
1478
1479
			// Format the username properly.
1480
			$_POST['username'] = preg_replace('~[\t\n\r\x0B\0\xA0]+~', ' ', $_POST['username']);
1481
			$ip = isset($_SERVER['REMOTE_ADDR']) ? substr($_SERVER['REMOTE_ADDR'], 0, 255) : '';
1482
1483
			$_POST['password1'] = hash_password(stripslashes($_POST['username']), stripslashes($_POST['password1']));
1484
1485
			$request = $smcFunc['db_insert']('',
1486
				$db_prefix . 'members',
1487
				array(
1488
					'member_name' => 'string-25', 'real_name' => 'string-25', 'passwd' => 'string', 'email_address' => 'string',
1489
					'id_group' => 'int', 'posts' => 'int', 'date_registered' => 'int',
1490
					'password_salt' => 'string', 'lngfile' => 'string', 'personal_text' => 'string', 'avatar' => 'string',
1491
					'member_ip' => 'inet', 'member_ip2' => 'inet', 'buddy_list' => 'string', 'pm_ignore_list' => 'string',
1492
					'website_title' => 'string', 'website_url' => 'string',
1493
					'signature' => 'string', 'usertitle' => 'string', 'secret_question' => 'string',
1494
					'additional_groups' => 'string', 'ignore_boards' => 'string',
1495
				),
1496
				array(
1497
					stripslashes($_POST['username']), stripslashes($_POST['username']), $_POST['password1'], stripslashes($_POST['email']),
1498
					1, 0, time(),
1499
					$incontext['member_salt'], '', '', '',
1500
					$ip, $ip, '', '',
1501
					'', '',
1502
					'', '', '',
1503
					'', '',
1504
				),
1505
				array('id_member')
1506
			);
1507
1508
			// Awww, crud!
1509
			if ($request === false)
1510
			{
1511
				$incontext['error'] = $txt['error_user_settings_query'] . '<br>
1512
				<div style="margin: 2ex;">' . nl2br(htmlspecialchars($smcFunc['db_error']($db_connection))) . '</div>';
1513
				return false;
1514
			}
1515
1516
			$incontext['member_id'] = $smcFunc['db_insert_id']("{$db_prefix}members", 'id_member');
1517
		}
1518
1519
		// If we're here we're good.
1520
		return true;
1521
	}
1522
1523
	return false;
1524
}
1525
1526
// Final step, clean up and a complete message!
1527
function DeleteInstall()
1528
{
1529
	global $txt, $incontext;
1530
	global $smcFunc, $db_character_set, $context, $cookiename;
1531
	global $current_smf_version, $databases, $sourcedir, $forum_version, $modSettings, $user_info, $db_type, $boardurl;
1532
1533
	$incontext['page_title'] = $txt['congratulations'];
1534
	$incontext['sub_template'] = 'delete_install';
1535
	$incontext['continue'] = 0;
1536
1537
	require(dirname(__FILE__) . '/Settings.php');
1538
	load_database();
1539
1540
	chdir(dirname(__FILE__));
1541
1542
	require_once($sourcedir . '/Errors.php');
1543
	require_once($sourcedir . '/Logging.php');
1544
	require_once($sourcedir . '/Subs.php');
1545
	require_once($sourcedir . '/Load.php');
1546
	require_once($sourcedir . '/Security.php');
1547
	require_once($sourcedir . '/Subs-Auth.php');
1548
1549
	// Bring a warning over.
1550
	if (!empty($incontext['account_existed']))
1551
		$incontext['warning'] = $incontext['account_existed'];
1552
1553 View Code Duplication
	if (!empty($db_character_set) && !empty($databases[$db_type]['utf8_support']))
1554
		$smcFunc['db_query']('', '
1555
			SET NAMES {string:db_character_set}',
1556
			array(
1557
				'db_character_set' => $db_character_set,
1558
				'db_error_skip' => true,
1559
			)
1560
		);
1561
1562
	// As track stats is by default enabled let's add some activity.
1563
	$smcFunc['db_insert']('ignore',
1564
		'{db_prefix}log_activity',
1565
		array('date' => 'date', 'topics' => 'int', 'posts' => 'int', 'registers' => 'int'),
1566
		array(strftime('%Y-%m-%d', time()), 1, 1, (!empty($incontext['member_id']) ? 1 : 0)),
1567
		array('date')
1568
	);
1569
1570
	// We're going to want our lovely $modSettings now.
1571
	$request = $smcFunc['db_query']('', '
1572
		SELECT variable, value
1573
		FROM {db_prefix}settings',
1574
		array(
1575
			'db_error_skip' => true,
1576
		)
1577
	);
1578
	// Only proceed if we can load the data.
1579
	if ($request)
1580
	{
1581 View Code Duplication
		while ($row = $smcFunc['db_fetch_row']($request))
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1582
			$modSettings[$row[0]] = $row[1];
1583
		$smcFunc['db_free_result']($request);
1584
	}
1585
1586
	// Automatically log them in ;)
1587
	if (isset($incontext['member_id']) && isset($incontext['member_salt']))
1588
		setLoginCookie(3153600 * 60, $incontext['member_id'], hash_salt($_POST['password1'], $incontext['member_salt']));
1589
1590
	$result = $smcFunc['db_query']('', '
1591
		SELECT value
1592
		FROM {db_prefix}settings
1593
		WHERE variable = {string:db_sessions}',
1594
		array(
1595
			'db_sessions' => 'databaseSession_enable',
1596
			'db_error_skip' => true,
1597
		)
1598
	);
1599 View Code Duplication
	if ($smcFunc['db_num_rows']($result) != 0)
1600
		list ($db_sessions) = $smcFunc['db_fetch_row']($result);
1601
	$smcFunc['db_free_result']($result);
1602
1603
	if (empty($db_sessions))
1604
		$_SESSION['admin_time'] = time();
1605
	else
1606
	{
1607
		$_SERVER['HTTP_USER_AGENT'] = substr($_SERVER['HTTP_USER_AGENT'], 0, 211);
1608
1609
		$smcFunc['db_insert']('replace',
1610
			'{db_prefix}sessions',
1611
			array(
1612
				'session_id' => 'string', 'last_update' => 'int', 'data' => 'string',
1613
			),
1614
			array(
1615
				session_id(), time(), 'USER_AGENT|s:' . strlen($_SERVER['HTTP_USER_AGENT']) . ':"' . $_SERVER['HTTP_USER_AGENT'] . '";admin_time|i:' . time() . ';',
1616
			),
1617
			array('session_id')
1618
		);
1619
	}
1620
1621
	updateStats('member');
1622
	updateStats('message');
1623
	updateStats('topic');
1624
1625
	// This function is needed to do the updateStats('subject') call.
1626
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' :
1627 View Code Duplication
		function($string){
1628
			global $sourcedir;
1629
			if (function_exists('mb_strtolower'))
1630
				return mb_strtolower($string, 'UTF-8');
1631
			require_once($sourcedir . '/Subs-Charset.php');
1632
			return utf8_strtolower($string);
1633
		};
1634
1635
	$request = $smcFunc['db_query']('', '
1636
		SELECT id_msg
1637
		FROM {db_prefix}messages
1638
		WHERE id_msg = 1
1639
			AND modified_time = 0
1640
		LIMIT 1',
1641
		array(
1642
			'db_error_skip' => true,
1643
		)
1644
	);
1645
	$context['utf8'] = $db_character_set === 'utf8' || $txt['lang_character_set'] === 'UTF-8';
1646
	if ($smcFunc['db_num_rows']($request) > 0)
1647
		updateStats('subject', 1, htmlspecialchars($txt['default_topic_subject']));
1648
	$smcFunc['db_free_result']($request);
1649
1650
	// Now is the perfect time to fetch the SM files.
1651
	require_once($sourcedir . '/ScheduledTasks.php');
1652
	// Sanity check that they loaded earlier!
1653
	if (isset($modSettings['recycle_board']))
1654
	{
1655
		$forum_version = $current_smf_version;  // The variable is usually defined in index.php so lets just use our variable to do it for us.
1656
		scheduled_fetchSMfiles(); // Now go get those files!
1657
1658
		// We've just installed!
1659
		$user_info['ip'] = $_SERVER['REMOTE_ADDR'];
1660
		$user_info['id'] = isset($incontext['member_id']) ? $incontext['member_id'] : 0;
1661
		logAction('install', array('version' => $forum_version), 'admin');
1662
	}
1663
1664
	// Check if we need some stupid MySQL fix.
1665
	$server_version = $smcFunc['db_server_info']();
1666 View Code Duplication
	if (($db_type == 'mysql' || $db_type == 'mysqli') && in_array(substr($server_version, 0, 6), array('5.0.50', '5.0.51')))
1667
		updateSettings(array('db_mysql_group_by_fix' => '1'));
1668
1669
	// Some final context for the template.
1670
	$incontext['dir_still_writable'] = is_writable(dirname(__FILE__)) && substr(__FILE__, 1, 2) != ':\\';
1671
	$incontext['probably_delete_install'] = isset($_SESSION['installer_temp_ftp']) || is_writable(dirname(__FILE__)) || is_writable(__FILE__);
1672
1673
	// Update hash's cost to an appropriate setting
1674
	updateSettings(array(
1675
		'bcrypt_hash_cost' => hash_benchmark(),
1676
	));
1677
1678
	return false;
1679
}
1680
1681
function updateSettingsFile($vars)
1682
{
1683
	// Modify Settings.php.
1684
	$settingsArray = file(dirname(__FILE__) . '/Settings.php');
1685
1686
	// @todo Do we just want to read the file in clean, and split it this way always?
1687
	if (count($settingsArray) == 1)
1688
		$settingsArray = preg_split('~[\r\n]~', $settingsArray[0]);
1689
1690
	for ($i = 0, $n = count($settingsArray); $i < $n; $i++)
1691
	{
1692
		// Remove the redirect...
1693
		if (trim($settingsArray[$i]) == 'if (file_exists(dirname(__FILE__) . \'/install.php\'))' && trim($settingsArray[$i + 1]) == '{' && trim($settingsArray[$i + 3]) == '}')
1694
		{
1695
			// Get the four lines to nothing.
1696
			$settingsArray[$i] = '';
1697
			$settingsArray[++$i] = '';
1698
			$settingsArray[++$i] = '';
1699
			$settingsArray[++$i] = '';
1700
			continue;
1701
		}
1702
1703
		if (trim($settingsArray[$i]) == '?' . '>')
1704
			$settingsArray[$i] = '';
1705
1706
		// Don't trim or bother with it if it's not a variable.
1707
		if (substr($settingsArray[$i], 0, 1) != '$')
1708
			continue;
1709
1710
		$settingsArray[$i] = rtrim($settingsArray[$i]) . "\n";
1711
1712
		foreach ($vars as $var => $val)
1713 View Code Duplication
			if (strncasecmp($settingsArray[$i], '$' . $var, 1 + strlen($var)) == 0)
1714
			{
1715
				$comment = strstr($settingsArray[$i], '#');
1716
				$settingsArray[$i] = '$' . $var . ' = \'' . $val . '\';' . ($comment != '' ? "\t\t" . $comment : "\n");
1717
				unset($vars[$var]);
1718
			}
1719
	}
1720
1721
	// Uh oh... the file wasn't empty... was it?
1722 View Code Duplication
	if (!empty($vars))
1723
	{
1724
		$settingsArray[$i++] = '';
1725
		foreach ($vars as $var => $val)
1726
			$settingsArray[$i++] = '$' . $var . ' = \'' . $val . '\';' . "\n";
1727
	}
1728
1729
	// Blank out the file - done to fix a oddity with some servers.
1730
	$fp = @fopen(dirname(__FILE__) . '/Settings.php', 'w');
1731
	if (!$fp)
1732
		return false;
1733
	fclose($fp);
1734
1735
	$fp = fopen(dirname(__FILE__) . '/Settings.php', 'r+');
1736
1737
	// Gotta have one of these ;)
1738
	if (trim($settingsArray[0]) != '<?php')
1739
		fwrite($fp, "<?php\n");
1740
1741
	$lines = count($settingsArray);
1742
	for ($i = 0; $i < $lines - 1; $i++)
1743
	{
1744
		// Don't just write a bunch of blank lines.
1745
		if ($settingsArray[$i] != '' || @$settingsArray[$i - 1] != '')
1746
			fwrite($fp, strtr($settingsArray[$i], "\r", ''));
1747
	}
1748
	fwrite($fp, $settingsArray[$i] . '?' . '>');
1749
	fclose($fp);
1750
1751
	// Even though on normal installations the filemtime should prevent this being used by the installer incorrectly
1752
	// it seems that there are times it might not. So let's MAKE it dump the cache.
1753
	if (function_exists('opcache_invalidate'))
1754
		opcache_invalidate(dirname(__FILE__) . '/Settings.php', true);
1755
1756
	return true;
1757
}
1758
1759
function updateDbLastError()
1760
{
1761
	// Write out the db_last_error file with the error timestamp
1762
	file_put_contents(dirname(__FILE__) . '/db_last_error.php', '<' . '?' . "php\n" . '$db_last_error = 0;' . "\n" . '?' . '>');
1763
1764
	return true;
1765
}
1766
1767
// Create an .htaccess file to prevent mod_security. SMF has filtering built-in.
1768
function fixModSecurity()
1769
{
1770
	$htaccess_addition = '
1771
<IfModule mod_security.c>
1772
	# Turn off mod_security filtering.  SMF is a big boy, it doesn\'t need its hands held.
1773
	SecFilterEngine Off
1774
1775
	# The below probably isn\'t needed, but better safe than sorry.
1776
	SecFilterScanPOST Off
1777
</IfModule>';
1778
1779
	if (!function_exists('apache_get_modules') || !in_array('mod_security', apache_get_modules()))
1780
		return true;
1781
	elseif (file_exists(dirname(__FILE__) . '/.htaccess') && is_writable(dirname(__FILE__) . '/.htaccess'))
1782
	{
1783
		$current_htaccess = implode('', file(dirname(__FILE__) . '/.htaccess'));
1784
1785
		// Only change something if mod_security hasn't been addressed yet.
1786
		if (strpos($current_htaccess, '<IfModule mod_security.c>') === false)
1787
		{
1788 View Code Duplication
			if ($ht_handle = fopen(dirname(__FILE__) . '/.htaccess', 'a'))
1789
			{
1790
				fwrite($ht_handle, $htaccess_addition);
1791
				fclose($ht_handle);
1792
				return true;
1793
			}
1794
			else
1795
				return false;
1796
		}
1797
		else
1798
			return true;
1799
	}
1800
	elseif (file_exists(dirname(__FILE__) . '/.htaccess'))
1801
		return strpos(implode('', file(dirname(__FILE__) . '/.htaccess')), '<IfModule mod_security.c>') !== false;
1802
	elseif (is_writable(dirname(__FILE__)))
1803
	{
1804 View Code Duplication
		if ($ht_handle = fopen(dirname(__FILE__) . '/.htaccess', 'w'))
1805
		{
1806
			fwrite($ht_handle, $htaccess_addition);
1807
			fclose($ht_handle);
1808
			return true;
1809
		}
1810
		else
1811
			return false;
1812
	}
1813
	else
1814
		return false;
1815
}
1816
1817
function template_install_above()
1818
{
1819
	global $incontext, $txt, $installurl;
1820
1821
	echo '<!DOCTYPE html>
1822
<html', $txt['lang_rtl'] == true ? ' dir="rtl"' : '', '>
1823
	<head>
1824
		<meta charset="', isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8', '">
1825
		<meta name="robots" content="noindex">
1826
		<title>', $txt['smf_installer'], '</title>
1827
		<link rel="stylesheet" href="Themes/default/css/index.css?alp21">
1828
		<link rel="stylesheet" href="Themes/default/css/install.css?alp21">
1829
		', $txt['lang_rtl'] == true ? '<link rel="stylesheet" href="Themes/default/css/rtl.css?alp21">' : '' , '
1830
1831
		<script src="Themes/default/scripts/jquery-2.1.4.min.js"></script>
1832
		<script src="Themes/default/scripts/script.js"></script>
1833
	</head>
1834
	<body><div id="footerfix">
1835
		<div id="header">
1836
			<h1 class="forumtitle">', $txt['smf_installer'], '</h1>
1837
			<img id="smflogo" src="Themes/default/images/smflogo.png" alt="Simple Machines Forum" title="Simple Machines Forum">
1838
		</div>
1839
		<div id="wrapper">
1840
			<div id="upper_section">
1841
				<div id="inner_section">
1842
					<div id="inner_wrap">';
1843
1844
	// Have we got a language drop down - if so do it on the first step only.
1845
	if (!empty($incontext['detected_languages']) && count($incontext['detected_languages']) > 1 && $incontext['current_step'] == 0)
1846
	{
1847
		echo '
1848
						<div class="news">
1849
							<form action="', $installurl, '" method="get">
1850
								<label for="installer_language">', $txt['installer_language'], ':</label>
1851
								<select id="installer_language" name="lang_file" onchange="location.href = \'', $installurl, '?lang_file=\' + this.options[this.selectedIndex].value;">';
1852
1853
		foreach ($incontext['detected_languages'] as $lang => $name)
1854
			echo '
1855
									<option', isset($_SESSION['installer_temp_lang']) && $_SESSION['installer_temp_lang'] == $lang ? ' selected' : '', ' value="', $lang, '">', $name, '</option>';
1856
1857
		echo '
1858
								</select>
1859
								<noscript><input type="submit" value="', $txt['installer_language_set'], '" class="button_submit" /></noscript>
1860
							</form>
1861
						</div>
1862
						<hr class="clear" />';
1863
	}
1864
1865
	echo '
1866
					</div>
1867
				</div>
1868
			</div>
1869
			<div id="content_section">
1870
				<div id="main_content_section">
1871
					<div id="main_steps">
1872
						<h2>', $txt['upgrade_progress'], '</h2>
1873
						<ul>';
1874
1875 View Code Duplication
	foreach ($incontext['steps'] as $num => $step)
1876
		echo '
1877
							<li class="', $num < $incontext['current_step'] ? 'stepdone' : ($num == $incontext['current_step'] ? 'stepcurrent' : 'stepwaiting'), '">', $txt['upgrade_step'], ' ', $step[0], ': ', $step[1], '</li>';
1878
1879
	echo '
1880
						</ul>
1881
					</div>
1882
					<div id="progress_bar">
1883
						<div id="overall_text">', $incontext['overall_percent'], '%</div>
1884
						<div id="overall_progress" style="width: ', $incontext['overall_percent'], '%;">
1885
							<span>'. $txt['upgrade_overall_progress'], '</span>
1886
						</div>
1887
					</div>
1888
					<div id="main_screen" class="clear">
1889
						<h2>', $incontext['page_title'], '</h2>
1890
						<div class="panel">';
1891
}
1892
1893
function template_install_below()
1894
{
1895
	global $incontext, $txt;
1896
1897
	if (!empty($incontext['continue']) || !empty($incontext['skip']))
1898
	{
1899
		echo '
1900
								<div>';
1901
1902
		if (!empty($incontext['continue']))
1903
			echo '
1904
									<input type="submit" id="contbutt" name="contbutt" value="', $txt['upgrade_continue'], '" onclick="return submitThisOnce(this);" class="button_submit" />';
1905
		if (!empty($incontext['skip']))
1906
			echo '
1907
									<input type="submit" id="skip" name="skip" value="', $txt['upgrade_skip'], '" onclick="return submitThisOnce(this);" class="button_submit" />';
1908
		echo '
1909
								</div>';
1910
	}
1911
1912
	// Show the closing form tag and other data only if not in the last step
1913
	if (count($incontext['steps']) - 1 !== (int) $incontext['current_step'])
1914
		echo '
1915
							</form>';
1916
1917
	echo '
1918
						</div>
1919
					</div>
1920
				</div>
1921
			</div>
1922
		</div></div>
1923
		<div id="footer">
1924
			<ul>
1925
				<li class="copyright"><a href="http://www.simplemachines.org/" title="Simple Machines Forum" target="_blank" class="new_win">SMF &copy; 2016, Simple Machines</a></li>
1926
			</ul>
1927
		</div>
1928
	</body>
1929
</html>';
1930
}
1931
1932
// Welcome them to the wonderful world of SMF!
1933
function template_welcome_message()
1934
{
1935
	global $incontext, $txt;
1936
1937
	echo '
1938
	<script src="http://www.simplemachines.org/smf/current-version.js?version=' . $GLOBALS['current_smf_version'] . '"></script>
1939
	<form action="', $incontext['form_url'], '" method="post">
1940
		<p>', sprintf($txt['install_welcome_desc'], $GLOBALS['current_smf_version']), '</p>
1941
		<div id="version_warning" style="margin: 2ex; padding: 2ex; border: 2px dashed #a92174; color: black; background-color: #fbbbe2; display: none;">
1942
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
1943
			<strong style="text-decoration: underline;">', $txt['error_warning_notice'], '</strong><br>
1944
			<div style="padding-left: 6ex;">
1945
				', 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>'), '
1946
			</div>
1947
		</div>';
1948
1949
	// Show the warnings, or not.
1950
	if (template_warning_divs())
1951
		echo '
1952
		<h3>', $txt['install_all_lovely'], '</h3>';
1953
1954
	// Say we want the continue button!
1955
	if (empty($incontext['error']))
1956
		$incontext['continue'] = 1;
1957
1958
	// For the latest version stuff.
1959
	echo '
1960
		<script>
1961
			// Latest version?
1962
			function smfCurrentVersion()
1963
			{
1964
				var smfVer, yourVer;
1965
1966
				if (!(\'smfVersion\' in window))
1967
					return;
1968
1969
				window.smfVersion = window.smfVersion.replace(/SMF\s?/g, \'\');
1970
1971
				smfVer = document.getElementById("smfVersion");
1972
				yourVer = document.getElementById("yourVersion");
1973
1974
				setInnerHTML(smfVer, window.smfVersion);
1975
1976
				var currentVersion = getInnerHTML(yourVer);
1977
				if (currentVersion < window.smfVersion)
1978
					document.getElementById(\'version_warning\').style.display = \'\';
1979
			}
1980
			addLoadEvent(smfCurrentVersion);
1981
		</script>';
1982
}
1983
1984
// A shortcut for any warning stuff.
1985
function template_warning_divs()
1986
{
1987
	global $txt, $incontext;
1988
1989
	// Errors are very serious..
1990
	if (!empty($incontext['error']))
1991
		echo '
1992
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
1993
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
1994
			<strong style="text-decoration: underline;">', $txt['upgrade_critical_error'], '</strong><br>
1995
			<div style="padding-left: 6ex;">
1996
				', $incontext['error'], '
1997
			</div>
1998
		</div>';
1999
	// A warning message?
2000
	elseif (!empty($incontext['warning']))
2001
		echo '
2002
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
2003
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
2004
			<strong style="text-decoration: underline;">', $txt['upgrade_warning'], '</strong><br>
2005
			<div style="padding-left: 6ex;">
2006
				', $incontext['warning'], '
2007
			</div>
2008
		</div>';
2009
2010
	return empty($incontext['error']) && empty($incontext['warning']);
2011
}
2012
2013
function template_chmod_files()
2014
{
2015
	global $txt, $incontext;
2016
2017
	echo '
2018
		<p>', $txt['ftp_setup_why_info'], '</p>
2019
		<ul style="margin: 2.5ex; font-family: monospace;">
2020
			<li>', implode('</li>
2021
			<li>', $incontext['failed_files']), '</li>
2022
		</ul>';
2023
2024
	if (isset($incontext['systemos'], $incontext['detected_path']) && $incontext['systemos'] == 'linux')
2025
		echo '
2026
		<hr>
2027
		<p>', $txt['chmod_linux_info'], '</p>
2028
		<tt># chmod a+w ', implode(' ' . $incontext['detected_path'] . '/', $incontext['failed_files']), '</tt>';
2029
2030
	// This is serious!
2031
	if (!template_warning_divs())
2032
		return;
2033
2034
	echo '
2035
		<hr>
2036
		<p>', $txt['ftp_setup_info'], '</p>';
2037
2038
	if (!empty($incontext['ftp_errors']))
2039
		echo '
2040
		<div class="error_message">
2041
			', $txt['error_ftp_no_connect'], '<br><br>
2042
			<code>', implode('<br>', $incontext['ftp_errors']), '</code>
2043
		</div>
2044
		<br>';
2045
2046
	echo '
2047
		<form action="', $incontext['form_url'], '" method="post">
2048
			<table align="center" style="width: 520px; margin: 1em 0; padding: 0; border: 0">
2049
				<tr>
2050
					<td width="26%" valign="top" class="textbox"><label for="ftp_server">', $txt['ftp_server'], ':</label></td>
2051
					<td>
2052
						<div style="float: ', $txt['lang_rtl'] == false ? 'right' : 'left', '; margin-', $txt['lang_rtl'] == false ? 'right' : 'left', ': 1px;"><label for="ftp_port" class="textbox"><strong>', $txt['ftp_port'], ':&nbsp;</strong></label> <input type="text" size="3" name="ftp_port" id="ftp_port" value="', $incontext['ftp']['port'], '" class="input_text" /></div>
2053
						<input type="text" size="30" name="ftp_server" id="ftp_server" value="', $incontext['ftp']['server'], '" style="width: 70%;" class="input_text" />
2054
						<div class="smalltext block">', $txt['ftp_server_info'], '</div>
2055
					</td>
2056
				</tr><tr>
2057
					<td width="26%" valign="top" class="textbox"><label for="ftp_username">', $txt['ftp_username'], ':</label></td>
2058
					<td>
2059
						<input type="text" size="50" name="ftp_username" id="ftp_username" value="', $incontext['ftp']['username'], '" style="width: 99%;" class="input_text" />
2060
						<div class="smalltext block">', $txt['ftp_username_info'], '</div>
2061
					</td>
2062
				</tr><tr>
2063
					<td width="26%" valign="top" class="textbox"><label for="ftp_password">', $txt['ftp_password'], ':</label></td>
2064
					<td>
2065
						<input type="password" size="50" name="ftp_password" id="ftp_password" style="width: 99%;" class="input_password" />
2066
						<div class="smalltext block">', $txt['ftp_password_info'], '</div>
2067
					</td>
2068
				</tr><tr>
2069
					<td width="26%" valign="top" class="textbox"><label for="ftp_path">', $txt['ftp_path'], ':</label></td>
2070
					<td style="padding-bottom: 1ex;">
2071
						<input type="text" size="50" name="ftp_path" id="ftp_path" value="', $incontext['ftp']['path'], '" style="width: 99%;" class="input_text" />
2072
						<div class="smalltext block">', $incontext['ftp']['path_msg'], '</div>
2073
					</td>
2074
				</tr>
2075
			</table>
2076
			<div style="margin: 1ex; margin-top: 1ex; text-align: ', $txt['lang_rtl'] == false ? 'right' : 'left', ';"><input type="submit" value="', $txt['ftp_connect'], '" onclick="return submitThisOnce(this);" class="button_submit" /></div>
2077
		</form>
2078
		<a href="', $incontext['form_url'], '">', $txt['error_message_click'], '</a> ', $txt['ftp_setup_again'];
2079
}
2080
2081
// Get the database settings prepared.
2082
function template_database_settings()
2083
{
2084
	global $incontext, $txt;
2085
2086
	echo '
2087
	<form action="', $incontext['form_url'], '" method="post">
2088
		<p>', $txt['db_settings_info'], '</p>';
2089
2090
	template_warning_divs();
2091
2092
	echo '
2093
		<table width="100%" border="0" style="margin: 1em 0;">';
2094
2095
	// More than one database type?
2096
	if (count($incontext['supported_databases']) > 1)
2097
	{
2098
		echo '
2099
			<tr>
2100
				<td width="20%" valign="top" class="textbox"><label for="db_type_input">', $txt['db_settings_type'], ':</label></td>
2101
				<td>
2102
					<select name="db_type" id="db_type_input" onchange="toggleDBInput();">';
2103
2104
	foreach ($incontext['supported_databases'] as $key => $db)
2105
			echo '
2106
						<option value="', $key, '"', isset($_POST['db_type']) && $_POST['db_type'] == $key ? ' selected' : '', '>', $db['name'], '</option>';
2107
2108
	echo '
2109
					</select>
2110
					<div class="smalltext block">', $txt['db_settings_type_info'], '</div>
2111
				</td>
2112
			</tr>';
2113
	}
2114
	else
2115
	{
2116
		echo '
2117
			<tr style="display: none;">
2118
				<td>
2119
					<input type="hidden" name="db_type" value="', $incontext['db']['type'], '" />
2120
				</td>
2121
			</tr>';
2122
	}
2123
2124
	echo '
2125
			<tr id="db_server_contain">
2126
				<td width="20%" valign="top" class="textbox"><label for="db_server_input">', $txt['db_settings_server'], ':</label></td>
2127
				<td>
2128
					<input type="text" name="db_server" id="db_server_input" value="', $incontext['db']['server'], '" size="30" class="input_text" /><br>
2129
					<div class="smalltext block">', $txt['db_settings_server_info'], '</div>
2130
				</td>
2131
			</tr><tr id="db_port_contain">
2132
				<td width="20%" valign="top" class="textbox"><label for="db_port_input">', $txt['db_settings_port'], ':</label></td>
2133
				<td>
2134
					<input type="text" name="db_port" id="db_port_input" value="', $incontext['db']['port'], '"><br>
2135
					<div class="smalltext block">', $txt['db_settings_port_info'], '</div>
2136
				</td>
2137
			</tr><tr id="db_user_contain">
2138
				<td valign="top" class="textbox"><label for="db_user_input">', $txt['db_settings_username'], ':</label></td>
2139
				<td>
2140
					<input type="text" name="db_user" id="db_user_input" value="', $incontext['db']['user'], '" size="30" class="input_text" /><br>
2141
					<div class="smalltext block">', $txt['db_settings_username_info'], '</div>
2142
				</td>
2143
			</tr><tr id="db_passwd_contain">
2144
				<td valign="top" class="textbox"><label for="db_passwd_input">', $txt['db_settings_password'], ':</label></td>
2145
				<td>
2146
					<input type="password" name="db_passwd" id="db_passwd_input" value="', $incontext['db']['pass'], '" size="30" class="input_password" /><br>
2147
					<div class="smalltext block">', $txt['db_settings_password_info'], '</div>
2148
				</td>
2149
			</tr><tr id="db_name_contain">
2150
				<td valign="top" class="textbox"><label for="db_name_input">', $txt['db_settings_database'], ':</label></td>
2151
				<td>
2152
					<input type="text" name="db_name" id="db_name_input" value="', empty($incontext['db']['name']) ? 'smf' : $incontext['db']['name'], '" size="30" class="input_text" /><br>
2153
					<div class="smalltext block">', $txt['db_settings_database_info'], '
2154
					<span id="db_name_info_warning">', $txt['db_settings_database_info_note'], '</span></div>
2155
				</td>
2156
			</tr><tr id="db_filename_contain" style="display: none;">
2157
				<td valign="top" class="textbox"><label for="db_filename_input">', $txt['db_settings_database_file'], ':</label></td>
2158
				<td>
2159
					<input type="text" name="db_filename" id="db_filename_input" value="', empty($incontext['db']['name']) ? dirname(__FILE__) . '/smf_' . substr(md5(microtime()), 0, 10) : stripslashes($incontext['db']['name']), '" size="30" class="input_text" /><br>
2160
					<div class="smalltext block">', $txt['db_settings_database_file_info'], '</div>
2161
				</td>
2162
			</tr><tr>
2163
				<td valign="top" class="textbox"><label for="db_prefix_input">', $txt['db_settings_prefix'], ':</label></td>
2164
				<td>
2165
					<input type="text" name="db_prefix" id="db_prefix_input" value="', $incontext['db']['prefix'], '" size="30" class="input_text" /><br>
2166
					<div class="smalltext block">', $txt['db_settings_prefix_info'], '</div>
2167
				</td>
2168
			</tr>
2169
		</table>';
2170
2171
	// Toggles a warning related to db names in PostgreSQL
2172
	echo '
2173
	<script>
2174
		function toggleDBInput()
2175
		{
2176
			if (document.getElementById(\'db_type_input\').value == \'postgresql\')
2177
				document.getElementById(\'db_name_info_warning\').style.display = \'none\';
2178
			else
2179
				document.getElementById(\'db_name_info_warning\').style.display = \'\';
2180
		}
2181
		toggleDBInput();
2182
	</script>';
2183
}
2184
2185
// Stick in their forum settings.
2186
function template_forum_settings()
2187
{
2188
	global $incontext, $txt;
2189
2190
	echo '
2191
	<form action="', $incontext['form_url'], '" method="post">
2192
		<h3>', $txt['install_settings_info'], '</h3>';
2193
2194
	template_warning_divs();
2195
2196
	echo '
2197
		<table style="width: 100%; margin: 1em 0;">
2198
			<tr>
2199
				<td class="textbox" style="width: 20%; vertical-align: top;">
2200
					<label for="mbname_input">', $txt['install_settings_name'], ':</label>
2201
				</td>
2202
				<td>
2203
					<input type="text" name="mbname" id="mbname_input" value="', $txt['install_settings_name_default'], '" size="65" class="input_text" />
2204
					<div class="smalltext block">', $txt['install_settings_name_info'], '</div>
2205
				</td>
2206
			</tr>
2207
			<tr>
2208
				<td class="textbox" style="vertical-align: top;">
2209
					<label for="boardurl_input">', $txt['install_settings_url'], ':</label>
2210
				</td>
2211
				<td>
2212
					<input type="text" name="boardurl" id="boardurl_input" value="', $incontext['detected_url'], '" size="65" class="input_text" />
2213
					<br>
2214
					<div class="smalltext block">', $txt['install_settings_url_info'], '</div>
2215
				</td>
2216
			</tr>
2217
			<tr>
2218
				<td class="textbox" style="vertical-align: top;">
2219
					<label for="reg_mode">', $txt['install_settings_reg_mode'], ':</label>
2220
				</td>
2221
				<td>
2222
					<select name="reg_mode" id="reg_mode">
2223
						<optgroup label="', $txt['install_settings_reg_modes'], ':">
2224
							<option value="0" selected>', $txt['install_settings_reg_immediate'], '</option>
2225
							<option value="1">', $txt['install_settings_reg_email'], '</option>
2226
							<option value="2">', $txt['install_settings_reg_admin'], '</option>
2227
							<option value="3">', $txt['install_settings_reg_disabled'], '</option>
2228
						</optgroup>
2229
					</select>
2230
					<br>
2231
					<div class="smalltext block">', $txt['install_settings_reg_mode_info'], '</div>
2232
				</td>
2233
			</tr>
2234
			<tr>
2235
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_compress'], ':</td>
2236
				<td>
2237
					<input type="checkbox" name="compress" id="compress_check" checked class="input_check" />&nbsp;
2238
					<label for="compress_check">', $txt['install_settings_compress_title'], '</label>
2239
					<br>
2240
					<div class="smalltext block">', $txt['install_settings_compress_info'], '</div>
2241
				</td>
2242
			</tr>
2243
			<tr>
2244
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_dbsession'], ':</td>
2245
				<td>
2246
					<input type="checkbox" name="dbsession" id="dbsession_check" checked class="input_check" />&nbsp;
2247
					<label for="dbsession_check">', $txt['install_settings_dbsession_title'], '</label>
2248
					<br>
2249
					<div class="smalltext block">', $incontext['test_dbsession'] ? $txt['install_settings_dbsession_info1'] : $txt['install_settings_dbsession_info2'], '</div>
2250
				</td>
2251
			</tr>
2252
			<tr>
2253
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_utf8'], ':</td>
2254
				<td>
2255
					<input type="checkbox" name="utf8" id="utf8_check"', $incontext['utf8_default'] ? ' checked' : '', ' class="input_check"', $incontext['utf8_required'] ? ' disabled' : '', ' />&nbsp;
2256
					<label for="utf8_check">', $txt['install_settings_utf8_title'], '</label>
2257
					<br>
2258
					<div class="smalltext block">', $txt['install_settings_utf8_info'], '</div>
2259
				</td>
2260
			</tr>
2261
			<tr>
2262
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_stats'], ':</td>
2263
				<td>
2264
					<input type="checkbox" name="stats" id="stats_check" class="input_check" />&nbsp;
2265
					<label for="stats_check">', $txt['install_settings_stats_title'], '</label>
2266
					<br>
2267
					<div class="smalltext block">', $txt['install_settings_stats_info'], '</div>
2268
				</td>
2269
			</tr>
2270
			<tr>
2271
				<td class="textbox" style="vertical-align: top;">', $txt['force_ssl'], ':</td>
2272
				<td>
2273
					<input type="checkbox" name="force_ssl" id="force_ssl" class="input_check" />&nbsp;
2274
					<label for="force_ssl">', $txt['force_ssl_label'], '</label>
2275
					<br>
2276
					<div class="smalltext block">', $txt['force_ssl_info'], '</div>
2277
				</td>
2278
			</tr>
2279
		</table>
2280
	';
2281
}
2282
2283
// Show results of the database population.
2284
function template_populate_database()
2285
{
2286
	global $incontext, $txt;
2287
2288
	echo '
2289
	<form action="', $incontext['form_url'], '" method="post">
2290
		<p>', !empty($incontext['was_refresh']) ? $txt['user_refresh_install_desc'] : $txt['db_populate_info'], '</p>';
2291
2292
	if (!empty($incontext['sql_results']))
2293
	{
2294
		echo '
2295
		<ul>
2296
			<li>', implode('</li><li>', $incontext['sql_results']), '</li>
2297
		</ul>';
2298
	}
2299
2300
	if (!empty($incontext['failures']))
2301
	{
2302
		echo '
2303
				<div style="color: red;">', $txt['error_db_queries'], '</div>
2304
				<ul>';
2305
2306
		foreach ($incontext['failures'] as $line => $fail)
2307
			echo '
2308
						<li><strong>', $txt['error_db_queries_line'], $line + 1, ':</strong> ', nl2br(htmlspecialchars($fail)), '</li>';
2309
2310
		echo '
2311
				</ul>';
2312
	}
2313
2314
	echo '
2315
		<p>', $txt['db_populate_info2'], '</p>';
2316
2317
	template_warning_divs();
2318
2319
	echo '
2320
	<input type="hidden" name="pop_done" value="1" />';
2321
}
2322
2323
// Create the admin account.
2324
function template_admin_account()
2325
{
2326
	global $incontext, $txt;
2327
2328
	echo '
2329
	<form action="', $incontext['form_url'], '" method="post">
2330
		<p>', $txt['user_settings_info'], '</p>';
2331
2332
	template_warning_divs();
2333
2334
	echo '
2335
		<table width="100%" border="0" style="margin: 2em 0;">
2336
			<tr>
2337
				<td width="18%" valign="top" class="textbox"><label for="username">', $txt['user_settings_username'], ':</label></td>
2338
				<td>
2339
					<input type="text" name="username" id="username" value="', $incontext['username'], '" size="40" class="input_text" />
2340
					<div class="smalltext block">', $txt['user_settings_username_info'], '</div>
2341
				</td>
2342
			</tr><tr>
2343
				<td valign="top" class="textbox"><label for="password1">', $txt['user_settings_password'], ':</label></td>
2344
				<td>
2345
					<input type="password" name="password1" id="password1" size="40" class="input_password" />
2346
					<div class="smalltext block">', $txt['user_settings_password_info'], '</div>
2347
				</td>
2348
			</tr><tr>
2349
				<td valign="top" class="textbox"><label for="password2">', $txt['user_settings_again'], ':</label></td>
2350
				<td>
2351
					<input type="password" name="password2" id="password2" size="40" class="input_password" />
2352
					<div class="smalltext block">', $txt['user_settings_again_info'], '</div>
2353
				</td>
2354
			</tr><tr>
2355
				<td valign="top" class="textbox"><label for="email">', $txt['user_settings_admin_email'], ':</label></td>
2356
				<td>
2357
					<input type="text" name="email" id="email" value="', $incontext['email'], '" size="40" class="input_text" />
2358
					<div class="smalltext block">', $txt['user_settings_admin_email_info'], '</div>
2359
				</td>
2360
			</tr><tr>
2361
				<td valign="top" class="textbox"><label for="server_email">', $txt['user_settings_server_email'], ':</label></td>
2362
				<td>
2363
					<input type="text" name="server_email" id="server_email" value="', $incontext['server_email'], '" size="40" class="input_text" />
2364
					<div class="smalltext block">', $txt['user_settings_server_email_info'], '</div>
2365
				</td>
2366
			</tr>
2367
		</table>';
2368
2369
	if ($incontext['require_db_confirm'])
2370
		echo '
2371
		<h2>', $txt['user_settings_database'], '</h2>
2372
		<p>', $txt['user_settings_database_info'], '</p>
2373
2374
		<div style="margin-bottom: 2ex; padding-', $txt['lang_rtl'] == false ? 'left' : 'right', ': 50px;">
2375
			<input type="password" name="password3" size="30" class="input_password" />
2376
		</div>';
2377
}
2378
2379
// Tell them it's done, and to delete.
2380
function template_delete_install()
2381
{
2382
	global $incontext, $installurl, $txt, $boardurl;
2383
2384
	echo '
2385
		<p>', $txt['congratulations_help'], '</p>';
2386
2387
	template_warning_divs();
2388
2389
	// Install directory still writable?
2390
	if ($incontext['dir_still_writable'])
2391
		echo '
2392
		<em>', $txt['still_writable'], '</em><br>
2393
		<br>';
2394
2395
	// Don't show the box if it's like 99% sure it won't work :P.
2396
	if ($incontext['probably_delete_install'])
2397
		echo '
2398
		<div style="margin: 1ex; font-weight: bold;">
2399
			<label for="delete_self"><input type="checkbox" id="delete_self" onclick="doTheDelete();" class="input_check" /> ', $txt['delete_installer'], !isset($_SESSION['installer_temp_ftp']) ? ' ' . $txt['delete_installer_maybe'] : '', '</label>
2400
		</div>
2401
		<script>
2402
			function doTheDelete()
2403
			{
2404
				var theCheck = document.getElementById ? document.getElementById("delete_self") : document.all.delete_self;
2405
				var tempImage = new Image();
2406
2407
				tempImage.src = "', $installurl, '?delete=1&ts_" + (new Date().getTime());
2408
				tempImage.width = 0;
2409
				theCheck.disabled = true;
2410
			}
2411
		</script>
2412
		<br>';
2413
2414
	echo '
2415
		', sprintf($txt['go_to_your_forum'], $boardurl . '/index.php'), '<br>
2416
		<br>
2417
		', $txt['good_luck'];
2418
}
2419
2420
?>
2421