Completed
Push — release-2.1 ( aa21c4...7040ad )
by Mathias
09:20
created

other/install.php (53 issues)

Upgrade to new PHP Analysis Engine

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
227
			}
228
		}
229
230
		// Now just redirect to a blank.png...
231
		header('Location: http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png');
232
		exit;
233
	}
234
235
	// PHP 5 might cry if we don't do this now.
236
	if (function_exists('date_default_timezone_set'))
237
	{
238
		// Get PHP's default timezone, if set
239
		$ini_tz = ini_get('date.timezone');
240
		if (!empty($ini_tz))
241
			$timezone_id = $ini_tz;
242
		else
243
			$timezone_id = '';
244
245
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
246 View Code Duplication
		if (!in_array($timezone_id, timezone_identifiers_list()))
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...
247
		{
248
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
249
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
250
		}
251
252
		date_default_timezone_set($timezone_id);
253
	}
254
255
	// Force an integer step, defaulting to 0.
256
	$_GET['step'] = (int) @$_GET['step'];
257
}
258
259
// Load the list of language files, and the current language file.
260
function load_lang_file()
261
{
262
	global $txt, $incontext;
263
264
	$incontext['detected_languages'] = array();
265
266
	// Make sure the languages directory actually exists.
267
	if (file_exists(dirname(__FILE__) . '/Themes/default/languages'))
268
	{
269
		// Find all the "Install" language files in the directory.
270
		$dir = dir(dirname(__FILE__) . '/Themes/default/languages');
271
		while ($entry = $dir->read())
272
		{
273
			if (substr($entry, 0, 8) == 'Install.' && substr($entry, -4) == '.php')
274
				$incontext['detected_languages'][$entry] = ucfirst(substr($entry, 8, strlen($entry) - 12));
275
		}
276
		$dir->close();
277
	}
278
279
	// Didn't find any, show an error message!
280
	if (empty($incontext['detected_languages']))
281
	{
282
		// Let's not cache this message, eh?
283
		header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
284
		header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
285
		header('Cache-Control: no-cache');
286
287
		echo '<!DOCTYPE html>
288
<html>
289
	<head>
290
		<title>SMF Installer: Error!</title>
291
	</head>
292
	<body style="font-family: sans-serif;"><div style="width: 600px;">
293
		<h1 style="font-size: 14pt;">A critical error has occurred.</h1>
294
295
		<p>This installer was unable to find the installer\'s language file or files.  They should be found under:</p>
296
297
		<div style="margin: 1ex; font-family: monospace; font-weight: bold;">', dirname($_SERVER['PHP_SELF']) != '/' ? dirname($_SERVER['PHP_SELF']) : '', '/Themes/default/languages</div>
298
299
		<p>In some cases, FTP clients do not properly upload files with this many folders.  Please double check to make sure you <span style="font-weight: 600;">have uploaded all the files in the distribution</span>.</p>
300
		<p>If that doesn\'t help, please make sure this install.php file is in the same place as the Themes folder.</p>
301
302
		<p>If you continue to get this error message, feel free to <a href="https://support.simplemachines.org/">look to us for support</a>.</p>
303
	</div></body>
304
</html>';
305
		die;
306
	}
307
308
	// Override the language file?
309
	if (isset($_GET['lang_file']))
310
		$_SESSION['installer_temp_lang'] = $_GET['lang_file'];
311
	elseif (isset($GLOBALS['HTTP_GET_VARS']['lang_file']))
312
		$_SESSION['installer_temp_lang'] = $GLOBALS['HTTP_GET_VARS']['lang_file'];
313
314
	// Make sure it exists, if it doesn't reset it.
315
	if (!isset($_SESSION['installer_temp_lang']) || preg_match('~[^\\w_\\-.]~', $_SESSION['installer_temp_lang']) === 1 || !file_exists(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']))
316
	{
317
		// Use the first one...
318
		list ($_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
319
320
		// If we have english and some other language, use the other language.  We Americans hate english :P.
321
		if ($_SESSION['installer_temp_lang'] == 'Install.english.php' && count($incontext['detected_languages']) > 1)
322
			list (, $_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
323
	}
324
325
	// And now include the actual language file itself.
326
	require_once(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']);
327
}
328
329
// This handy function loads some settings and the like.
330
function load_database()
331
{
332
	global $db_prefix, $db_connection, $sourcedir, $smcFunc, $modSettings;
333
	global $db_server, $db_passwd, $db_type, $db_name, $db_user, $db_persist;
334
335
	if (empty($sourcedir))
336
		$sourcedir = dirname(__FILE__) . '/Sources';
337
338
	// Need this to check whether we need the database password.
339
	require(dirname(__FILE__) . '/Settings.php');
340
	if (!defined('SMF'))
341
		define('SMF', 1);
342
	if (empty($smcFunc))
343
		$smcFunc = array();
344
345
	$modSettings['disableQueryCheck'] = true;
346
347
	// Connect the database.
348
	if (!$db_connection)
349
	{
350
		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
351
		if (version_compare(PHP_VERSION, '5', '<'))
352
			require_once($sourcedir . '/Subs-Compat.php');
353
354
		$db_options = array('persist' => $db_persist);
355
		$port = '';
356
357
		// Figure out the port...
358
		if (!empty($_POST['db_port']))
359
		{
360
			if ($db_type == 'mysql')
361
			{
362
				$port = ((int) $_POST['db_port'] == ini_get($db_type . 'default_port')) ? '' : (int) $_POST['db_port'];
363
			}
364 View Code Duplication
			elseif ($db_type == 'postgresql')
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...
365
			{
366
				// PostgreSQL doesn't have a default port setting in php.ini, so just check against the default
367
				$port = ((int) $_POST['db_port'] == 5432) ? '' : (int) $_POST['db_port'];
368
			}
369
		}
370
371
		if (!empty($port))
372
			$db_options['port'] = $port;
373
374
		if (!$db_connection)
375
			$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options);
376
	}
377
}
378
379
// This is called upon exiting the installer, for template etc.
380
function installExit($fallThrough = false)
381
{
382
	global $incontext, $installurl, $txt;
383
384
	// Send character set.
385
	header('Content-Type: text/html; charset=' . (isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8'));
386
387
	// We usually dump our templates out.
388
	if (!$fallThrough)
389
	{
390
		// The top install bit.
391
		template_install_above();
392
393
		// Call the template.
394
		if (isset($incontext['sub_template']))
395
		{
396
			$incontext['form_url'] = $installurl . '?step=' . $incontext['current_step'];
397
398
			call_user_func('template_' . $incontext['sub_template']);
399
		}
400
		// @todo REMOVE THIS!!
401
		else
402
		{
403
			if (function_exists('doStep' . $_GET['step']))
404
				call_user_func('doStep' . $_GET['step']);
405
		}
406
		// Show the footer.
407
		template_install_below();
408
	}
409
410
	// Bang - gone!
411
	die();
412
}
413
414
function Welcome()
415
{
416
	global $incontext, $txt, $databases, $installurl;
417
418
	$incontext['page_title'] = $txt['install_welcome'];
419
	$incontext['sub_template'] = 'welcome_message';
420
421
	// Done the submission?
422
	if (isset($_POST['contbutt']))
423
		return true;
424
425
	// See if we think they have already installed it?
426
	if (is_readable(dirname(__FILE__) . '/Settings.php'))
427
	{
428
		$probably_installed = 0;
429
		foreach (file(dirname(__FILE__) . '/Settings.php') as $line)
430
		{
431
			if (preg_match('~^\$db_passwd\s=\s\'([^\']+)\';$~', $line))
432
				$probably_installed++;
433
			if (preg_match('~^\$boardurl\s=\s\'([^\']+)\';~', $line) && !preg_match('~^\$boardurl\s=\s\'http://127\.0\.0\.1/smf\';~', $line))
434
				$probably_installed++;
435
		}
436
437
		if ($probably_installed == 2)
438
			$incontext['warning'] = $txt['error_already_installed'];
439
	}
440
441
	// Is some database support even compiled in?
442
	$incontext['supported_databases'] = array();
443
	foreach ($databases as $key => $db)
444
	{
445
		if ($db['supported'])
446
		{
447
			$type = ($key == 'mysqli') ? 'mysql' : $key;
448
			if (!file_exists(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql'))
449
			{
450
				$databases[$key]['supported'] = false;
451
				$notFoundSQLFile = true;
452
				$txt['error_db_script_missing'] = sprintf($txt['error_db_script_missing'], 'install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
453
			}
454
			else
455
				$incontext['supported_databases'][] = $db;
456
		}
457
	}
458
459
	// Check the PHP version.
460
	if ((!function_exists('version_compare') || version_compare($GLOBALS['required_php_version'], PHP_VERSION, '>=')))
461
		$error = 'error_php_too_low';
462
	// Make sure we have a supported database
463
	elseif (empty($incontext['supported_databases']))
464
		$error = empty($notFoundSQLFile) ? 'error_db_missing' : 'error_db_script_missing';
465
	// How about session support?  Some crazy sysadmin remove it?
466
	elseif (!function_exists('session_start'))
467
		$error = 'error_session_missing';
468
	// Make sure they uploaded all the files.
469
	elseif (!file_exists(dirname(__FILE__) . '/index.php'))
470
		$error = 'error_missing_files';
471
	// Very simple check on the session.save_path for Windows.
472
	// @todo Move this down later if they don't use database-driven sessions?
473
	elseif (@ini_get('session.save_path') == '/tmp' && substr(__FILE__, 1, 2) == ':\\')
474
		$error = 'error_session_save_path';
475
476
	// Since each of the three messages would look the same, anyway...
477
	if (isset($error))
478
		$incontext['error'] = $txt[$error];
479
480
	// Mod_security blocks everything that smells funny. Let SMF handle security.
481
	if (!fixModSecurity() && !isset($_GET['overmodsecurity']))
482
		$incontext['error'] = $txt['error_mod_security'] . '<br><br><a href="' . $installurl . '?overmodsecurity=true">' . $txt['error_message_click'] . '</a> ' . $txt['error_message_bad_try_again'];
483
484
	// Confirm mbstring is loaded...
485
	if (!extension_loaded('mbstring'))
486
		$incontext['error'] = $txt['install_no_mbstring'];
487
488
	// Check for https stream support.
489
	$supported_streams = stream_get_wrappers();
490
	if (!in_array('https', $supported_streams))
491
		$incontext['warning'] = $txt['install_no_https'];
492
493
	return false;
494
}
495
496
function CheckFilesWritable()
497
{
498
	global $txt, $incontext;
499
500
	$incontext['page_title'] = $txt['ftp_checking_writable'];
501
	$incontext['sub_template'] = 'chmod_files';
502
503
	$writable_files = array(
504
		'attachments',
505
		'avatars',
506
		'custom_avatar',
507
		'cache',
508
		'Packages',
509
		'Smileys',
510
		'Themes',
511
		'agreement.txt',
512
		'Settings.php',
513
		'Settings_bak.php',
514
		'db_last_error.php',
515
	);
516
517
	foreach ($incontext['detected_languages'] as $lang => $temp)
518
		$extra_files[] = 'Themes/default/languages/' . $lang;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$extra_files was never initialized. Although not strictly required by PHP, it is generally a good practice to add $extra_files = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
519
520
	// With mod_security installed, we could attempt to fix it with .htaccess.
521
	if (function_exists('apache_get_modules') && in_array('mod_security', apache_get_modules()))
522
		$writable_files[] = file_exists(dirname(__FILE__) . '/.htaccess') ? '.htaccess' : '.';
523
524
	$failed_files = array();
525
526
	// On linux, it's easy - just use is_writable!
527
	if (substr(__FILE__, 1, 2) != ':\\')
528
	{
529
		$incontext['systemos'] = 'linux';
530
531
		foreach ($writable_files as $file)
532
		{
533
			if (!is_writable(dirname(__FILE__) . '/' . $file))
534
			{
535
				@chmod(dirname(__FILE__) . '/' . $file, 0755);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
536
537
				// Well, 755 hopefully worked... if not, try 777.
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
538
				if (!is_writable(dirname(__FILE__) . '/' . $file) && !@chmod(dirname(__FILE__) . '/' . $file, 0777))
539
					$failed_files[] = $file;
540
			}
541
		}
542 View Code Duplication
		foreach ($extra_files as $file)
0 ignored issues
show
The variable $extra_files does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
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...
543
			@chmod(dirname(__FILE__) . (empty($file) ? '' : '/' . $file), 0777);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
544
	}
545
	// Windows is trickier.  Let's try opening for r+...
546
	else
547
	{
548
		$incontext['systemos'] = 'windows';
549
550
		foreach ($writable_files as $file)
551
		{
552
			// Folders can't be opened for write... but the index.php in them can ;)
553
			if (is_dir(dirname(__FILE__) . '/' . $file))
554
				$file .= '/index.php';
555
556
			// Funny enough, chmod actually does do something on windows - it removes the read only attribute.
557
			@chmod(dirname(__FILE__) . '/' . $file, 0777);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
558
			$fp = @fopen(dirname(__FILE__) . '/' . $file, 'r+');
559
560
			// Hmm, okay, try just for write in that case...
561
			if (!is_resource($fp))
562
				$fp = @fopen(dirname(__FILE__) . '/' . $file, 'w');
563
564
			if (!is_resource($fp))
565
				$failed_files[] = $file;
566
567
			@fclose($fp);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
568
		}
569 View Code Duplication
		foreach ($extra_files as $file)
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...
570
			@chmod(dirname(__FILE__) . (empty($file) ? '' : '/' . $file), 0777);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
571
	}
572
573
	$failure = count($failed_files) >= 1;
574
575
	if (!isset($_SERVER))
576
		return !$failure;
577
578
	// Put the list into context.
579
	$incontext['failed_files'] = $failed_files;
580
581
	// It's not going to be possible to use FTP on windows to solve the problem...
582
	if ($failure && substr(__FILE__, 1, 2) == ':\\')
583
	{
584
		$incontext['error'] = $txt['error_windows_chmod'] . '
585
					<ul style="margin: 2.5ex; font-family: monospace;">
586
						<li>' . implode('</li>
587
						<li>', $failed_files) . '</li>
588
					</ul>';
589
590
		return false;
591
	}
592
	// We're going to have to use... FTP!
593
	elseif ($failure)
594
	{
595
		// Load any session data we might have...
596 View Code Duplication
		if (!isset($_POST['ftp_username']) && isset($_SESSION['installer_temp_ftp']))
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...
597
		{
598
			$_POST['ftp_server'] = $_SESSION['installer_temp_ftp']['server'];
599
			$_POST['ftp_port'] = $_SESSION['installer_temp_ftp']['port'];
600
			$_POST['ftp_username'] = $_SESSION['installer_temp_ftp']['username'];
601
			$_POST['ftp_password'] = $_SESSION['installer_temp_ftp']['password'];
602
			$_POST['ftp_path'] = $_SESSION['installer_temp_ftp']['path'];
603
		}
604
605
		$incontext['ftp_errors'] = array();
606
		require_once('Sources/Class-Package.php');
607 View Code Duplication
		if (isset($_POST['ftp_username']))
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...
608
		{
609
			$ftp = new ftp_connection($_POST['ftp_server'], $_POST['ftp_port'], $_POST['ftp_username'], $_POST['ftp_password']);
610
611
			if ($ftp->error === false)
612
			{
613
				// Try it without /home/abc just in case they messed up.
614
				if (!$ftp->chdir($_POST['ftp_path']))
615
				{
616
					$incontext['ftp_errors'][] = $ftp->last_message;
617
					$ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $_POST['ftp_path']));
618
				}
619
			}
620
		}
621
622
		if (!isset($ftp) || $ftp->error !== false)
623
		{
624
			if (!isset($ftp))
625
				$ftp = new ftp_connection(null);
626
			// Save the error so we can mess with listing...
627
			elseif ($ftp->error !== false && empty($incontext['ftp_errors']) && !empty($ftp->last_message))
628
				$incontext['ftp_errors'][] = $ftp->last_message;
629
630
			list ($username, $detect_path, $found_path) = $ftp->detect_path(dirname(__FILE__));
631
632
			if (empty($_POST['ftp_path']) && $found_path)
633
				$_POST['ftp_path'] = $detect_path;
634
635
			if (!isset($_POST['ftp_username']))
636
				$_POST['ftp_username'] = $username;
637
638
			// Set the username etc, into context.
639
			$incontext['ftp'] = array(
640
				'server' => isset($_POST['ftp_server']) ? $_POST['ftp_server'] : 'localhost',
641
				'port' => isset($_POST['ftp_port']) ? $_POST['ftp_port'] : '21',
642
				'username' => isset($_POST['ftp_username']) ? $_POST['ftp_username'] : '',
643
				'path' => isset($_POST['ftp_path']) ? $_POST['ftp_path'] : '/',
644
				'path_msg' => !empty($found_path) ? $txt['ftp_path_found_info'] : $txt['ftp_path_info'],
645
			);
646
647
			return false;
648
		}
649
		else
650
		{
651
			$_SESSION['installer_temp_ftp'] = array(
652
				'server' => $_POST['ftp_server'],
653
				'port' => $_POST['ftp_port'],
654
				'username' => $_POST['ftp_username'],
655
				'password' => $_POST['ftp_password'],
656
				'path' => $_POST['ftp_path']
657
			);
658
659
			$failed_files_updated = array();
660
661
			foreach ($failed_files as $file)
662
			{
663
				if (!is_writable(dirname(__FILE__) . '/' . $file))
664
					$ftp->chmod($file, 0755);
665
				if (!is_writable(dirname(__FILE__) . '/' . $file))
666
					$ftp->chmod($file, 0777);
667
				if (!is_writable(dirname(__FILE__) . '/' . $file))
668
				{
669
					$failed_files_updated[] = $file;
670
					$incontext['ftp_errors'][] = rtrim($ftp->last_message) . ' -> ' . $file . "\n";
671
				}
672
			}
673
674
			$ftp->close();
675
676
			// Are there any errors left?
677
			if (count($failed_files_updated) >= 1)
678
			{
679
				// Guess there are...
680
				$incontext['failed_files'] = $failed_files_updated;
681
682
				// Set the username etc, into context.
683
				$incontext['ftp'] = $_SESSION['installer_temp_ftp'] += array(
684
					'path_msg' => $txt['ftp_path_info'],
685
				);
686
687
				return false;
688
			}
689
		}
690
	}
691
692
	return true;
693
}
694
695
function DatabaseSettings()
696
{
697
	global $txt, $databases, $incontext, $smcFunc, $sourcedir;
698
	global $db_server, $db_name, $db_user, $db_passwd;
699
700
	$incontext['sub_template'] = 'database_settings';
701
	$incontext['page_title'] = $txt['db_settings'];
702
	$incontext['continue'] = 1;
703
704
	// Set up the defaults.
705
	$incontext['db']['server'] = 'localhost';
706
	$incontext['db']['user'] = '';
707
	$incontext['db']['name'] = '';
708
	$incontext['db']['pass'] = '';
709
	$incontext['db']['type'] = '';
710
	$incontext['supported_databases'] = array();
711
712
	$foundOne = false;
713
	foreach ($databases as $key => $db)
714
	{
715
		// Override with the defaults for this DB if appropriate.
716
		if ($db['supported'])
717
		{
718
			$incontext['supported_databases'][$key] = $db;
719
720
			if (!$foundOne)
721
			{
722
				if (isset($db['default_host']))
723
					$incontext['db']['server'] = ini_get($db['default_host']) or $incontext['db']['server'] = 'localhost';
724
				if (isset($db['default_user']))
725
				{
726
					$incontext['db']['user'] = ini_get($db['default_user']);
727
					$incontext['db']['name'] = ini_get($db['default_user']);
728
				}
729
				if (isset($db['default_password']))
730
					$incontext['db']['pass'] = ini_get($db['default_password']);
731
732
				// For simplicity and less confusion, leave the port blank by default
733
				$incontext['db']['port'] = '';
734
735
				$incontext['db']['type'] = $key;
736
				$foundOne = true;
737
			}
738
		}
739
	}
740
741
	// Override for repost.
742
	if (isset($_POST['db_user']))
743
	{
744
		$incontext['db']['user'] = $_POST['db_user'];
745
		$incontext['db']['name'] = $_POST['db_name'];
746
		$incontext['db']['server'] = $_POST['db_server'];
747
		$incontext['db']['prefix'] = $_POST['db_prefix'];
748
749
		if (!empty($_POST['db_port']))
750
			$incontext['db']['port'] = $_POST['db_port'];
751
	}
752
	else
753
	{
754
		$incontext['db']['prefix'] = 'smf_';
755
	}
756
757
	// Are we submitting?
758
	if (isset($_POST['db_type']))
759
	{
760
		// What type are they trying?
761
		$db_type = preg_replace('~[^A-Za-z0-9]~', '', $_POST['db_type']);
762
		$db_prefix = $_POST['db_prefix'];
763
		// Validate the prefix.
764
		$valid_prefix = $databases[$db_type]['validate_prefix']($db_prefix);
765
766
		if ($valid_prefix !== true)
767
		{
768
			$incontext['error'] = $valid_prefix;
769
			return false;
770
		}
771
772
		// Take care of these variables...
773
		$vars = array(
774
			'db_type' => $db_type,
775
			'db_name' => $_POST['db_name'],
776
			'db_user' => $_POST['db_user'],
777
			'db_passwd' => isset($_POST['db_passwd']) ? $_POST['db_passwd'] : '',
778
			'db_server' => $_POST['db_server'],
779
			'db_prefix' => $db_prefix,
780
			// The cookiename is special; we want it to be the same if it ever needs to be reinstalled with the same info.
781
			'cookiename' => 'SMFCookie' . abs(crc32($_POST['db_name'] . preg_replace('~[^A-Za-z0-9_$]~', '', $_POST['db_prefix'])) % 1000),
782
		);
783
784
		// Only set the port if we're not using the default
785
		if (!empty($_POST['db_port']))
786
		{
787
			// For MySQL, we can get the "default port" from PHP. PostgreSQL has no such option though.
788
			if (($db_type == 'mysql' || $db_type == 'mysqli') && $_POST['db_port'] != ini_get($db_type . '.default_port'))
789
				$vars['db_port'] = (int) $_POST['db_port'];
790 View Code Duplication
			elseif ($db_type == 'postgresql' && $_POST['db_port'] != 5432)
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...
791
				$vars['db_port'] = (int) $_POST['db_port'];
792
		}
793
794
		// God I hope it saved!
795 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
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...
796
		{
797
			$incontext['error'] = $txt['error_windows_chmod'];
798
			return false;
799
		}
800
801
		// Make sure it works.
802
		require(dirname(__FILE__) . '/Settings.php');
803
804
		if (empty($sourcedir))
805
			$sourcedir = dirname(__FILE__) . '/Sources';
806
807
		// Better find the database file!
808
		if (!file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php'))
809
		{
810
			$incontext['error'] = sprintf($txt['error_db_file'], 'Subs-Db-' . $db_type . '.php');
811
			return false;
812
		}
813
814
		// Now include it for database functions!
815
		if (!defined('SMF'))
816
			define('SMF', 1);
817
818
		$modSettings['disableQueryCheck'] = true;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$modSettings was never initialized. Although not strictly required by PHP, it is generally a good practice to add $modSettings = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
819
		if (empty($smcFunc))
820
			$smcFunc = array();
821
822
			require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
823
824
		// What - running PHP4? The shame!
825
		if (version_compare(PHP_VERSION, '5', '<'))
826
			require_once($sourcedir . '/Subs-Compat.php');
827
828
		// Attempt a connection.
829
		$needsDB = !empty($databases[$db_type]['always_has_db']);
830
		$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('non_fatal' => true, 'dont_select_db' => !$needsDB));
831
832
		// No dice?  Let's try adding the prefix they specified, just in case they misread the instructions ;)
833
		if ($db_connection == null)
834
		{
835
			$db_error = @$smcFunc['db_error']();
836
837
			$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));
838
			if ($db_connection != null)
839
			{
840
				$db_user = $_POST['db_prefix'] . $db_user;
841
				updateSettingsFile(array('db_user' => $db_user));
842
			}
843
		}
844
845
		// Still no connection?  Big fat error message :P.
846
		if (!$db_connection)
847
		{
848
			$incontext['error'] = $txt['error_db_connect'] . '<div style="margin: 2.5ex; font-family: monospace;"><strong>' . $db_error . '</strong></div>';
0 ignored issues
show
The variable $db_error does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
849
			return false;
850
		}
851
852
		// Do they meet the install requirements?
853
		// @todo Old client, new server?
854
		if (version_compare($databases[$db_type]['version'], preg_replace('~^\D*|\-.+?$~', '', eval($databases[$db_type]['version_check']))) > 0)
0 ignored issues
show
The function DatabaseSettings() contains an eval expression.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
855
		{
856
			$incontext['error'] = $txt['error_db_too_low'];
857
			return false;
858
		}
859
860
		// Let's try that database on for size... assuming we haven't already lost the opportunity.
861
		if ($db_name != '' && !$needsDB)
862
		{
863
			$smcFunc['db_query']('', "
864
				CREATE DATABASE IF NOT EXISTS `$db_name`",
865
				array(
866
					'security_override' => true,
867
					'db_error_skip' => true,
868
				),
869
				$db_connection
870
			);
871
872
			// Okay, let's try the prefix if it didn't work...
873
			if (!$smcFunc['db_select_db']($db_name, $db_connection) && $db_name != '')
874
			{
875
				$smcFunc['db_query']('', "
876
					CREATE DATABASE IF NOT EXISTS `$_POST[db_prefix]$db_name`",
877
					array(
878
						'security_override' => true,
879
						'db_error_skip' => true,
880
					),
881
					$db_connection
882
				);
883
884
				if ($smcFunc['db_select_db']($_POST['db_prefix'] . $db_name, $db_connection))
885
				{
886
					$db_name = $_POST['db_prefix'] . $db_name;
887
					updateSettingsFile(array('db_name' => $db_name));
888
				}
889
			}
890
891
			// Okay, now let's try to connect...
892
			if (!$smcFunc['db_select_db']($db_name, $db_connection))
893
			{
894
				$incontext['error'] = sprintf($txt['error_db_database'], $db_name);
895
				return false;
896
			}
897
		}
898
899
		return true;
900
	}
901
902
	return false;
903
}
904
905
// Let's start with basic forum type settings.
906
function ForumSettings()
907
{
908
	global $txt, $incontext, $databases, $db_type, $db_connection;
909
910
	$incontext['sub_template'] = 'forum_settings';
911
	$incontext['page_title'] = $txt['install_settings'];
912
913
	// Let's see if we got the database type correct.
914
	if (isset($_POST['db_type'], $databases[$_POST['db_type']]))
915
		$db_type = $_POST['db_type'];
916
917
	// Else we'd better be able to get the connection.
918
	else
919
		load_database();
920
921
	$db_type = isset($_POST['db_type']) ? $_POST['db_type'] : $db_type;
922
923
	// What host and port are we on?
924
	$host = empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST'];
925
926
	// Now, to put what we've learned together... and add a path.
927
	$incontext['detected_url'] = 'http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . $host . substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
928
929
	// Check if the database sessions will even work.
930
	$incontext['test_dbsession'] = (ini_get('session.auto_start') != 1);
931
	$incontext['utf8_default'] = $databases[$db_type]['utf8_default'];
932
	$incontext['utf8_required'] = $databases[$db_type]['utf8_required'];
933
934
	$incontext['continue'] = 1;
935
936
	// Submitting?
937
	if (isset($_POST['boardurl']))
938
	{
939 View Code Duplication
		if (substr($_POST['boardurl'], -10) == '/index.php')
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...
940
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -10);
941
		elseif (substr($_POST['boardurl'], -1) == '/')
942
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -1);
943 View Code Duplication
		if (substr($_POST['boardurl'], 0, 7) != 'http://' && substr($_POST['boardurl'], 0, 7) != 'file://' && substr($_POST['boardurl'], 0, 8) != 'https://')
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...
944
			$_POST['boardurl'] = 'http://' . $_POST['boardurl'];
945
946
		// Save these variables.
947
		$vars = array(
948
			'boardurl' => $_POST['boardurl'],
949
			'boarddir' => addslashes(dirname(__FILE__)),
950
			'sourcedir' => addslashes(dirname(__FILE__)) . '/Sources',
951
			'cachedir' => addslashes(dirname(__FILE__)) . '/cache',
952
			'packagesdir' => addslashes(dirname(__FILE__)) . '/Packages',
953
			'tasksdir' => addslashes(dirname(__FILE__)) . '/Sources/tasks',
954
			'mbname' => strtr($_POST['mbname'], array('\"' => '"')),
955
			'language' => substr($_SESSION['installer_temp_lang'], 8, -4),
956
			'image_proxy_secret' => substr(sha1(mt_rand()), 0, 20),
957
			'image_proxy_enabled' => !empty($_POST['force_ssl']),
958
		);
959
960
		// Must save!
961 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
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...
962
		{
963
			$incontext['error'] = $txt['error_windows_chmod'];
964
			return false;
965
		}
966
967
		// Make sure it works.
968
		require(dirname(__FILE__) . '/Settings.php');
969
970
		// UTF-8 requires a setting to override the language charset.
971
		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'])))
972
		{
973
			if (!$databases[$db_type]['utf8_support']())
974
			{
975
				$incontext['error'] = sprintf($txt['error_utf8_support']);
976
				return false;
977
			}
978
979
			if (!empty($databases[$db_type]['utf8_version_check']) && version_compare($databases[$db_type]['utf8_version'], preg_replace('~\-.+?$~', '', eval($databases[$db_type]['utf8_version_check'])), '>'))
0 ignored issues
show
The function ForumSettings() contains an eval expression.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
980
			{
981
				$incontext['error'] = sprintf($txt['error_utf8_version'], $databases[$db_type]['utf8_version']);
982
				return false;
983
			}
984
			else
985
				// Set the character set here.
986
				updateSettingsFile(array('db_character_set' => 'utf8'));
987
		}
988
989
		// Good, skip on.
990
		return true;
991
	}
992
993
	return false;
994
}
995
996
// Step one: Do the SQL thang.
997
function DatabasePopulation()
998
{
999
	global $db_character_set, $txt, $db_connection, $smcFunc, $databases, $modSettings, $db_type, $db_prefix, $incontext, $db_name, $boardurl;
1000
1001
	$incontext['sub_template'] = 'populate_database';
1002
	$incontext['page_title'] = $txt['db_populate'];
1003
	$incontext['continue'] = 1;
1004
1005
	// Already done?
1006
	if (isset($_POST['pop_done']))
1007
		return true;
1008
1009
	// Reload settings.
1010
	require(dirname(__FILE__) . '/Settings.php');
1011
	load_database();
1012
1013
	// Before running any of the queries, let's make sure another version isn't already installed.
1014
	$result = $smcFunc['db_query']('', '
1015
		SELECT variable, value
1016
		FROM {db_prefix}settings',
1017
		array(
1018
			'db_error_skip' => true,
1019
		)
1020
	);
1021
	$newSettings = array();
1022
	$modSettings = array();
1023
	if ($result !== false)
1024
	{
1025 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($result))
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...
1026
			$modSettings[$row['variable']] = $row['value'];
1027
		$smcFunc['db_free_result']($result);
1028
1029
		// Do they match?  If so, this is just a refresh so charge on!
1030
		if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] != $GLOBALS['current_smf_version'])
1031
		{
1032
			$incontext['error'] = $txt['error_versions_do_not_match'];
1033
			return false;
1034
		}
1035
	}
1036
	$modSettings['disableQueryCheck'] = true;
1037
1038
	// If doing UTF8, select it. PostgreSQL requires passing it as a string...
1039 View Code Duplication
	if (!empty($db_character_set) && $db_character_set == 'utf8' && !empty($databases[$db_type]['utf8_support']))
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...
1040
		$smcFunc['db_query']('', '
1041
			SET NAMES {string:utf8}',
1042
			array(
1043
				'db_error_skip' => true,
1044
				'utf8' => 'utf8',
1045
			)
1046
		);
1047
1048
	// Windows likes to leave the trailing slash, which yields to C:\path\to\SMF\/attachments...
1049
	if (substr(__DIR__, -1) == '\\')
1050
		$attachdir = __DIR__ . 'attachments';
1051
	else
1052
		$attachdir = __DIR__ . '/attachments';
1053
1054
	$replaces = array(
1055
		'{$db_prefix}' => $db_prefix,
1056
		'{$attachdir}' => json_encode(array(1 => $smcFunc['db_escape_string']($attachdir))),
1057
		'{$boarddir}' => $smcFunc['db_escape_string'](dirname(__FILE__)),
1058
		'{$boardurl}' => $boardurl,
1059
		'{$enableCompressedOutput}' => isset($_POST['compress']) ? '1' : '0',
1060
		'{$databaseSession_enable}' => isset($_POST['dbsession']) ? '1' : '0',
1061
		'{$smf_version}' => $GLOBALS['current_smf_version'],
1062
		'{$current_time}' => time(),
1063
		'{$sched_task_offset}' => 82800 + mt_rand(0, 86399),
1064
		'{$registration_method}' => isset($_POST['reg_mode']) ? $_POST['reg_mode'] : 0,
1065
	);
1066
1067
	foreach ($txt as $key => $value)
1068
	{
1069
		if (substr($key, 0, 8) == 'default_')
1070
			$replaces['{$' . $key . '}'] = $smcFunc['db_escape_string']($value);
1071
	}
1072
	$replaces['{$default_reserved_names}'] = strtr($replaces['{$default_reserved_names}'], array('\\\\n' => '\\n'));
1073
1074
	// MySQL-specific stuff - storage engine and UTF8 handling
1075
	if (substr($db_type, 0, 5) == 'mysql')
1076
	{
1077
		// Just in case the query fails for some reason...
1078
		$engines = array();
1079
1080
		// Figure out storage engines - what do we have, etc.
1081
		$get_engines = $smcFunc['db_query']('', 'SHOW ENGINES', array());
1082
1083 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($get_engines))
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...
1084
		{
1085
			if ($row['Support'] == 'YES' || $row['Support'] == 'DEFAULT')
1086
				$engines[] = $row['Engine'];
1087
		}
1088
1089
		// Done with this now
1090
		$smcFunc['db_free_result']($get_engines);
1091
1092
		// InnoDB is better, so use it if possible...
1093
		$has_innodb = in_array('InnoDB', $engines);
1094
		$replaces['{$engine}'] = $has_innodb ? 'InnoDB' : 'MyISAM';
1095
		$replaces['{$memory}'] = (!$has_innodb && in_array('MEMORY', $engines)) ? 'MEMORY' : $replaces['{$engine}'];
1096
1097
		// If the UTF-8 setting was enabled, add it to the table definitions.
1098
		if (!empty($databases[$db_type]['utf8_support']) && (!empty($databases[$db_type]['utf8_required']) || isset($_POST['utf8'])))
1099
		{
1100
			$replaces['{$engine}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1101
			$replaces['{$memory}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1102
		}
1103
1104
		// One last thing - if we don't have InnoDB, we can't do transactions...
1105
		if (!$has_innodb)
1106
		{
1107
			$replaces['START TRANSACTION;'] = '';
1108
			$replaces['COMMIT;'] = '';
1109
		}
1110
	}
1111
	else
1112
	{
1113
		$has_innodb = false;
1114
	}
1115
1116
	// Read in the SQL.  Turn this on and that off... internationalize... etc.
1117
	$type = ($db_type == 'mysqli' ? 'mysql' : $db_type);
1118
	$sql_lines = explode("\n", strtr(implode(' ', file(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql')), $replaces));
1119
1120
	// Execute the SQL.
1121
	$current_statement = '';
1122
	$exists = array();
1123
	$incontext['failures'] = array();
1124
	$incontext['sql_results'] = array(
1125
		'tables' => 0,
1126
		'inserts' => 0,
1127
		'table_dups' => 0,
1128
		'insert_dups' => 0,
1129
	);
1130
	foreach ($sql_lines as $count => $line)
1131
	{
1132
		// No comments allowed!
1133
		if (substr(trim($line), 0, 1) != '#')
1134
			$current_statement .= "\n" . rtrim($line);
1135
1136
		// Is this the end of the query string?
1137
		if (empty($current_statement) || (preg_match('~;[\s]*$~s', $line) == 0 && $count != count($sql_lines)))
1138
			continue;
1139
1140
		// Does this table already exist?  If so, don't insert more data into it!
1141
		if (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) != 0 && in_array($match[1], $exists))
1142
		{
1143
			preg_match_all('~\)[,;]~', $current_statement, $matches);
1144 View Code Duplication
			if (!empty($matches[0]))
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...
1145
				$incontext['sql_results']['insert_dups'] += count($matches[0]);
1146
			else
1147
				$incontext['sql_results']['insert_dups']++;
1148
1149
			$current_statement = '';
1150
			continue;
1151
		}
1152
1153
		if ($smcFunc['db_query']('', $current_statement, array('security_override' => true, 'db_error_skip' => true), $db_connection) === false)
1154
		{
1155
			// Use the appropriate function based on the DB type
1156
			if ($db_type == 'mysql' || $db_type == 'mysqli')
1157
				$db_errorno = $db_type . '_errno';
1158
1159
			// Error 1050: Table already exists!
1160
			// @todo Needs to be made better!
1161
			if ((($db_type != 'mysql' && $db_type != 'mysqli') || $db_errorno($db_connection) == 1050) && preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
0 ignored issues
show
The variable $db_errorno does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1162
			{
1163
				$exists[] = $match[1];
1164
				$incontext['sql_results']['table_dups']++;
1165
			}
1166
			// Don't error on duplicate indexes (or duplicate operators in PostgreSQL.)
1167
			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)))
1168
			{
1169
				// MySQLi requires a connection object. It's optional with MySQL and Postgres
1170
				$incontext['failures'][$count] = $smcFunc['db_error']($db_connection);
1171
			}
1172
		}
1173
		else
1174
		{
1175
			if (preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1176
				$incontext['sql_results']['tables']++;
1177
			elseif (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1178
			{
1179
				preg_match_all('~\)[,;]~', $current_statement, $matches);
1180 View Code Duplication
				if (!empty($matches[0]))
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...
1181
					$incontext['sql_results']['inserts'] += count($matches[0]);
1182
				else
1183
					$incontext['sql_results']['inserts']++;
1184
			}
1185
		}
1186
1187
		$current_statement = '';
1188
1189
		// Wait, wait, I'm still working here!
1190
		set_time_limit(60);
1191
	}
1192
1193
	// Sort out the context for the SQL.
1194
	foreach ($incontext['sql_results'] as $key => $number)
1195
	{
1196
		if ($number == 0)
1197
			unset($incontext['sql_results'][$key]);
1198
		else
1199
			$incontext['sql_results'][$key] = sprintf($txt['db_populate_' . $key], $number);
1200
	}
1201
1202
	// Make sure UTF will be used globally.
1203
	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'])))
1204
		$newSettings[] = array('global_character_set', 'UTF-8');
1205
1206
	// Maybe we can auto-detect better cookie settings?
1207
	preg_match('~^http[s]?://([^\.]+?)([^/]*?)(/.*)?$~', $boardurl, $matches);
1208
	if (!empty($matches))
1209
	{
1210
		// Default = both off.
1211
		$localCookies = false;
1212
		$globalCookies = false;
1213
1214
		// Okay... let's see.  Using a subdomain other than www.? (not a perfect check.)
1215
		if ($matches[2] != '' && (strpos(substr($matches[2], 1), '.') === false || in_array($matches[1], array('forum', 'board', 'community', 'forums', 'support', 'chat', 'help', 'talk', 'boards', 'www'))))
1216
			$globalCookies = true;
1217
		// If there's a / in the middle of the path, or it starts with ~... we want local.
1218
		if (isset($matches[3]) && strlen($matches[3]) > 3 && (substr($matches[3], 0, 2) == '/~' || strpos(substr($matches[3], 1), '/') !== false))
1219
			$localCookies = true;
1220
1221
		if ($globalCookies)
1222
			$newSettings[] = array('globalCookies', '1');
1223
		if ($localCookies)
1224
			$newSettings[] = array('localCookies', '1');
1225
	}
1226
1227
	// Are we allowing stat collection?
1228
	if (!empty($_POST['stats']) && substr($boardurl, 0, 16) != 'http://localhost' && empty($modSettings['allow_sm_stats']) && empty($modSettings['enable_sm_stats']))
1229
	{
1230
		$upcontext['allow_sm_stats'] = true;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$upcontext was never initialized. Although not strictly required by PHP, it is generally a good practice to add $upcontext = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

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

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

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

Loading history...
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...
1264
		$smcFunc['db_query']('', '
1265
			DELETE FROM {db_prefix}settings
1266
			WHERE variable = {string:enable_sm_stats}',
1267
			array(
1268
				'enable_sm_stats' => 'enable_sm_stats',
1269
				'db_error_skip' => true,
1270
			)
1271
		);
1272
1273
	// Are we enabling SSL?
1274
	if (!empty($_POST['force_ssl']))
1275
		$newSettings[] = array('force_ssl', 2);
1276
1277
	// Setting a timezone is required.
1278
	if (!isset($modSettings['default_timezone']) && function_exists('date_default_timezone_set'))
1279
	{
1280
		// Get PHP's default timezone, if set
1281
		$ini_tz = ini_get('date.timezone');
1282
		if (!empty($ini_tz))
1283
			$timezone_id = $ini_tz;
1284
		else
1285
			$timezone_id = '';
1286
1287
		// If date.timezone is unset, invalid, or just plain weird, make a best guess
1288 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...
1289
		{
1290
			$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
1291
			$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
1292
		}
1293
1294
		if (date_default_timezone_set($timezone_id))
1295
			$newSettings[] = array('default_timezone', $timezone_id);
1296
	}
1297
1298
	if (!empty($newSettings))
1299
	{
1300
		$smcFunc['db_insert']('replace',
1301
			'{db_prefix}settings',
1302
			array('variable' => 'string-255', 'value' => 'string-65534'),
1303
			$newSettings,
1304
			array('variable')
1305
		);
1306
	}
1307
1308
	// Let's optimize those new tables, but not on InnoDB, ok?
1309
	if (!$has_innodb)
1310
	{
1311
		db_extend();
1312
		$tables = $smcFunc['db_list_tables']($db_name, $db_prefix . '%');
1313
		foreach ($tables as $table)
1314
		{
1315
			$smcFunc['db_optimize_table']($table) != -1 or $db_messed = true;
1316
1317
			if (!empty($db_messed))
1318
			{
1319
				$incontext['failures'][-1] = $smcFunc['db_error']();
1320
				break;
1321
			}
1322
		}
1323
	}
1324
1325
	// MySQL specific stuff
1326
	if (substr($db_type, 0, 5) != 'mysql')
1327
		return false;
1328
1329
	// Find database user privileges.
1330
	$privs = array();
1331
	$get_privs = $smcFunc['db_query']('', 'SHOW PRIVILEGES', array());
1332
	while ($row = $smcFunc['db_fetch_assoc']($get_privs))
1333
	{
1334
		if ($row['Privilege'] == 'Alter')
1335
			$privs[] = $row['Privilege'];
1336
	}
1337
	$smcFunc['db_free_result']($get_privs);
1338
1339
	// Check for the ALTER privilege.
1340
	if (!empty($databases[$db_type]['alter_support']) && !in_array('Alter', $privs))
1341
	{
1342
		$incontext['error'] = $txt['error_db_alter_priv'];
1343
		return false;
1344
	}
1345
1346
	if (!empty($exists))
1347
	{
1348
		$incontext['page_title'] = $txt['user_refresh_install'];
1349
		$incontext['was_refresh'] = true;
1350
	}
1351
1352
	return false;
1353
}
1354
1355
// Ask for the administrator login information.
1356
function AdminAccount()
1357
{
1358
	global $txt, $db_type, $smcFunc, $incontext, $db_prefix, $db_passwd, $sourcedir, $db_character_set, $boardurl, $cachedir;
1359
1360
	$incontext['sub_template'] = 'admin_account';
1361
	$incontext['page_title'] = $txt['user_settings'];
1362
	$incontext['continue'] = 1;
1363
1364
	// Skipping?
1365
	if (!empty($_POST['skip']))
1366
		return true;
1367
1368
	// Need this to check whether we need the database password.
1369
	require(dirname(__FILE__) . '/Settings.php');
1370
	load_database();
1371
1372
	require_once($sourcedir . '/Subs-Auth.php');
1373
1374
	require_once($sourcedir . '/Subs.php');
1375
1376
	// Reload settings & set some global funcs
1377
	require_once($sourcedir . '/Load.php');
1378
	reloadSettings();
1379
1380
	// We need this to properly hash the password for Admin
1381 View Code Duplication
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' : function($string) {
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...
1382
			global $sourcedir;
1383
			if (function_exists('mb_strtolower'))
1384
				return mb_strtolower($string, 'UTF-8');
1385
			require_once($sourcedir . '/Subs-Charset.php');
1386
			return utf8_strtolower($string);
1387
		};
1388
1389
	if (!isset($_POST['username']))
1390
		$_POST['username'] = '';
1391
	if (!isset($_POST['email']))
1392
		$_POST['email'] = '';
1393
	if (!isset($_POST['server_email']))
1394
		$_POST['server_email'] = '';
1395
1396
	$incontext['username'] = htmlspecialchars(stripslashes($_POST['username']));
1397
	$incontext['email'] = htmlspecialchars(stripslashes($_POST['email']));
1398
	$incontext['server_email'] = htmlspecialchars(stripslashes($_POST['server_email']));
1399
1400
	$incontext['require_db_confirm'] = empty($db_type);
1401
1402
	// Only allow skipping if we think they already have an account setup.
1403
	$request = $smcFunc['db_query']('', '
1404
		SELECT id_member
1405
		FROM {db_prefix}members
1406
		WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
1407
		LIMIT 1',
1408
		array(
1409
			'db_error_skip' => true,
1410
			'admin_group' => 1,
1411
		)
1412
	);
1413
	if ($smcFunc['db_num_rows']($request) != 0)
1414
		$incontext['skip'] = 1;
1415
	$smcFunc['db_free_result']($request);
1416
1417
	// Trying to create an account?
1418
	if (isset($_POST['password1']) && !empty($_POST['contbutt']))
1419
	{
1420
		// Wrong password?
1421
		if ($incontext['require_db_confirm'] && $_POST['password3'] != $db_passwd)
1422
		{
1423
			$incontext['error'] = $txt['error_db_connect'];
1424
			return false;
1425
		}
1426
		// Not matching passwords?
1427
		if ($_POST['password1'] != $_POST['password2'])
1428
		{
1429
			$incontext['error'] = $txt['error_user_settings_again_match'];
1430
			return false;
1431
		}
1432
		// No password?
1433
		if (strlen($_POST['password1']) < 4)
1434
		{
1435
			$incontext['error'] = $txt['error_user_settings_no_password'];
1436
			return false;
1437
		}
1438
		if (!file_exists($sourcedir . '/Subs.php'))
1439
		{
1440
			$incontext['error'] = $txt['error_subs_missing'];
1441
			return false;
1442
		}
1443
1444
		// Update the webmaster's email?
1445
		if (!empty($_POST['server_email']) && (empty($webmaster_email) || $webmaster_email == '[email protected]'))
0 ignored issues
show
The variable $webmaster_email seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
The variable $webmaster_email does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

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

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
2433