Completed
Push — release-2.1 ( 5876a2...f30e04 )
by Mert
06:50
created

install.php ➔ AdminAccount()   F

Complexity

Conditions 36
Paths 1601

Size

Total Lines 183
Code Lines 98

Duplication

Lines 12
Ratio 6.56 %
Metric Value
cc 36
eloc 98
nc 1601
nop 0
dl 12
loc 183
rs 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Simple Machines Forum (SMF)
5
 *
6
 * @package SMF
7
 * @author Simple Machines http://www.simplemachines.org
8
 * @copyright 2016 Simple Machines and individual contributors
9
 * @license http://www.simplemachines.org/about/smf/license.php BSD
10
 *
11
 * @version 2.1 Beta 3
12
 */
13
14
$GLOBALS['current_smf_version'] = '2.1 Beta 3';
15
$GLOBALS['db_script_version'] = '2-1';
16
17
$GLOBALS['required_php_version'] = '5.3.8';
18
19
// Don't have PHP support, do you?
20
// ><html dir="ltr"><head><title>Error!</title></head><body>Sorry, this installer requires PHP!<div style="display: none;">
21
22
// Database info.
23
$databases = array(
24
	'mysqli' => array(
25
		'name' => 'MySQLi',
26
		'version' => '5.0.3',
27
		'version_check' => 'return min(mysqli_get_server_info($db_connection), mysqli_get_client_info());',
28
		'supported' => function_exists('mysqli_connect'),
29
		'default_user' => 'mysql.default_user',
30
		'default_password' => 'mysql.default_password',
31
		'default_host' => 'mysql.default_host',
32
		'default_port' => 'mysql.default_port',
33
		'utf8_support' => true,
34
		'utf8_version' => '5.0.3',
35
		'utf8_version_check' => 'return mysqli_get_server_info($db_connection);',
36
		'utf8_default' => true,
37
		'utf8_required' => true,
38
		'alter_support' => true,
39
		'validate_prefix' => create_function('&$value', '
40
			$value = preg_replace(\'~[^A-Za-z0-9_\$]~\', \'\', $value);
41
			return true;
42
		'),
43
	),
44
	'mysql' => array(
45
		'name' => 'MySQL',
46
		'version' => '5.0.3',
47
		'version_check' => 'return min(mysql_get_server_info(), mysql_get_client_info());',
48
		'supported' => function_exists('mysql_connect'),
49
		'default_user' => 'mysql.default_user',
50
		'default_password' => 'mysql.default_password',
51
		'default_host' => 'mysql.default_host',
52
		'default_port' => 'mysql.default_port',
53
		'utf8_support' => true,
54
		'utf8_version' => '5.0.3',
55
		'utf8_version_check' => 'return mysql_get_server_info();',
56
		'utf8_default' => true,
57
		'utf8_required' => true,
58
		'alter_support' => true,
59
		'validate_prefix' => create_function('&$value', '
60
			$value = preg_replace(\'~[^A-Za-z0-9_\$]~\', \'\', $value);
61
			return true;
62
		'),
63
	),
64
	'postgresql' => array(
65
		'name' => 'PostgreSQL',
66
		'version' => '8.0',
67
		'function_check' => 'pg_connect',
68
		'version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
69
		'supported' => function_exists('pg_connect'),
70
		'always_has_db' => true,
71
		'utf8_default' => true,
72
		'utf8_required' => true,
73
		'utf8_support' => true,
74
		'utf8_version' => '8.0',
75
		'utf8_version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
76
		'validate_prefix' => create_function('&$value', '
77
			$value = preg_replace(\'~[^A-Za-z0-9_\$]~\', \'\', $value);
78
79
			// Is it reserved?
80
			if ($value == \'pg_\')
81
				return $txt[\'error_db_prefix_reserved\'];
82
83
			// Is the prefix numeric?
84
			if (preg_match(\'~^\d~\', $value))
85
				return $txt[\'error_db_prefix_numeric\'];
86
87
			return true;
88
		'),
89
	),
90
);
91
92
// Initialize everything and load the language files.
93
initialize_inputs();
94
load_lang_file();
95
96
// This is what we are.
97
$installurl = $_SERVER['PHP_SELF'];
98
// This is where SMF is.
99
$smfsite = 'http://www.simplemachines.org/smf';
100
101
// All the steps in detail.
102
// Number,Name,Function,Progress Weight.
103
$incontext['steps'] = array(
104
	0 => array(1, $txt['install_step_welcome'], 'Welcome', 0),
105
	1 => array(2, $txt['install_step_writable'], 'CheckFilesWritable', 10),
106
	2 => array(3, $txt['install_step_databaseset'], 'DatabaseSettings', 15),
107
	3 => array(4, $txt['install_step_forum'], 'ForumSettings', 40),
108
	4 => array(5, $txt['install_step_databasechange'], 'DatabasePopulation', 15),
109
	5 => array(6, $txt['install_step_admin'], 'AdminAccount', 20),
110
	6 => array(7, $txt['install_step_delete'], 'DeleteInstall', 0),
111
);
112
113
// Default title...
114
$incontext['page_title'] = $txt['smf_installer'];
115
116
// What step are we on?
117
$incontext['current_step'] = isset($_GET['step']) ? (int) $_GET['step'] : 0;
118
119
// Loop through all the steps doing each one as required.
120
$incontext['overall_percent'] = 0;
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 View Code Duplication
		if (function_exists($step[2]) && $step[2]() === false)
0 ignored issues
show
Duplication introduced by
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...
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, $incontext;
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
	// Turn off magic quotes runtime and enable error reporting.
154
	if (function_exists('set_magic_quotes_runtime'))
155
		@set_magic_quotes_runtime(0);
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...
156
	error_reporting(E_ALL);
157
158
	// Fun.  Low PHP version...
159
	if (!isset($_GET))
160
	{
161
		$GLOBALS['_GET']['step'] = 0;
162
		return;
163
	}
164
165
	if (!isset($_GET['obgz']))
166
	{
167
		ob_start();
168
169
		if (ini_get('session.save_handler') == 'user')
170
			@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...
171
		if (function_exists('session_start'))
172
			@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...
173
	}
174
	else
175
	{
176
		ob_start('ob_gzhandler');
177
178
		if (ini_get('session.save_handler') == 'user')
179
			@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...
180
		session_start();
181
182
		if (!headers_sent())
183
			echo '<!DOCTYPE html>
184
<html>
185
	<head>
186
		<title>', htmlspecialchars($_GET['pass_string']), '</title>
187
	</head>
188
	<body style="background-color: #d4d4d4; margin-top: 16%; text-align: center; font-size: 16pt;">
189
		<strong>', htmlspecialchars($_GET['pass_string']), '</strong>
190
	</body>
191
</html>';
192
		exit;
193
	}
194
195
	// Anybody home?
196 View Code Duplication
	if (!isset($_GET['xml']))
0 ignored issues
show
Duplication introduced by
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...
197
	{
198
		$incontext['remote_files_available'] = false;
199
		$test = @fsockopen('www.simplemachines.org', 80, $errno, $errstr, 1);
200
		if ($test)
201
			$incontext['remote_files_available'] = true;
202
		@fclose($test);
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...
203
	}
204
205
	// Add slashes, as long as they aren't already being added.
206
	if (!function_exists('get_magic_quotes_gpc') || @get_magic_quotes_gpc() == 0)
207
		foreach ($_POST as $k => $v)
208
			if (strpos($k, 'password') === false && strpos($k, 'db_passwd') === false)
209
				$_POST[$k] = addslashes($v);
210
211
	// This is really quite simple; if ?delete is on the URL, delete the installer...
212
	if (isset($_GET['delete']))
213
	{
214
		if (isset($_SESSION['installer_temp_ftp']))
215
		{
216
			$ftp = new ftp_connection($_SESSION['installer_temp_ftp']['server'], $_SESSION['installer_temp_ftp']['port'], $_SESSION['installer_temp_ftp']['username'], $_SESSION['installer_temp_ftp']['password']);
217
			$ftp->chdir($_SESSION['installer_temp_ftp']['path']);
218
219
			$ftp->unlink('install.php');
220
221
			foreach ($databases as $key => $dummy)
222
			{
223
				$type = ($key == 'mysqli') ? 'mysql' : $key;
224
				$ftp->unlink('install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
225
			}
226
227
			$ftp->close();
228
229
			unset($_SESSION['installer_temp_ftp']);
230
		}
231
		else
232
		{
233
			@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...
234
235
			foreach ($databases as $key => $dummy)
236
			{
237
				$type = ($key == 'mysqli') ? 'mysql' : $key;
238
				@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...
239
			}
240
		}
241
242
		// Now just redirect to a blank.png...
243
		header('Location: http://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png');
244
		exit;
245
	}
246
247
	// PHP 5 might cry if we don't do this now.
248
	if (function_exists('date_default_timezone_set'))
249
	{
250
		$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
251
		date_default_timezone_set('Etc/GMT' . ($server_offset > 0 ? '+' : '') . ($server_offset / 3600));
252
	}
253
254
	// Force an integer step, defaulting to 0.
255
	$_GET['step'] = (int) @$_GET['step'];
256
}
257
258
// Load the list of language files, and the current language file.
259
function load_lang_file()
260
{
261
	global $txt, $incontext;
262
263
	$incontext['detected_languages'] = array();
264
265
	// Make sure the languages directory actually exists.
266
	if (file_exists(dirname(__FILE__) . '/Themes/default/languages'))
267
	{
268
		// Find all the "Install" language files in the directory.
269
		$dir = dir(dirname(__FILE__) . '/Themes/default/languages');
270
		while ($entry = $dir->read())
271
		{
272
			if (substr($entry, 0, 8) == 'Install.' && substr($entry, -4) == '.php')
273
				$incontext['detected_languages'][$entry] = ucfirst(substr($entry, 8, strlen($entry) - 12));
274
		}
275
		$dir->close();
276
	}
277
278
	// Didn't find any, show an error message!
279
	if (empty($incontext['detected_languages']))
280
	{
281
		// Let's not cache this message, eh?
282
		header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
283
		header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
284
		header('Cache-Control: no-cache');
285
286
		echo '<!DOCTYPE html>
287
<html>
288
	<head>
289
		<title>SMF Installer: Error!</title>
290
	</head>
291
	<body style="font-family: sans-serif;"><div style="width: 600px;">
292
		<h1 style="font-size: 14pt;">A critical error has occurred.</h1>
293
294
		<p>This installer was unable to find the installer\'s language file or files.  They should be found under:</p>
295
296
		<div style="margin: 1ex; font-family: monospace; font-weight: bold;">', dirname($_SERVER['PHP_SELF']) != '/' ? dirname($_SERVER['PHP_SELF']) : '', '/Themes/default/languages</div>
297
298
		<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>
299
		<p>If that doesn\'t help, please make sure this install.php file is in the same place as the Themes folder.</p>
300
301
		<p>If you continue to get this error message, feel free to <a href="http://support.simplemachines.org/">look to us for support</a>.</p>
302
	</div></body>
303
</html>';
304
		die;
305
	}
306
307
	// Override the language file?
308
	if (isset($_GET['lang_file']))
309
		$_SESSION['installer_temp_lang'] = $_GET['lang_file'];
310
	elseif (isset($GLOBALS['HTTP_GET_VARS']['lang_file']))
311
		$_SESSION['installer_temp_lang'] = $GLOBALS['HTTP_GET_VARS']['lang_file'];
312
313
	// Make sure it exists, if it doesn't reset it.
314
	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']))
315
	{
316
		// Use the first one...
317
		list ($_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
318
319
		// If we have english and some other language, use the other language.  We Americans hate english :P.
320
		if ($_SESSION['installer_temp_lang'] == 'Install.english.php' && count($incontext['detected_languages']) > 1)
321
			list (, $_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
322
	}
323
324
	// And now include the actual language file itself.
325
	require_once(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']);
326
}
327
328
// This handy function loads some settings and the like.
329
function load_database()
330
{
331
	global $db_prefix, $db_connection, $sourcedir;
332
	global $smcFunc, $modSettings, $db_type, $db_name, $db_user, $db_persist;
333
334
	if (empty($sourcedir))
335
		$sourcedir = dirname(__FILE__) . '/Sources';
336
337
	// Need this to check whether we need the database password.
338
	require(dirname(__FILE__) . '/Settings.php');
339
	if (!defined('SMF'))
340
		define('SMF', 1);
341
	if (empty($smcFunc))
342
		$smcFunc = array();
343
344
	$modSettings['disableQueryCheck'] = true;
345
346
	// Connect the database.
347
	if (!$db_connection)
348
	{
349
		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
350
		if (version_compare(PHP_VERSION, '5', '<'))
351
			require_once($sourcedir . '/Subs-Compat.php');
352
353
		$db_options = array('persist' => $db_persist);
354
		$port = '';
355
356
		// Figure out the port...
357
		if (!empty($_POST['db_port']))
358
		{
359
			if ($db_type == 'mysql' || $db_type == 'mysqli')
360
			{
361
				$port = ((int) $_POST['db_port'] == ini_get($db_type . 'default_port')) ? '' : (int) $_POST['db_port'];
362
			}
363 View Code Duplication
			elseif ($db_type == 'postgresql')
0 ignored issues
show
Duplication introduced by
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...
364
			{
365
				// PostgreSQL doesn't have a default port setting in php.ini, so just check against the default
366
				$port = ((int) $_POST['db_port'] == 5432) ? '' : (int) $_POST['db_port'];
367
			}
368
		}
369
370
		if (!empty($port))
371
			$db_options['port'] = $port;
372
373
		if (!$db_connection)
374
			$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $db_options);
0 ignored issues
show
Bug introduced by
The variable $db_server 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...
Bug introduced by
The variable $db_passwd 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...
375
	}
376
}
377
378
// This is called upon exiting the installer, for template etc.
379
function installExit($fallThrough = false)
380
{
381
	global $incontext, $installurl, $txt;
382
383
	// Send character set.
384
	header('Content-Type: text/html; charset=' . (isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8'));
385
386
	// We usually dump our templates out.
387
	if (!$fallThrough)
388
	{
389
		// The top install bit.
390
		template_install_above();
391
392
		// Call the template.
393
		if (isset($incontext['sub_template']))
394
		{
395
			$incontext['form_url'] = $installurl . '?step=' . $incontext['current_step'];
396
397
			call_user_func('template_' . $incontext['sub_template']);
398
		}
399
		// @todo REMOVE THIS!!
400
		else
401
		{
402
			if (function_exists('doStep' . $_GET['step']))
403
				call_user_func('doStep' . $_GET['step']);
404
		}
405
		// Show the footer.
406
		template_install_below();
407
	}
408
409
	// Bang - gone!
410
	die();
411
}
412
413
function Welcome()
414
{
415
	global $incontext, $txt, $databases, $installurl;
416
417
	$incontext['page_title'] = $txt['install_welcome'];
418
	$incontext['sub_template'] = 'welcome_message';
419
420
	// Done the submission?
421
	if (isset($_POST['contbutt']))
422
		return true;
423
424
	// See if we think they have already installed it?
425
	if (is_readable(dirname(__FILE__) . '/Settings.php'))
426
	{
427
		$probably_installed = 0;
428
		foreach (file(dirname(__FILE__) . '/Settings.php') as $line)
429
		{
430
			if (preg_match('~^\$db_passwd\s=\s\'([^\']+)\';$~', $line))
431
				$probably_installed++;
432
			if (preg_match('~^\$boardurl\s=\s\'([^\']+)\';~', $line) && !preg_match('~^\$boardurl\s=\s\'http://127\.0\.0\.1/smf\';~', $line))
433
				$probably_installed++;
434
		}
435
436
		if ($probably_installed == 2)
437
			$incontext['warning'] = $txt['error_already_installed'];
438
	}
439
440
	// Is some database support even compiled in?
441
	$incontext['supported_databases'] = array();
442
	foreach ($databases as $key => $db)
443
	{
444
		if ($db['supported'])
445
		{
446
			$type = ($key == 'mysqli') ? 'mysql' : $key;
447
			if (!file_exists(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql'))
448
			{
449
				$databases[$key]['supported'] = false;
450
				$notFoundSQLFile = true;
451
				$txt['error_db_script_missing'] = sprintf($txt['error_db_script_missing'], 'install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql');
452
			}
453
			else
454
			{
455
				$db_type = $key;
0 ignored issues
show
Unused Code introduced by
$db_type is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
456
				$incontext['supported_databases'][] = $db;
457
			}
458
		}
459
	}
460
461
	// Check the PHP version.
462
	if ((!function_exists('version_compare') || version_compare($GLOBALS['required_php_version'], PHP_VERSION, '>')))
463
		$error = 'error_php_too_low';
464
	// Make sure we have a supported database
465
	elseif (empty($incontext['supported_databases']))
466
		$error = empty($notFoundSQLFile) ? 'error_db_missing' : 'error_db_script_missing';
467
	// How about session support?  Some crazy sysadmin remove it?
468
	elseif (!function_exists('session_start'))
469
		$error = 'error_session_missing';
470
	// Make sure they uploaded all the files.
471
	elseif (!file_exists(dirname(__FILE__) . '/index.php'))
472
		$error = 'error_missing_files';
473
	// Very simple check on the session.save_path for Windows.
474
	// @todo Move this down later if they don't use database-driven sessions?
475
	elseif (@ini_get('session.save_path') == '/tmp' && substr(__FILE__, 1, 2) == ':\\')
476
		$error = 'error_session_save_path';
477
478
	// Since each of the three messages would look the same, anyway...
479
	if (isset($error))
480
		$incontext['error'] = $txt[$error];
481
482
	// Mod_security blocks everything that smells funny. Let SMF handle security.
483
	if (!fixModSecurity() && !isset($_GET['overmodsecurity']))
484
		$incontext['error'] = $txt['error_mod_security'] . '<br><br><a href="' . $installurl . '?overmodsecurity=true">' . $txt['error_message_click'] . '</a> ' . $txt['error_message_bad_try_again'];
485
486
	return false;
487
}
488
489
function CheckFilesWritable()
490
{
491
	global $txt, $incontext;
492
493
	$incontext['page_title'] = $txt['ftp_checking_writable'];
494
	$incontext['sub_template'] = 'chmod_files';
495
496
	$writable_files = array(
497
		'attachments',
498
		'avatars',
499
		'custom_avatar',
500
		'cache',
501
		'Packages',
502
		'Smileys',
503
		'Themes',
504
		'agreement.txt',
505
		'Settings.php',
506
		'Settings_bak.php'
507
	);
508
	foreach ($incontext['detected_languages'] as $lang => $temp)
509
		$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...
510
511
	// With mod_security installed, we could attempt to fix it with .htaccess.
512
	if (function_exists('apache_get_modules') && in_array('mod_security', apache_get_modules()))
513
		$writable_files[] = file_exists(dirname(__FILE__) . '/.htaccess') ? '.htaccess' : '.';
514
515
	$failed_files = array();
516
517
	// On linux, it's easy - just use is_writable!
518
	if (substr(__FILE__, 1, 2) != ':\\')
519
	{
520
		$incontext['systemos'] = 'linux';
521
522
		foreach ($writable_files as $file)
523
		{
524
			if (!is_writable(dirname(__FILE__) . '/' . $file))
525
			{
526
				@chmod(dirname(__FILE__) . '/' . $file, 0755);
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...
527
528
				// Well, 755 hopefully worked... if not, try 777.
529
				if (!is_writable(dirname(__FILE__) . '/' . $file) && !@chmod(dirname(__FILE__) . '/' . $file, 0777))
530
					$failed_files[] = $file;
531
			}
532
		}
533 View Code Duplication
		foreach ($extra_files as $file)
0 ignored issues
show
Bug introduced by
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...
Duplication introduced by
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...
534
			@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...
535
	}
536
	// Windows is trickier.  Let's try opening for r+...
537
	else
538
	{
539
		$incontext['systemos'] = 'windows';
540
541
		foreach ($writable_files as $file)
542
		{
543
			// Folders can't be opened for write... but the index.php in them can ;)
544
			if (is_dir(dirname(__FILE__) . '/' . $file))
545
				$file .= '/index.php';
546
547
			// Funny enough, chmod actually does do something on windows - it removes the read only attribute.
548
			@chmod(dirname(__FILE__) . '/' . $file, 0777);
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...
549
			$fp = @fopen(dirname(__FILE__) . '/' . $file, 'r+');
550
551
			// Hmm, okay, try just for write in that case...
552
			if (!is_resource($fp))
553
				$fp = @fopen(dirname(__FILE__) . '/' . $file, 'w');
554
555
			if (!is_resource($fp))
556
				$failed_files[] = $file;
557
558
			@fclose($fp);
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...
559
		}
560 View Code Duplication
		foreach ($extra_files as $file)
0 ignored issues
show
Duplication introduced by
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...
561
			@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...
562
	}
563
564
	$failure = count($failed_files) >= 1;
565
566
	if (!isset($_SERVER))
567
		return !$failure;
568
569
	// Put the list into context.
570
	$incontext['failed_files'] = $failed_files;
571
572
	// It's not going to be possible to use FTP on windows to solve the problem...
573
	if ($failure && substr(__FILE__, 1, 2) == ':\\')
574
	{
575
		$incontext['error'] = $txt['error_windows_chmod'] . '
576
					<ul style="margin: 2.5ex; font-family: monospace;">
577
						<li>' . implode('</li>
578
						<li>', $failed_files) . '</li>
579
					</ul>';
580
581
		return false;
582
	}
583
	// We're going to have to use... FTP!
584
	elseif ($failure)
585
	{
586
		// Load any session data we might have...
587 View Code Duplication
		if (!isset($_POST['ftp_username']) && isset($_SESSION['installer_temp_ftp']))
0 ignored issues
show
Duplication introduced by
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...
588
		{
589
			$_POST['ftp_server'] = $_SESSION['installer_temp_ftp']['server'];
590
			$_POST['ftp_port'] = $_SESSION['installer_temp_ftp']['port'];
591
			$_POST['ftp_username'] = $_SESSION['installer_temp_ftp']['username'];
592
			$_POST['ftp_password'] = $_SESSION['installer_temp_ftp']['password'];
593
			$_POST['ftp_path'] = $_SESSION['installer_temp_ftp']['path'];
594
		}
595
596
		$incontext['ftp_errors'] = array();
597
598 View Code Duplication
		if (isset($_POST['ftp_username']))
0 ignored issues
show
Duplication introduced by
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...
599
		{
600
			$ftp = new ftp_connection($_POST['ftp_server'], $_POST['ftp_port'], $_POST['ftp_username'], $_POST['ftp_password']);
601
602
			if ($ftp->error === false)
0 ignored issues
show
Bug introduced by
The property error cannot be accessed from this context as it is declared private in class ftp_connection.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
603
			{
604
				// Try it without /home/abc just in case they messed up.
605
				if (!$ftp->chdir($_POST['ftp_path']))
606
				{
607
					$incontext['ftp_errors'][] = $ftp->last_message;
0 ignored issues
show
Bug introduced by
The property last_message cannot be accessed from this context as it is declared private in class ftp_connection.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
608
					$ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $_POST['ftp_path']));
609
				}
610
			}
611
		}
612
613
		if (!isset($ftp) || $ftp->error !== false)
0 ignored issues
show
Bug introduced by
The property error cannot be accessed from this context as it is declared private in class ftp_connection.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
614
		{
615
			if (!isset($ftp))
616
				$ftp = new ftp_connection(null);
617
			// Save the error so we can mess with listing...
618
			elseif ($ftp->error !== false && empty($incontext['ftp_errors']) && !empty($ftp->last_message))
0 ignored issues
show
Bug introduced by
The property error cannot be accessed from this context as it is declared private in class ftp_connection.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
Bug introduced by
The property last_message cannot be accessed from this context as it is declared private in class ftp_connection.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
619
				$incontext['ftp_errors'][] = $ftp->last_message;
0 ignored issues
show
Bug introduced by
The property last_message cannot be accessed from this context as it is declared private in class ftp_connection.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
620
621
			list ($username, $detect_path, $found_path) = $ftp->detect_path(dirname(__FILE__));
622
623
			if (empty($_POST['ftp_path']) && $found_path)
624
				$_POST['ftp_path'] = $detect_path;
625
626
			if (!isset($_POST['ftp_username']))
627
				$_POST['ftp_username'] = $username;
628
629
			// Set the username etc, into context.
630
			$incontext['ftp'] = array(
631
				'server' => isset($_POST['ftp_server']) ? $_POST['ftp_server'] : 'localhost',
632
				'port' => isset($_POST['ftp_port']) ? $_POST['ftp_port'] : '21',
633
				'username' => isset($_POST['ftp_username']) ? $_POST['ftp_username'] : '',
634
				'path' => isset($_POST['ftp_path']) ? $_POST['ftp_path'] : '/',
635
				'path_msg' => !empty($found_path) ? $txt['ftp_path_found_info'] : $txt['ftp_path_info'],
636
			);
637
638
			return false;
639
		}
640
		else
641
		{
642
			$_SESSION['installer_temp_ftp'] = array(
643
				'server' => $_POST['ftp_server'],
644
				'port' => $_POST['ftp_port'],
645
				'username' => $_POST['ftp_username'],
646
				'password' => $_POST['ftp_password'],
647
				'path' => $_POST['ftp_path']
648
			);
649
650
			$failed_files_updated = array();
651
652
			foreach ($failed_files as $file)
653
			{
654
				if (!is_writable(dirname(__FILE__) . '/' . $file))
655
					$ftp->chmod($file, 0755);
656
				if (!is_writable(dirname(__FILE__) . '/' . $file))
657
					$ftp->chmod($file, 0777);
658
				if (!is_writable(dirname(__FILE__) . '/' . $file))
659
				{
660
					$failed_files_updated[] = $file;
661
					$incontext['ftp_errors'][] = rtrim($ftp->last_message) . ' -> ' . $file . "\n";
0 ignored issues
show
Bug introduced by
The property last_message cannot be accessed from this context as it is declared private in class ftp_connection.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
662
				}
663
			}
664
665
			$ftp->close();
666
667
			// Are there any errors left?
668
			if (count($failed_files_updated) >= 1)
669
			{
670
				// Guess there are...
671
				$incontext['failed_files'] = $failed_files_updated;
672
673
				// Set the username etc, into context.
674
				$incontext['ftp'] = $_SESSION['installer_temp_ftp'] += array(
675
					'path_msg' => $txt['ftp_path_info'],
676
				);
677
678
				return false;
679
			}
680
		}
681
	}
682
683
	return true;
684
}
685
686
function DatabaseSettings()
687
{
688
	global $txt, $databases, $incontext, $smcFunc, $sourcedir;
689
690
	$incontext['sub_template'] = 'database_settings';
691
	$incontext['page_title'] = $txt['db_settings'];
692
	$incontext['continue'] = 1;
693
694
	// Set up the defaults.
695
	$incontext['db']['server'] = 'localhost';
696
	$incontext['db']['user'] = '';
697
	$incontext['db']['name'] = '';
698
	$incontext['db']['pass'] = '';
699
	$incontext['db']['type'] = '';
700
	$incontext['supported_databases'] = array();
701
702
	$foundOne = false;
703
	foreach ($databases as $key => $db)
704
	{
705
		// Override with the defaults for this DB if appropriate.
706
		if ($db['supported'])
707
		{
708
			$incontext['supported_databases'][$key] = $db;
709
710
			if (!$foundOne)
711
			{
712
				if (isset($db['default_host']))
713
					$incontext['db']['server'] = ini_get($db['default_host']) or $incontext['db']['server'] = 'localhost';
714
				if (isset($db['default_user']))
715
				{
716
					$incontext['db']['user'] = ini_get($db['default_user']);
717
					$incontext['db']['name'] = ini_get($db['default_user']);
718
				}
719
				if (isset($db['default_password']))
720
					$incontext['db']['pass'] = ini_get($db['default_password']);
721
722
				// For simplicity and less confusion, leave the port blank by default
723
				$incontext['db']['port'] = '';
724
725
				$incontext['db']['type'] = $key;
726
				$foundOne = true;
727
			}
728
		}
729
	}
730
731
	// Override for repost.
732
	if (isset($_POST['db_user']))
733
	{
734
		$incontext['db']['user'] = $_POST['db_user'];
735
		$incontext['db']['name'] =  $_POST['db_name'];
736
		$incontext['db']['server'] = $_POST['db_server'];
737
		$incontext['db']['prefix'] = $_POST['db_prefix'];
738
739
		if (!empty($_POST['db_port']))
740
			$incontext['db']['port'] = $_POST['db_port'];
741
	}
742
	else
743
	{
744
		$incontext['db']['prefix'] = 'smf_';
745
	}
746
747
	// Are we submitting?
748
	if (isset($_POST['db_type']))
749
	{
750
		// What type are they trying?
751
		$db_type = preg_replace('~[^A-Za-z0-9]~', '', $_POST['db_type']);
752
		$db_prefix = $_POST['db_prefix'];
753
		// Validate the prefix.
754
		$valid_prefix = $databases[$db_type]['validate_prefix']($db_prefix);
755
756
		if ($valid_prefix !== true)
757
		{
758
			$incontext['error'] = $valid_prefix;
759
			return false;
760
		}
761
762
		// Take care of these variables...
763
		$vars = array(
764
			'db_type' => $db_type,
765
			'db_name' => $_POST['db_name'],
766
			'db_user' => $_POST['db_user'],
767
			'db_passwd' => isset($_POST['db_passwd']) ? $_POST['db_passwd'] : '',
768
			'db_server' => $_POST['db_server'],
769
			'db_prefix' => $db_prefix,
770
			// The cookiename is special; we want it to be the same if it ever needs to be reinstalled with the same info.
771
			'cookiename' => 'SMFCookie' . abs(crc32($_POST['db_name'] . preg_replace('~[^A-Za-z0-9_$]~', '', $_POST['db_prefix'])) % 1000),
772
		);
773
774
		// Only set the port if we're not using the default
775
		if (!empty($_POST['db_port']))
776
		{
777
			// For MySQL, we can get the "default port" from PHP. PostgreSQL has no such option though.
778
			if (($db_type == 'mysql' || $db_type == 'mysqli') && $_POST['db_port'] != ini_get($db_type . '.default_port'))
779
				$vars['db_port'] == (int) $_POST['db_port'];
780 View Code Duplication
			elseif ($db_type == 'postgresql' && $_POST['db_port'] != 5432)
0 ignored issues
show
Duplication introduced by
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...
781
				$vars['db_port'] == (int) $_POST['db_port'];
782
		}
783
784
		// God I hope it saved!
785 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
0 ignored issues
show
Duplication introduced by
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...
786
		{
787
			$incontext['error'] = $txt['error_windows_chmod'];
788
			return false;
789
		}
790
791
		// Make sure it works.
792
		require(dirname(__FILE__) . '/Settings.php');
793
794
		if (empty($sourcedir))
795
			$sourcedir = dirname(__FILE__) . '/Sources';
796
797
		// Better find the database file!
798
		if (!file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php'))
799
		{
800
			$incontext['error'] = sprintf($txt['error_db_file'], 'Subs-Db-' . $db_type . '.php');
801
			return false;
802
		}
803
804
		// Now include it for database functions!
805
		define('SMF', 1);
806
		$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...
807
		if (empty($smcFunc))
808
			$smcFunc = array();
809
810
			require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
811
812
		// What - running PHP4? The shame!
813
		if (version_compare(PHP_VERSION, '5', '<'))
814
			require_once($sourcedir . '/Subs-Compat.php');
815
816
		// Attempt a connection.
817
		$needsDB = !empty($databases[$db_type]['always_has_db']);
818
		$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('non_fatal' => true, 'dont_select_db' => !$needsDB));
0 ignored issues
show
Bug introduced by
The variable $db_server 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...
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
Bug introduced by
The variable $db_user seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
Bug introduced by
The variable $db_passwd 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...
819
820
		// No dice?  Let's try adding the prefix they specified, just in case they misread the instructions ;)
821
		if ($db_connection == null)
822
		{
823
			$db_error = @$smcFunc['db_error']();
824
825
			$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));
0 ignored issues
show
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
Bug introduced by
The variable $db_user seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
826
			if ($db_connection != null)
827
			{
828
				$db_user = $_POST['db_prefix'] . $db_user;
0 ignored issues
show
Bug introduced by
The variable $db_user seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
829
				updateSettingsFile(array('db_user' => $db_user));
830
			}
831
		}
832
833
		// Still no connection?  Big fat error message :P.
834
		if (!$db_connection)
835
		{
836
			$incontext['error'] = $txt['error_db_connect'] . '<div style="margin: 2.5ex; font-family: monospace;"><strong>' . $db_error . '</strong></div>';
0 ignored issues
show
Bug introduced by
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...
837
			return false;
838
		}
839
840
		// Do they meet the install requirements?
841
		// @todo Old client, new server?
842
		if (version_compare($databases[$db_type]['version'], preg_replace('~^\D*|\-.+?$~', '', eval($databases[$db_type]['version_check']))) > 0)
843
		{
844
			$incontext['error'] = $txt['error_db_too_low'];
845
			return false;
846
		}
847
848
		// Let's try that database on for size... assuming we haven't already lost the opportunity.
849
		if ($db_name != '' && !$needsDB)
850
		{
851
			$smcFunc['db_query']('', "
852
				CREATE DATABASE IF NOT EXISTS `$db_name`",
0 ignored issues
show
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
853
				array(
854
					'security_override' => true,
855
					'db_error_skip' => true,
856
				),
857
				$db_connection
858
			);
859
860
			// Okay, let's try the prefix if it didn't work...
861
			if (!$smcFunc['db_select_db']($db_name, $db_connection) && $db_name != '')
0 ignored issues
show
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
862
			{
863
				$smcFunc['db_query']('', "
864
					CREATE DATABASE IF NOT EXISTS `$_POST[db_prefix]$db_name`",
0 ignored issues
show
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
865
					array(
866
						'security_override' => true,
867
						'db_error_skip' => true,
868
					),
869
					$db_connection
870
				);
871
872
				if ($smcFunc['db_select_db']($_POST['db_prefix'] . $db_name, $db_connection))
0 ignored issues
show
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
873
				{
874
					$db_name = $_POST['db_prefix'] . $db_name;
0 ignored issues
show
Bug introduced by
The variable $db_name seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
875
					updateSettingsFile(array('db_name' => $db_name));
876
				}
877
			}
878
879
			// Okay, now let's try to connect...
880
			if (!$smcFunc['db_select_db']($db_name, $db_connection))
881
			{
882
				$incontext['error'] = sprintf($txt['error_db_database'], $db_name);
0 ignored issues
show
Bug introduced by
The variable $db_name 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...
883
				return false;
884
			}
885
		}
886
887
		return true;
888
	}
889
890
	return false;
891
}
892
893
// Let's start with basic forum type settings.
894
function ForumSettings()
895
{
896
	global $txt, $incontext, $databases, $db_type, $db_connection;
897
898
	$incontext['sub_template'] = 'forum_settings';
899
	$incontext['page_title'] = $txt['install_settings'];
900
901
	// Let's see if we got the database type correct.
902
	if (isset($_POST['db_type'], $databases[$_POST['db_type']]))
903
		$db_type = $_POST['db_type'];
904
905
	// Else we'd better be able to get the connection.
906
	else
907
		load_database();
908
909
	$db_type = isset($_POST['db_type']) ? $_POST['db_type'] : $db_type;
910
911
	// What host and port are we on?
912
	$host = empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST'];
913
914
	// Now, to put what we've learned together... and add a path.
915
	$incontext['detected_url'] = 'http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . $host . substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
916
917
	// Check if the database sessions will even work.
918
	$incontext['test_dbsession'] = (ini_get('session.auto_start') != 1);
919
	$incontext['utf8_default'] = $databases[$db_type]['utf8_default'];
920
	$incontext['utf8_required'] = $databases[$db_type]['utf8_required'];
921
922
	$incontext['continue'] = 1;
923
924
	// Submitting?
925
	if (isset($_POST['boardurl']))
926
	{
927 View Code Duplication
		if (substr($_POST['boardurl'], -10) == '/index.php')
0 ignored issues
show
Duplication introduced by
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...
928
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -10);
929
		elseif (substr($_POST['boardurl'], -1) == '/')
930
			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -1);
931 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
Duplication introduced by
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...
932
			$_POST['boardurl'] = 'http://' . $_POST['boardurl'];
933
934
		// Save these variables.
935
		$vars = array(
936
			'boardurl' => $_POST['boardurl'],
937
			'boarddir' => addslashes(dirname(__FILE__)),
938
			'sourcedir' => addslashes(dirname(__FILE__)) . '/Sources',
939
			'cachedir' => addslashes(dirname(__FILE__)) . '/cache',
940
			'mbname' => strtr($_POST['mbname'], array('\"' => '"')),
941
			'language' => substr($_SESSION['installer_temp_lang'], 8, -4),
942
			'image_proxy_secret' => substr(sha1(mt_rand()), 0, 20),
943
			'image_proxy_enabled' => !empty($_POST['force_ssl']),
944
		);
945
946
		// Must save!
947 View Code Duplication
		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
0 ignored issues
show
Duplication introduced by
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...
948
		{
949
			$incontext['error'] = $txt['error_windows_chmod'];
950
			return false;
951
		}
952
953
		// Make sure it works.
954
		require(dirname(__FILE__) . '/Settings.php');
955
956
		// UTF-8 requires a setting to override the language charset.
957
		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'])))
958
		{
959
			if (!empty($databases[$db_type]['utf8_version_check']) && version_compare($databases[$db_type]['utf8_version'], preg_replace('~\-.+?$~', '', eval($databases[$db_type]['utf8_version_check'])), '>'))
960
			{
961
				$incontext['error'] = sprintf($txt['error_utf8_version'], $databases[$db_type]['utf8_version']);
962
				return false;
963
			}
964
			else
965
				// Set the character set here.
966
				updateSettingsFile(array('db_character_set' => 'utf8'));
967
		}
968
969
		// Good, skip on.
970
		return true;
971
	}
972
973
	return false;
974
}
975
976
// Step one: Do the SQL thang.
977
function DatabasePopulation()
978
{
979
	global $db_character_set, $txt, $db_connection, $smcFunc, $databases, $modSettings, $db_type, $db_prefix, $incontext, $db_name, $boardurl;
980
981
	$incontext['sub_template'] = 'populate_database';
982
	$incontext['page_title'] = $txt['db_populate'];
983
	$incontext['continue'] = 1;
984
985
	// Already done?
986
	if (isset($_POST['pop_done']))
987
		return true;
988
989
	// Reload settings.
990
	require(dirname(__FILE__) . '/Settings.php');
991
	load_database();
992
993
	// Before running any of the queries, let's make sure another version isn't already installed.
994
	$result = $smcFunc['db_query']('', '
995
		SELECT variable, value
996
		FROM {db_prefix}settings',
997
		array(
998
			'db_error_skip' => true,
999
		)
1000
	);
1001
	$newSettings = array();
1002
	$modSettings = array();
1003
	if ($result !== false)
1004
	{
1005 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($result))
0 ignored issues
show
Duplication introduced by
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...
1006
			$modSettings[$row['variable']] = $row['value'];
1007
		$smcFunc['db_free_result']($result);
1008
1009
		// Do they match?  If so, this is just a refresh so charge on!
1010
		if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] != $GLOBALS['current_smf_version'])
1011
		{
1012
			$incontext['error'] = $txt['error_versions_do_not_match'];
1013
			return false;
1014
		}
1015
	}
1016
	$modSettings['disableQueryCheck'] = true;
1017
1018
	// If doing UTF8, select it. PostgreSQL requires passing it as a string...
1019
	if (!empty($db_character_set) && $db_character_set == 'utf8' && !empty($databases[$db_type]['utf8_support']))
1020
		$smcFunc['db_query']('', '
1021
			SET NAMES {'. ($db_type == 'postgresql' ? 'string' : 'raw') . ':utf8}',
1022
			array(
1023
				'db_error_skip' => true,
1024
				'utf8' => 'utf8',
1025
			)
1026
		);
1027
1028
	// Windows likes to leave the trailing slash, which yields to C:\path\to\SMF\/attachments...
1029
	if (substr(__DIR__, -1) == '\\')
1030
		$attachdir = __DIR__ . 'attachments';
1031
	else
1032
		$attachdir = __DIR__ . '/attachments';
1033
1034
	$replaces = array(
1035
		'{$db_prefix}' => $db_prefix,
1036
		'{$attachdir}' => json_encode(array(1 => $smcFunc['db_escape_string']($attachdir))),
1037
		'{$boarddir}' => $smcFunc['db_escape_string'](dirname(__FILE__)),
1038
		'{$boardurl}' => $boardurl,
1039
		'{$enableCompressedOutput}' => isset($_POST['compress']) ? '1' : '0',
1040
		'{$databaseSession_enable}' => isset($_POST['dbsession']) ? '1' : '0',
1041
		'{$smf_version}' => $GLOBALS['current_smf_version'],
1042
		'{$current_time}' => time(),
1043
		'{$sched_task_offset}' => 82800 + mt_rand(0, 86399),
1044
		'{$registration_method}' => isset($_POST['reg_mode']) ? $_POST['reg_mode'] : 0,
1045
	);
1046
1047
	foreach ($txt as $key => $value)
1048
	{
1049
		if (substr($key, 0, 8) == 'default_')
1050
			$replaces['{$' . $key . '}'] = $smcFunc['db_escape_string']($value);
1051
	}
1052
	$replaces['{$default_reserved_names}'] = strtr($replaces['{$default_reserved_names}'], array('\\\\n' => '\\n'));
1053
1054
	// MySQL-specific stuff - storage engine and UTF8 handling
1055
	if (substr($db_type, 0, 5) == 'mysql')
1056
	{
1057
		// Just in case the query fails for some reason...
1058
		$engines = array();
1059
1060
		// Figure out storage engines - what do we have, etc.
1061
		$get_engines = $smcFunc['db_query']('', 'SHOW ENGINES', array());
1062
1063 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($get_engines))
0 ignored issues
show
Duplication introduced by
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...
1064
		{
1065
			if ($row['Support'] == 'YES' || $row['Support'] == 'DEFAULT')
1066
				$engines[] = $row['Engine'];
1067
		}
1068
1069
		// Done with this now
1070
		$smcFunc['db_free_result']($get_engines);
1071
1072
		// InnoDB is better, so use it if possible...
1073
		$has_innodb = in_array('InnoDB', $engines);
1074
		$replaces['{$engine}'] = $has_innodb ? 'InnoDB' : 'MyISAM';
1075
		$replaces['{$memory}'] = (!$has_innodb && in_array('MEMORY', $engines)) ? 'MEMORY' : $replaces['{$engine}'];
1076
1077
		// If the UTF-8 setting was enabled, add it to the table definitions.
1078
		if (!empty($databases[$db_type]['utf8_support']) && (!empty($databases[$db_type]['utf8_required']) || isset($_POST['utf8'])))
1079
		{
1080
			$replaces['{$engine}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1081
			$replaces['{$memory}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1082
		}
1083
1084
		// One last thing - if we don't have InnoDB, we can't do transactions...
1085
		if (!$has_innodb)
1086
		{
1087
			$replaces['START TRANSACTION;'] = '';
1088
			$replaces['COMMIT;'] = '';
1089
		}
1090
	} 
1091
	else 
1092
	{
1093
		$has_innodb = false;
1094
	}
1095
1096
	// PostgreSQL-specific stuff - unlogged table
1097
	if ($db_type == 'postgresql')
1098
	{
1099
		$result = $smcFunc['db_query']('', '
1100
			SHOW server_version_num'
1101
		);
1102
		if ($result !== false)
1103
		{
1104
			while ($row = $smcFunc['db_fetch_assoc']($result))
1105
				$pg_version = $row['server_version_num'];
1106
			$smcFunc['db_free_result']($result);
1107
		}
1108
		
1109
		if(isset($pg_version) && $pg_version >= 90100)
1110
			$replaces['{$unlogged}'] = 'UNLOGGED';
1111
		else
1112
			$replaces['{$unlogged}'] = '';
1113
	}
1114
1115
	// Read in the SQL.  Turn this on and that off... internationalize... etc.
1116
	$type = ($db_type == 'mysqli' ? 'mysql' : $db_type);
1117
	$sql_lines = explode("\n", strtr(implode(' ', file(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql')), $replaces));
1118
1119
	// Execute the SQL.
1120
	$current_statement = '';
1121
	$exists = array();
1122
	$incontext['failures'] = array();
1123
	$incontext['sql_results'] = array(
1124
		'tables' => 0,
1125
		'inserts' => 0,
1126
		'table_dups' => 0,
1127
		'insert_dups' => 0,
1128
	);
1129
	foreach ($sql_lines as $count => $line)
1130
	{
1131
		// No comments allowed!
1132
		if (substr(trim($line), 0, 1) != '#')
1133
			$current_statement .= "\n" . rtrim($line);
1134
1135
		// Is this the end of the query string?
1136
		if (empty($current_statement) || (preg_match('~;[\s]*$~s', $line) == 0 && $count != count($sql_lines)))
1137
			continue;
1138
1139
		// Does this table already exist?  If so, don't insert more data into it!
1140
		if (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) != 0 && in_array($match[1], $exists))
1141
		{
1142
			preg_match_all('~\)[,;]~', $current_statement, $matches);
1143 View Code Duplication
			if (!empty($matches[0]))
0 ignored issues
show
Duplication introduced by
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...
1144
				$incontext['sql_results']['insert_dups'] += count($matches[0]);
1145
			else
1146
				$incontext['sql_results']['insert_dups']++;
1147
1148
			$current_statement = '';
1149
			continue;
1150
		}
1151
1152
		if ($smcFunc['db_query']('', $current_statement, array('security_override' => true, 'db_error_skip' => true), $db_connection) === false)
1153
		{
1154
			// Use the appropriate function based on the DB type
1155
			if ($db_type == 'mysql' || $db_type =='mysqli')
1156
				$db_errorno = $db_type . '_errno';
1157
1158
			// Error 1050: Table already exists!
1159
			// @todo Needs to be made better!
1160
			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
Bug introduced by
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...
1161
			{
1162
				$exists[] = $match[1];
1163
				$incontext['sql_results']['table_dups']++;
1164
			}
1165
			// Don't error on duplicate indexes (or duplicate operators in PostgreSQL.)
1166
			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)))
1167
			{
1168
				// MySQLi requires a connection object. It's optional with MySQL and Postgres
1169
				$incontext['failures'][$count] = $smcFunc['db_error']($db_connection);
1170
			}
1171
		}
1172
		else
1173
		{
1174
			if (preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1175
				$incontext['sql_results']['tables']++;
1176
			elseif (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1177
			{
1178
				preg_match_all('~\)[,;]~', $current_statement, $matches);
1179 View Code Duplication
				if (!empty($matches[0]))
0 ignored issues
show
Duplication introduced by
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...
1180
					$incontext['sql_results']['inserts'] += count($matches[0]);
1181
				else
1182
					$incontext['sql_results']['inserts']++;
1183
			}
1184
		}
1185
1186
		$current_statement = '';
1187
1188
		// Wait, wait, I'm still working here!
1189
		set_time_limit(60);
1190
	}
1191
1192
	// Sort out the context for the SQL.
1193
	foreach ($incontext['sql_results'] as $key => $number)
1194
	{
1195
		if ($number == 0)
1196
			unset($incontext['sql_results'][$key]);
1197
		else
1198
			$incontext['sql_results'][$key] = sprintf($txt['db_populate_' . $key], $number);
1199
	}
1200
1201
	// Make sure UTF will be used globally.
1202
	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'])))
1203
		$newSettings[] = array('global_character_set', 'UTF-8');
1204
1205
	// Maybe we can auto-detect better cookie settings?
1206
	preg_match('~^http[s]?://([^\.]+?)([^/]*?)(/.*)?$~', $boardurl, $matches);
1207
	if (!empty($matches))
1208
	{
1209
		// Default = both off.
1210
		$localCookies = false;
1211
		$globalCookies = false;
1212
1213
		// Okay... let's see.  Using a subdomain other than www.? (not a perfect check.)
1214
		if ($matches[2] != '' && (strpos(substr($matches[2], 1), '.') === false || in_array($matches[1], array('forum', 'board', 'community', 'forums', 'support', 'chat', 'help', 'talk', 'boards', 'www'))))
1215
			$globalCookies = true;
1216
		// If there's a / in the middle of the path, or it starts with ~... we want local.
1217
		if (isset($matches[3]) && strlen($matches[3]) > 3 && (substr($matches[3], 0, 2) == '/~' || strpos(substr($matches[3], 1), '/') !== false))
1218
			$localCookies = true;
1219
1220
		if ($globalCookies)
1221
			$newSettings[] = array('globalCookies', '1');
1222
		if ($localCookies)
1223
			$newSettings[] = array('localCookies', '1');
1224
	}
1225
1226
	// Are we allowing stat collection?
1227
	if (isset($_POST['stats']) && strpos($_POST['boardurl'], 'http://localhost') !== 0)
1228
	{
1229
		// Attempt to register the site etc.
1230
		$fp = @fsockopen("www.simplemachines.org", 80, $errno, $errstr);
1231
		if ($fp)
1232
		{
1233
			$out = "GET /smf/stats/register_stats.php?site=" . base64_encode($_POST['boardurl']) . " HTTP/1.1\r\n";
1234
			$out .= "Host: www.simplemachines.org\r\n";
1235
			$out .= "Connection: Close\r\n\r\n";
1236
			fwrite($fp, $out);
1237
1238
			$return_data = '';
1239
			while (!feof($fp))
1240
				$return_data .= fgets($fp, 128);
1241
1242
			fclose($fp);
1243
1244
			// Get the unique site ID.
1245
			preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1246
1247
			if (!empty($ID[1]))
1248
				$newSettings[] = array('allow_sm_stats', $ID[1]);
1249
		}
1250
	}
1251
1252
	// Are we enabling SSL?
1253
	if (!empty($_POST['force_ssl']))
1254
		$newSettings[] = array('force_ssl', 2);
1255
1256
	// As of PHP 5.1, setting a timezone is required.
1257
	if (!isset($modSettings['default_timezone']) && function_exists('date_default_timezone_set'))
1258
	{
1259
		$server_offset = mktime(0, 0, 0, 1, 1, 1970);
1260
		$timezone_id = 'Etc/GMT' . ($server_offset > 0 ? '+' : '') . ($server_offset / 3600);
1261
		if (date_default_timezone_set($timezone_id))
1262
			$newSettings[] = array('default_timezone', $timezone_id);
1263
	}
1264
1265
	if (!empty($newSettings))
1266
	{
1267
		$smcFunc['db_insert']('replace',
1268
			'{db_prefix}settings',
1269
			array('variable' => 'string-255', 'value' => 'string-65534'),
1270
			$newSettings,
1271
			array('variable')
1272
		);
1273
	}
1274
1275
	// Let's optimize those new tables, but not on InnoDB, ok?
1276
	if (!$has_innodb)
1277
	{
1278
		db_extend();
1279
		$tables = $smcFunc['db_list_tables']($db_name, $db_prefix . '%');
1280
		foreach ($tables as $table)
1281
		{
1282
			$smcFunc['db_optimize_table']($table) != -1 or $db_messed = true;
1283
1284
			if (!empty($db_messed))
1285
			{
1286
				$incontext['failures'][-1] = $smcFunc['db_error']();
1287
				break;
1288
			}
1289
		}
1290
	}
1291
	
1292
	// MySQL specific stuff 
1293
	if (substr($db_type, 0, 5) != 'mysql')
1294
		return false;
1295
	
1296
	// Find database user privileges.
1297
	$privs = array();
1298
	$get_privs = $smcFunc['db_query']('', 'SHOW PRIVILEGES', array());
1299
	while ($row = $smcFunc['db_fetch_assoc']($get_privs))
1300
	{
1301
		if ($row['Privilege'] == 'Alter')
1302
			$privs[] = $row['Privilege'];
1303
	}
1304
	$smcFunc['db_free_result']($get_privs);
1305
1306
	// Check for the ALTER privilege.
1307
	if (!empty($databases[$db_type]['alter_support']) && !in_array('Alter', $privs))
1308
	{
1309
		$incontext['error'] = $txt['error_db_alter_priv'];
1310
		return false;
1311
	}
1312
1313
	if (!empty($exists))
1314
	{
1315
		$incontext['page_title'] = $txt['user_refresh_install'];
1316
		$incontext['was_refresh'] = true;
1317
	}
1318
1319
	return false;
1320
}
1321
1322
// Ask for the administrator login information.
1323
function AdminAccount()
1324
{
1325
	global $txt, $db_type, $db_connection, $smcFunc, $incontext, $db_prefix, $db_passwd, $sourcedir, $db_character_set;
1326
1327
	$incontext['sub_template'] = 'admin_account';
1328
	$incontext['page_title'] = $txt['user_settings'];
1329
	$incontext['continue'] = 1;
1330
1331
	// Skipping?
1332
	if (!empty($_POST['skip']))
1333
		return true;
1334
1335
	// Need this to check whether we need the database password.
1336
	require(dirname(__FILE__) . '/Settings.php');
1337
	load_database();
1338
1339
	require_once($sourcedir . '/Subs-Auth.php');
1340
1341
	// We need this to properly hash the password for Admin
1342
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' :
1343
		create_function('$string', '
1344
			global $sourcedir;
1345
			if (function_exists(\'mb_strtolower\'))
1346
				return mb_strtolower($string, \'UTF-8\');
1347
			require_once($sourcedir . \'/Subs-Charset.php\');
1348
			return utf8_strtolower($string);
1349
		');
1350
1351
	if (!isset($_POST['username']))
1352
		$_POST['username'] = '';
1353
	if (!isset($_POST['email']))
1354
		$_POST['email'] = '';
1355
	if (!isset($_POST['server_email']))
1356
		$_POST['server_email'] = '';
1357
1358
	$incontext['username'] = htmlspecialchars(stripslashes($_POST['username']));
1359
	$incontext['email'] = htmlspecialchars(stripslashes($_POST['email']));
1360
	$incontext['server_email'] = htmlspecialchars(stripslashes($_POST['server_email']));
1361
1362
	$incontext['require_db_confirm'] = empty($db_type);
1363
1364
	// Only allow skipping if we think they already have an account setup.
1365
	$request = $smcFunc['db_query']('', '
1366
		SELECT id_member
1367
		FROM {db_prefix}members
1368
		WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
1369
		LIMIT 1',
1370
		array(
1371
			'db_error_skip' => true,
1372
			'admin_group' => 1,
1373
		)
1374
	);
1375
	if ($smcFunc['db_num_rows']($request) != 0)
1376
		$incontext['skip'] = 1;
1377
	$smcFunc['db_free_result']($request);
1378
1379
	// Trying to create an account?
1380
	if (isset($_POST['password1']) && !empty($_POST['contbutt']))
1381
	{
1382
		// Wrong password?
1383
		if ($incontext['require_db_confirm'] && $_POST['password3'] != $db_passwd)
1384
		{
1385
			$incontext['error'] = $txt['error_db_connect'];
1386
			return false;
1387
		}
1388
		// Not matching passwords?
1389
		if ($_POST['password1'] != $_POST['password2'])
1390
		{
1391
			$incontext['error'] = $txt['error_user_settings_again_match'];
1392
			return false;
1393
		}
1394
		// No password?
1395
		if (strlen($_POST['password1']) < 4)
1396
		{
1397
			$incontext['error'] = $txt['error_user_settings_no_password'];
1398
			return false;
1399
		}
1400
		if (!file_exists($sourcedir . '/Subs.php'))
1401
		{
1402
			$incontext['error'] = $txt['error_subs_missing'];
1403
			return false;
1404
		}
1405
1406
		// Update the webmaster's email?
1407
		if (!empty($_POST['server_email']) && (empty($webmaster_email) || $webmaster_email == '[email protected]'))
0 ignored issues
show
Bug introduced by
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...
Bug introduced by
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...
1408
			updateSettingsFile(array('webmaster_email' => $_POST['server_email']));
1409
1410
		// Work out whether we're going to have dodgy characters and remove them.
1411
		$invalid_characters = preg_match('~[<>&"\'=\\\]~', $_POST['username']) != 0;
1412
		$_POST['username'] = preg_replace('~[<>&"\'=\\\]~', '', $_POST['username']);
1413
1414
		$result = $smcFunc['db_query']('', '
1415
			SELECT id_member, password_salt
1416
			FROM {db_prefix}members
1417
			WHERE member_name = {string:username} OR email_address = {string:email}
1418
			LIMIT 1',
1419
			array(
1420
				'username' => stripslashes($_POST['username']),
1421
				'email' => stripslashes($_POST['email']),
1422
				'db_error_skip' => true,
1423
			)
1424
		);
1425
		if ($smcFunc['db_num_rows']($result) != 0)
1426
		{
1427
			list ($incontext['member_id'], $incontext['member_salt']) = $smcFunc['db_fetch_row']($result);
1428
			$smcFunc['db_free_result']($result);
1429
1430
			$incontext['account_existed'] = $txt['error_user_settings_taken'];
1431
		}
1432
		elseif ($_POST['username'] == '' || strlen($_POST['username']) > 25)
1433
		{
1434
			// Try the previous step again.
1435
			$incontext['error'] = $_POST['username'] == '' ? $txt['error_username_left_empty'] : $txt['error_username_too_long'];
1436
			return false;
1437
		}
1438
		elseif ($invalid_characters || $_POST['username'] == '_' || $_POST['username'] == '|' || strpos($_POST['username'], '[code') !== false || strpos($_POST['username'], '[/code') !== false)
1439
		{
1440
			// Try the previous step again.
1441
			$incontext['error'] = $txt['error_invalid_characters_username'];
1442
			return false;
1443
		}
1444 View Code Duplication
		elseif (empty($_POST['email']) || !filter_var(stripslashes($_POST['email']), FILTER_VALIDATE_EMAIL) || strlen(stripslashes($_POST['email'])) > 255)
0 ignored issues
show
Duplication introduced by
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...
1445
		{
1446
			// One step back, this time fill out a proper admin email address.
1447
			$incontext['error'] = sprintf($txt['error_valid_admin_email_needed'], $_POST['username']);
1448
			return false;
1449
		}
1450 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
Duplication introduced by
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...
1451
		{
1452
			// One step back, this time fill out a proper admin email address.
1453
			$incontext['error'] = $txt['error_valid_server_email_needed'];
1454
			return false;
1455
		}
1456
		elseif ($_POST['username'] != '')
1457
		{
1458
			$incontext['member_salt'] = substr(md5(mt_rand()), 0, 4);
1459
1460
			// Format the username properly.
1461
			$_POST['username'] = preg_replace('~[\t\n\r\x0B\0\xA0]+~', ' ', $_POST['username']);
1462
			$ip = isset($_SERVER['REMOTE_ADDR']) ? substr($_SERVER['REMOTE_ADDR'], 0, 255) : '';
1463
1464
			$_POST['password1'] = hash_password(stripslashes($_POST['username']), stripslashes($_POST['password1']));
1465
1466
			$request = $smcFunc['db_insert']('',
1467
				$db_prefix . 'members',
1468
				array(
1469
					'member_name' => 'string-25', 'real_name' => 'string-25', 'passwd' => 'string', 'email_address' => 'string',
1470
					'id_group' => 'int', 'posts' => 'int', 'date_registered' => 'int',
1471
					'password_salt' => 'string', 'lngfile' => 'string', 'personal_text' => 'string', 'avatar' => 'string',
1472
					'member_ip' => 'inet', 'member_ip2' => 'inet', 'buddy_list' => 'string', 'pm_ignore_list' => 'string',
1473
					'website_title' => 'string', 'website_url' => 'string',
1474
					'signature' => 'string', 'usertitle' => 'string', 'secret_question' => 'string',
1475
					'additional_groups' => 'string', 'ignore_boards' => 'string',
1476
				),
1477
				array(
1478
					stripslashes($_POST['username']), stripslashes($_POST['username']), $_POST['password1'], stripslashes($_POST['email']),
1479
					1, 0, time(),
1480
					$incontext['member_salt'], '', '', '',
1481
					$ip, $ip, '', '',
1482
					'', '',
1483
					'', '', '',
1484
					'', '',
1485
				),
1486
				array('id_member')
1487
			);
1488
1489
			// Awww, crud!
1490
			if ($request === false)
1491
			{
1492
				$incontext['error'] = $txt['error_user_settings_query'] . '<br>
1493
				<div style="margin: 2ex;">' . nl2br(htmlspecialchars($smcFunc['db_error']($db_connection))) . '</div>';
1494
				return false;
1495
			}
1496
1497
			$incontext['member_id'] = $smcFunc['db_insert_id']("{$db_prefix}members", 'id_member');
1498
		}
1499
1500
		// If we're here we're good.
1501
		return true;
1502
	}
1503
1504
	return false;
1505
}
1506
1507
// Final step, clean up and a complete message!
1508
function DeleteInstall()
1509
{
1510
	global $txt, $incontext;
1511
	global $smcFunc, $db_character_set, $context, $cookiename;
1512
	global $current_smf_version, $databases, $sourcedir, $forum_version, $modSettings, $user_info, $db_type, $boardurl;
1513
1514
	$incontext['page_title'] = $txt['congratulations'];
1515
	$incontext['sub_template'] = 'delete_install';
1516
	$incontext['continue'] = 0;
1517
1518
	require(dirname(__FILE__) . '/Settings.php');
1519
	load_database();
1520
1521
	chdir(dirname(__FILE__));
1522
1523
	require_once($sourcedir . '/Errors.php');
1524
	require_once($sourcedir . '/Logging.php');
1525
	require_once($sourcedir . '/Subs.php');
1526
	require_once($sourcedir . '/Load.php');
1527
	require_once($sourcedir . '/Security.php');
1528
	require_once($sourcedir . '/Subs-Auth.php');
1529
1530
	// Bring a warning over.
1531
	if (!empty($incontext['account_existed']))
1532
		$incontext['warning'] = $incontext['account_existed'];
1533
1534
	if (!empty($db_character_set) && !empty($databases[$db_type]['utf8_support']))
1535
		$smcFunc['db_query']('', '
1536
			SET NAMES {raw:db_character_set}',
1537
			array(
1538
				'db_character_set' => $db_character_set,
1539
				'db_error_skip' => true,
1540
			)
1541
		);
1542
1543
	// As track stats is by default enabled let's add some activity.
1544
	$smcFunc['db_insert']('ignore',
1545
		'{db_prefix}log_activity',
1546
		array('date' => 'date', 'topics' => 'int', 'posts' => 'int', 'registers' => 'int'),
1547
		array(strftime('%Y-%m-%d', time()), 1, 1, (!empty($incontext['member_id']) ? 1 : 0)),
1548
		array('date')
1549
	);
1550
1551
	// We're going to want our lovely $modSettings now.
1552
	$request = $smcFunc['db_query']('', '
1553
		SELECT variable, value
1554
		FROM {db_prefix}settings',
1555
		array(
1556
			'db_error_skip' => true,
1557
		)
1558
	);
1559
	// Only proceed if we can load the data.
1560
	if ($request)
1561
	{
1562 View Code Duplication
		while ($row = $smcFunc['db_fetch_row']($request))
0 ignored issues
show
Duplication introduced by
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...
1563
			$modSettings[$row[0]] = $row[1];
1564
		$smcFunc['db_free_result']($request);
1565
	}
1566
1567
	// Automatically log them in ;)
1568
	if (isset($incontext['member_id']) && isset($incontext['member_salt']))
1569
		setLoginCookie(3153600 * 60, $incontext['member_id'], hash_salt($_POST['password1'], $incontext['member_salt']));
1570
1571
	$result = $smcFunc['db_query']('', '
1572
		SELECT value
1573
		FROM {db_prefix}settings
1574
		WHERE variable = {string:db_sessions}',
1575
		array(
1576
			'db_sessions' => 'databaseSession_enable',
1577
			'db_error_skip' => true,
1578
		)
1579
	);
1580 View Code Duplication
	if ($smcFunc['db_num_rows']($result) != 0)
0 ignored issues
show
Duplication introduced by
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...
1581
		list ($db_sessions) = $smcFunc['db_fetch_row']($result);
1582
	$smcFunc['db_free_result']($result);
1583
1584
	if (empty($db_sessions))
1585
		$_SESSION['admin_time'] = time();
1586
	else
1587
	{
1588
		$_SERVER['HTTP_USER_AGENT'] = substr($_SERVER['HTTP_USER_AGENT'], 0, 211);
1589
1590
		$smcFunc['db_insert']('replace',
1591
			'{db_prefix}sessions',
1592
			array(
1593
				'session_id' => 'string', 'last_update' => 'int', 'data' => 'string',
1594
			),
1595
			array(
1596
				session_id(), time(), 'USER_AGENT|s:' . strlen($_SERVER['HTTP_USER_AGENT']) . ':"' . $_SERVER['HTTP_USER_AGENT'] . '";admin_time|i:' . time() . ';',
1597
			),
1598
			array('session_id')
1599
		);
1600
	}
1601
1602
	updateStats('member');
1603
	updateStats('message');
1604
	updateStats('topic');
1605
1606
	// This function is needed to do the updateStats('subject') call.
1607
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' :
1608
		create_function('$string', '
1609
			global $sourcedir;
1610
			if (function_exists(\'mb_strtolower\'))
1611
				return mb_strtolower($string, \'UTF-8\');
1612
			require_once($sourcedir . \'/Subs-Charset.php\');
1613
			return utf8_strtolower($string);
1614
		');
1615
1616
	$request = $smcFunc['db_query']('', '
1617
		SELECT id_msg
1618
		FROM {db_prefix}messages
1619
		WHERE id_msg = 1
1620
			AND modified_time = 0
1621
		LIMIT 1',
1622
		array(
1623
			'db_error_skip' => true,
1624
		)
1625
	);
1626
	$context['utf8'] = $db_character_set === 'utf8' || $txt['lang_character_set'] === 'UTF-8';
1627
	if ($smcFunc['db_num_rows']($request) > 0)
1628
		updateStats('subject', 1, htmlspecialchars($txt['default_topic_subject']));
1629
	$smcFunc['db_free_result']($request);
1630
1631
	// Now is the perfect time to fetch the SM files.
1632
	require_once($sourcedir . '/ScheduledTasks.php');
1633
	// Sanity check that they loaded earlier!
1634
	if (isset($modSettings['recycle_board']))
1635
	{
1636
		$forum_version = $current_smf_version;  // The variable is usually defined in index.php so lets just use our variable to do it for us.
1637
		scheduled_fetchSMfiles(); // Now go get those files!
1638
1639
		// We've just installed!
1640
		$user_info['ip'] = $_SERVER['REMOTE_ADDR'];
1641
		$user_info['id'] = isset($incontext['member_id']) ? $incontext['member_id'] : 0;
1642
		logAction('install', array('version' => $forum_version), 'admin');
1643
	}
1644
1645
	// Check if we need some stupid MySQL fix.
1646
	$server_version = $smcFunc['db_server_info']();
1647 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
Duplication introduced by
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...
1648
		updateSettings(array('db_mysql_group_by_fix' => '1'));
1649
1650
	// Some final context for the template.
1651
	$incontext['dir_still_writable'] = is_writable(dirname(__FILE__)) && substr(__FILE__, 1, 2) != ':\\';
1652
	$incontext['probably_delete_install'] = isset($_SESSION['installer_temp_ftp']) || is_writable(dirname(__FILE__)) || is_writable(__FILE__);
1653
1654
	// Update hash's cost to an appropriate setting
1655
	updateSettings(array(
1656
		'bcrypt_hash_cost' => hash_benchmark(),
1657
	));
1658
1659
	return false;
1660
}
1661
1662
// http://www.faqs.org/rfcs/rfc959.html
1663
class ftp_connection
1664
{
1665
	var $connection = 'no_connection', $error = false, $last_message, $pasv = array();
1666
1667
	// Create a new FTP connection...
1668
	function ftp_connection($ftp_server, $ftp_port = 21, $ftp_user = 'anonymous', $ftp_pass = '[email protected]')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1669
	{
1670
		if ($ftp_server !== null)
1671
			$this->connect($ftp_server, $ftp_port, $ftp_user, $ftp_pass);
1672
	}
1673
1674 View Code Duplication
	function connect($ftp_server, $ftp_port = 21, $ftp_user = 'anonymous', $ftp_pass = '[email protected]')
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1675
	{
1676
		if (substr($ftp_server, 0, 6) == 'ftp://')
1677
			$ftp_server = substr($ftp_server, 6);
1678
		elseif (substr($ftp_server, 0, 7) == 'ftps://')
1679
			$ftp_server = 'ssl://' . substr($ftp_server, 7);
1680
		if (substr($ftp_server, 0, 7) == 'http://')
1681
			$ftp_server = substr($ftp_server, 7);
1682
		$ftp_server = strtr($ftp_server, array('/' => '', ':' => '', '@' => ''));
1683
1684
		// Connect to the FTP server.
1685
		$this->connection = @fsockopen($ftp_server, $ftp_port, $err, $err, 5);
1686
		if (!$this->connection)
1687
		{
1688
			$this->error = 'bad_server';
0 ignored issues
show
Documentation Bug introduced by
The property $error was declared of type boolean, but 'bad_server' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1689
			return;
1690
		}
1691
1692
		// Get the welcome message...
1693
		if (!$this->check_response(220))
1694
		{
1695
			$this->error = 'bad_response';
0 ignored issues
show
Documentation Bug introduced by
The property $error was declared of type boolean, but 'bad_response' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1696
			return;
1697
		}
1698
1699
		// Send the username, it should ask for a password.
1700
		fwrite($this->connection, 'USER ' . $ftp_user . "\r\n");
1701
		if (!$this->check_response(331))
1702
		{
1703
			$this->error = 'bad_username';
0 ignored issues
show
Documentation Bug introduced by
The property $error was declared of type boolean, but 'bad_username' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1704
			return;
1705
		}
1706
1707
		// Now send the password... and hope it goes okay.
1708
		fwrite($this->connection, 'PASS ' . $ftp_pass . "\r\n");
1709
		if (!$this->check_response(230))
1710
		{
1711
			$this->error = 'bad_password';
0 ignored issues
show
Documentation Bug introduced by
The property $error was declared of type boolean, but 'bad_password' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1712
			return;
1713
		}
1714
	}
1715
1716 View Code Duplication
	function chdir($ftp_path)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1717
	{
1718
		if (!is_resource($this->connection))
1719
			return false;
1720
1721
		// No slash on the end, please...
1722
		if (substr($ftp_path, -1) == '/')
1723
			$ftp_path = substr($ftp_path, 0, -1);
1724
1725
		fwrite($this->connection, 'CWD ' . $ftp_path . "\r\n");
1726
		if (!$this->check_response(250))
1727
		{
1728
			$this->error = 'bad_path';
0 ignored issues
show
Documentation Bug introduced by
The property $error was declared of type boolean, but 'bad_path' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1729
			return false;
1730
		}
1731
1732
		return true;
1733
	}
1734
1735 View Code Duplication
	function chmod($ftp_file, $chmod)
0 ignored issues
show
Unused Code introduced by
The parameter $chmod is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1736
	{
1737
		if (!is_resource($this->connection))
1738
			return false;
1739
1740
		// Convert the chmod value from octal (0777) to text ("777")
1741
		fwrite($this->connection, 'SITE CHMOD ' . decoct($chmod) . ' ' . $ftp_file . "\r\n");
1742
		if (!$this->check_response(200))
1743
		{
1744
			$this->error = 'bad_file';
0 ignored issues
show
Documentation Bug introduced by
The property $error was declared of type boolean, but 'bad_file' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1745
			return false;
1746
		}
1747
1748
		return true;
1749
	}
1750
1751 View Code Duplication
	function unlink($ftp_file)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1752
	{
1753
		// We are actually connected, right?
1754
		if (!is_resource($this->connection))
1755
			return false;
1756
1757
		// Delete file X.
1758
		fwrite($this->connection, 'DELE ' . $ftp_file . "\r\n");
1759
		if (!$this->check_response(250))
1760
		{
1761
			fwrite($this->connection, 'RMD ' . $ftp_file . "\r\n");
1762
1763
			// Still no love?
1764
			if (!$this->check_response(250))
1765
			{
1766
				$this->error = 'bad_file';
0 ignored issues
show
Documentation Bug introduced by
The property $error was declared of type boolean, but 'bad_file' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1767
				return false;
1768
			}
1769
		}
1770
1771
		return true;
1772
	}
1773
1774 View Code Duplication
	function check_response($desired)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1775
	{
1776
		// Wait for a response that isn't continued with -, but don't wait too long.
1777
		$time = time();
1778
		do
1779
			$this->last_message = fgets($this->connection, 1024);
1780
		while (substr($this->last_message, 3, 1) != ' ' && time() - $time < 5);
1781
1782
		// Was the desired response returned?
1783
		return is_array($desired) ? in_array(substr($this->last_message, 0, 3), $desired) : substr($this->last_message, 0, 3) == $desired;
1784
	}
1785
1786 View Code Duplication
	function passive()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1787
	{
1788
		// We can't create a passive data connection without a primary one first being there.
1789
		if (!is_resource($this->connection))
1790
			return false;
1791
1792
		// Request a passive connection - this means, we'll talk to you, you don't talk to us.
1793
		@fwrite($this->connection, "PASV\r\n");
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...
1794
		$time = time();
1795
		do
1796
			$response = fgets($this->connection, 1024);
1797
		while (substr($response, 3, 1) != ' ' && time() - $time < 5);
1798
1799
		// If it's not 227, we weren't given an IP and port, which means it failed.
1800
		if (substr($response, 0, 4) != '227 ')
1801
		{
1802
			$this->error = 'bad_response';
0 ignored issues
show
Documentation Bug introduced by
The property $error was declared of type boolean, but 'bad_response' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1803
			return false;
1804
		}
1805
1806
		// Snatch the IP and port information, or die horribly trying...
1807
		if (preg_match('~\((\d+),\s*(\d+),\s*(\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))\)~', $response, $match) == 0)
1808
		{
1809
			$this->error = 'bad_response';
1810
			return false;
1811
		}
1812
1813
		// This is pretty simple - store it for later use ;)
1814
		$this->pasv = array('ip' => $match[1] . '.' . $match[2] . '.' . $match[3] . '.' . $match[4], 'port' => $match[5] * 256 + $match[6]);
1815
1816
		return true;
1817
	}
1818
1819 View Code Duplication
	function create_file($ftp_file)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1820
	{
1821
		// First, we have to be connected... very important.
1822
		if (!is_resource($this->connection))
1823
			return false;
1824
1825
		// I'd like one passive mode, please!
1826
		if (!$this->passive())
1827
			return false;
1828
1829
		// Seems logical enough, so far...
1830
		fwrite($this->connection, 'STOR ' . $ftp_file . "\r\n");
1831
1832
		// Okay, now we connect to the data port.  If it doesn't work out, it's probably "file already exists", etc.
1833
		$fp = @fsockopen($this->pasv['ip'], $this->pasv['port'], $err, $err, 5);
1834
		if (!$fp || !$this->check_response(150))
1835
		{
1836
			$this->error = 'bad_file';
0 ignored issues
show
Documentation Bug introduced by
The property $error was declared of type boolean, but 'bad_file' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1837
			@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...
1838
			return false;
1839
		}
1840
1841
		// This may look strange, but we're just closing it to indicate a zero-byte upload.
1842
		fclose($fp);
1843
		if (!$this->check_response(226))
1844
		{
1845
			$this->error = 'bad_response';
0 ignored issues
show
Documentation Bug introduced by
The property $error was declared of type boolean, but 'bad_response' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1846
			return false;
1847
		}
1848
1849
		return true;
1850
	}
1851
1852 View Code Duplication
	function list_dir($ftp_path = '', $search = false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1853
	{
1854
		// Are we even connected...?
1855
		if (!is_resource($this->connection))
1856
			return false;
1857
1858
		// Passive... non-agressive...
1859
		if (!$this->passive())
1860
			return false;
1861
1862
		// Get the listing!
1863
		fwrite($this->connection, 'LIST -1' . ($search ? 'R' : '') . ($ftp_path == '' ? '' : ' ' . $ftp_path) . "\r\n");
1864
1865
		// Connect, assuming we've got a connection.
1866
		$fp = @fsockopen($this->pasv['ip'], $this->pasv['port'], $err, $err, 5);
1867
		if (!$fp || !$this->check_response(array(150, 125)))
1868
		{
1869
			$this->error = 'bad_response';
0 ignored issues
show
Documentation Bug introduced by
The property $error was declared of type boolean, but 'bad_response' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1870
			@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...
1871
			return false;
1872
		}
1873
1874
		// Read in the file listing.
1875
		$data = '';
1876
		while (!feof($fp))
1877
			$data .= fread($fp, 4096);
1878
		fclose($fp);
1879
1880
		// Everything go okay?
1881
		if (!$this->check_response(226))
1882
		{
1883
			$this->error = 'bad_response';
1884
			return false;
1885
		}
1886
1887
		return $data;
1888
	}
1889
1890 View Code Duplication
	function locate($file, $listing = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1891
	{
1892
		if ($listing === null)
1893
			$listing = $this->list_dir('', true);
1894
		$listing = explode("\n", $listing);
1895
1896
		@fwrite($this->connection, "PWD\r\n");
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...
1897
		$time = time();
1898
		do
1899
			$response = fgets($this->connection, 1024);
1900
		while (substr($response, 3, 1) != ' ' && time() - $time < 5);
1901
1902
		// Check for 257!
1903
		if (preg_match('~^257 "(.+?)" ~', $response, $match) != 0)
1904
			$current_dir = strtr($match[1], array('""' => '"'));
1905
		else
1906
			$current_dir = '';
1907
1908
		for ($i = 0, $n = count($listing); $i < $n; $i++)
1909
		{
1910
			if (trim($listing[$i]) == '' && isset($listing[$i + 1]))
1911
			{
1912
				$current_dir = substr(trim($listing[++$i]), 0, -1);
1913
				$i++;
1914
			}
1915
1916
			// Okay, this file's name is:
1917
			$listing[$i] = $current_dir . '/' . trim(strlen($listing[$i]) > 30 ? strrchr($listing[$i], ' ') : $listing[$i]);
1918
1919
			if (substr($file, 0, 1) == '*' && substr($listing[$i], -(strlen($file) - 1)) == substr($file, 1))
1920
				return $listing[$i];
1921
			if (substr($file, -1) == '*' && substr($listing[$i], 0, strlen($file) - 1) == substr($file, 0, -1))
1922
				return $listing[$i];
1923
			if (basename($listing[$i]) == $file || $listing[$i] == $file)
1924
				return $listing[$i];
1925
		}
1926
1927
		return false;
1928
	}
1929
1930 View Code Duplication
	function create_dir($ftp_dir)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1931
	{
1932
		// We must be connected to the server to do something.
1933
		if (!is_resource($this->connection))
1934
			return false;
1935
1936
		// Make this new beautiful directory!
1937
		fwrite($this->connection, 'MKD ' . $ftp_dir . "\r\n");
1938
		if (!$this->check_response(257))
1939
		{
1940
			$this->error = 'bad_file';
0 ignored issues
show
Documentation Bug introduced by
The property $error was declared of type boolean, but 'bad_file' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1941
			return false;
1942
		}
1943
1944
		return true;
1945
	}
1946
1947 View Code Duplication
	function detect_path($filesystem_path, $lookup_file = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in 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...
1948
	{
1949
		$username = '';
1950
1951
		if (isset($_SERVER['DOCUMENT_ROOT']))
1952
		{
1953
			if (preg_match('~^/home[2]?/([^/]+?)/public_html~', $_SERVER['DOCUMENT_ROOT'], $match))
1954
			{
1955
				$username = $match[1];
1956
1957
				$path = strtr($_SERVER['DOCUMENT_ROOT'], array('/home/' . $match[1] . '/' => '', '/home2/' . $match[1] . '/' => ''));
1958
1959
				if (substr($path, -1) == '/')
1960
					$path = substr($path, 0, -1);
1961
1962
				if (strlen(dirname($_SERVER['PHP_SELF'])) > 1)
1963
					$path .= dirname($_SERVER['PHP_SELF']);
1964
			}
1965
			elseif (substr($filesystem_path, 0, 9) == '/var/www/')
1966
				$path = substr($filesystem_path, 8);
1967
			else
1968
				$path = strtr(strtr($filesystem_path, array('\\' => '/')), array($_SERVER['DOCUMENT_ROOT'] => ''));
1969
		}
1970
		else
1971
			$path = '';
1972
1973
		if (is_resource($this->connection) && $this->list_dir($path) == '')
1974
		{
1975
			$data = $this->list_dir('', true);
1976
1977
			if ($lookup_file === null)
1978
				$lookup_file = $_SERVER['PHP_SELF'];
1979
1980
			$found_path = dirname($this->locate('*' . basename(dirname($lookup_file)) . '/' . basename($lookup_file), $data));
1981
			if ($found_path == false)
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $found_path of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
1982
				$found_path = dirname($this->locate(basename($lookup_file)));
1983
			if ($found_path != false)
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $found_path of type string to the boolean false. If you are specifically checking for a non-empty string, consider using the more explicit !== '' instead.
Loading history...
1984
				$path = $found_path;
1985
		}
1986
		elseif (is_resource($this->connection))
1987
			$found_path = true;
1988
1989
		return array($username, $path, isset($found_path));
1990
	}
1991
1992
	function close()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1993
	{
1994
		// Goodbye!
1995
		fwrite($this->connection, "QUIT\r\n");
1996
		fclose($this->connection);
1997
1998
		return true;
1999
	}
2000
}
2001
2002
function updateSettingsFile($vars)
2003
{
2004
	// Modify Settings.php.
2005
	$settingsArray = file(dirname(__FILE__) . '/Settings.php');
2006
2007
	// @todo Do we just want to read the file in clean, and split it this way always?
2008
	if (count($settingsArray) == 1)
2009
		$settingsArray = preg_split('~[\r\n]~', $settingsArray[0]);
2010
2011
	for ($i = 0, $n = count($settingsArray); $i < $n; $i++)
2012
	{
2013
		// Remove the redirect...
2014
		if (trim($settingsArray[$i]) == 'if (file_exists(dirname(__FILE__) . \'/install.php\'))' && trim($settingsArray[$i + 1]) == '{' && trim($settingsArray[$i + 3]) == '}')
2015
		{
2016
			// Get the four lines to nothing.
2017
			$settingsArray[$i] = '';
2018
			$settingsArray[++$i] = '';
2019
			$settingsArray[++$i] = '';
2020
			$settingsArray[++$i] = '';
2021
			continue;
2022
		}
2023
2024
		if (trim($settingsArray[$i]) == '?' . '>')
2025
			$settingsArray[$i] = '';
2026
2027
		// Don't trim or bother with it if it's not a variable.
2028
		if (substr($settingsArray[$i], 0, 1) != '$')
2029
			continue;
2030
2031
		$settingsArray[$i] = rtrim($settingsArray[$i]) . "\n";
2032
2033
		foreach ($vars as $var => $val)
2034 View Code Duplication
			if (strncasecmp($settingsArray[$i], '$' . $var, 1 + strlen($var)) == 0)
0 ignored issues
show
Duplication introduced by
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...
2035
			{
2036
				$comment = strstr($settingsArray[$i], '#');
2037
				$settingsArray[$i] = '$' . $var . ' = \'' . $val . '\';' . ($comment != '' ? "\t\t" . $comment : "\n");
2038
				unset($vars[$var]);
2039
			}
2040
	}
2041
2042
	// Uh oh... the file wasn't empty... was it?
2043 View Code Duplication
	if (!empty($vars))
0 ignored issues
show
Duplication introduced by
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...
2044
	{
2045
		$settingsArray[$i++] = '';
2046
		foreach ($vars as $var => $val)
2047
			$settingsArray[$i++] = '$' . $var . ' = \'' . $val . '\';' . "\n";
2048
	}
2049
2050
	// Blank out the file - done to fix a oddity with some servers.
2051
	$fp = @fopen(dirname(__FILE__) . '/Settings.php', 'w');
2052
	if (!$fp)
2053
		return false;
2054
	fclose($fp);
2055
2056
	$fp = fopen(dirname(__FILE__) . '/Settings.php', 'r+');
2057
2058
	// Gotta have one of these ;)
2059
	if (trim($settingsArray[0]) != '<?php')
2060
		fwrite($fp, "<?php\n");
2061
2062
	$lines = count($settingsArray);
2063
	for ($i = 0; $i < $lines - 1; $i++)
2064
	{
2065
		// Don't just write a bunch of blank lines.
2066
		if ($settingsArray[$i] != '' || @$settingsArray[$i - 1] != '')
2067
			fwrite($fp, strtr($settingsArray[$i], "\r", ''));
2068
	}
2069
	fwrite($fp, $settingsArray[$i] . '?' . '>');
2070
	fclose($fp);
2071
2072
	// Even though on normal installations the filemtime should prevent this being used by the installer incorrectly
2073
	// it seems that there are times it might not. So let's MAKE it dump the cache.
2074
	if (function_exists('opcache_invalidate'))
2075
		opcache_invalidate(dirname(__FILE__) . '/Settings.php', true);
2076
2077
	return true;
2078
}
2079
2080
function updateDbLastError()
2081
{
2082
	// Write out the db_last_error file with the error timestamp
2083
	file_put_contents(dirname(__FILE__) . '/db_last_error.php', '<' . '?' . "php\n" . '$db_last_error = 0;' . "\n" . '?' . '>');
2084
2085
	return true;
2086
}
2087
2088
// Create an .htaccess file to prevent mod_security. SMF has filtering built-in.
2089
function fixModSecurity()
2090
{
2091
	$htaccess_addition = '
2092
<IfModule mod_security.c>
2093
	# Turn off mod_security filtering.  SMF is a big boy, it doesn\'t need its hands held.
2094
	SecFilterEngine Off
2095
2096
	# The below probably isn\'t needed, but better safe than sorry.
2097
	SecFilterScanPOST Off
2098
</IfModule>';
2099
2100
	if (!function_exists('apache_get_modules') || !in_array('mod_security', apache_get_modules()))
2101
		return true;
2102
	elseif (file_exists(dirname(__FILE__) . '/.htaccess') && is_writable(dirname(__FILE__) . '/.htaccess'))
2103
	{
2104
		$current_htaccess = implode('', file(dirname(__FILE__) . '/.htaccess'));
2105
2106
		// Only change something if mod_security hasn't been addressed yet.
2107
		if (strpos($current_htaccess, '<IfModule mod_security.c>') === false)
2108
		{
2109 View Code Duplication
			if ($ht_handle = fopen(dirname(__FILE__) . '/.htaccess', 'a'))
0 ignored issues
show
Duplication introduced by
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...
2110
			{
2111
				fwrite($ht_handle, $htaccess_addition);
2112
				fclose($ht_handle);
2113
				return true;
2114
			}
2115
			else
2116
				return false;
2117
		}
2118
		else
2119
			return true;
2120
	}
2121
	elseif (file_exists(dirname(__FILE__) . '/.htaccess'))
2122
		return strpos(implode('', file(dirname(__FILE__) . '/.htaccess')), '<IfModule mod_security.c>') !== false;
2123
	elseif (is_writable(dirname(__FILE__)))
2124
	{
2125 View Code Duplication
		if ($ht_handle = fopen(dirname(__FILE__) . '/.htaccess', 'w'))
0 ignored issues
show
Duplication introduced by
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...
2126
		{
2127
			fwrite($ht_handle, $htaccess_addition);
2128
			fclose($ht_handle);
2129
			return true;
2130
		}
2131
		else
2132
			return false;
2133
	}
2134
	else
2135
		return false;
2136
}
2137
2138
function template_install_above()
2139
{
2140
	global $incontext, $txt, $installurl;
2141
2142
	echo '<!DOCTYPE html>
2143
<html', $txt['lang_rtl'] == true ? ' dir="rtl"' : '', '>
2144
	<head>
2145
		<meta charset="', isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8', '">
2146
		<meta name="robots" content="noindex">
2147
		<title>', $txt['smf_installer'], '</title>
2148
		<link rel="stylesheet" href="Themes/default/css/index.css?alp21">
2149
		<link rel="stylesheet" href="Themes/default/css/install.css?alp21">
2150
		', $txt['lang_rtl'] == true ? '<link rel="stylesheet" href="Themes/default/css/rtl.css?alp21">' : '' , '
2151
2152
		<script src="Themes/default/scripts/jquery-2.1.3.min.js"></script>
2153
		<script src="Themes/default/scripts/script.js"></script>
2154
	</head>
2155
	<body><div id="footerfix">
2156
		<div id="header">
2157
			<h1 class="forumtitle">', $txt['smf_installer'], '</h1>
2158
			<img id="smflogo" src="Themes/default/images/smflogo.png" alt="Simple Machines Forum" title="Simple Machines Forum">
2159
		</div>
2160
		<div id="wrapper">
2161
			<div id="upper_section">
2162
				<div id="inner_section">
2163
					<div id="inner_wrap">';
2164
2165
	// Have we got a language drop down - if so do it on the first step only.
2166
	if (!empty($incontext['detected_languages']) && count($incontext['detected_languages']) > 1 && $incontext['current_step'] == 0)
2167
	{
2168
		echo '
2169
						<div class="news">
2170
							<form action="', $installurl, '" method="get">
2171
								<label for="installer_language">', $txt['installer_language'], ':</label>
2172
								<select id="installer_language" name="lang_file" onchange="location.href = \'', $installurl, '?lang_file=\' + this.options[this.selectedIndex].value;">';
2173
2174
		foreach ($incontext['detected_languages'] as $lang => $name)
2175
			echo '
2176
									<option', isset($_SESSION['installer_temp_lang']) && $_SESSION['installer_temp_lang'] == $lang ? ' selected' : '', ' value="', $lang, '">', $name, '</option>';
2177
2178
		echo '
2179
								</select>
2180
								<noscript><input type="submit" value="', $txt['installer_language_set'], '" class="button_submit" /></noscript>
2181
							</form>
2182
						</div>
2183
						<hr class="clear" />';
2184
	}
2185
2186
	echo '
2187
					</div>
2188
				</div>
2189
			</div>
2190
			<div id="content_section">
2191
				<div id="main_content_section">
2192
					<div id="main_steps">
2193
						<h2>', $txt['upgrade_progress'], '</h2>
2194
						<ul>';
2195
2196 View Code Duplication
	foreach ($incontext['steps'] as $num => $step)
0 ignored issues
show
Duplication introduced by
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...
2197
		echo '
2198
							<li class="', $num < $incontext['current_step'] ? 'stepdone' : ($num == $incontext['current_step'] ? 'stepcurrent' : 'stepwaiting'), '">', $txt['upgrade_step'], ' ', $step[0], ': ', $step[1], '</li>';
2199
2200
	echo '
2201
						</ul>
2202
					</div>
2203
					<div id="progress_bar">
2204
						<div id="overall_text">', $incontext['overall_percent'], '%</div>
2205
						<div id="overall_progress" style="width: ', $incontext['overall_percent'], '%;">&nbsp;</div>
2206
						<div class="overall_progress">', $txt['upgrade_overall_progress'], '</div>
2207
					</div>
2208
					<div id="main_screen" class="clear">
2209
						<h2>', $incontext['page_title'], '</h2>
2210
						<div class="panel">';
2211
}
2212
2213
function template_install_below()
2214
{
2215
	global $incontext, $txt;
2216
2217
	if (!empty($incontext['continue']) || !empty($incontext['skip']))
2218
	{
2219
		echo '
2220
								<div>';
2221
2222
		if (!empty($incontext['continue']))
2223
			echo '
2224
									<input type="submit" id="contbutt" name="contbutt" value="', $txt['upgrade_continue'], '" onclick="return submitThisOnce(this);" class="button_submit" />';
2225
		if (!empty($incontext['skip']))
2226
			echo '
2227
									<input type="submit" id="skip" name="skip" value="', $txt['upgrade_skip'], '" onclick="return submitThisOnce(this);" class="button_submit" />';
2228
		echo '
2229
								</div>';
2230
	}
2231
2232
	// Show the closing form tag and other data only if not in the last step
2233
	if (count($incontext['steps']) - 1 !== (int) $incontext['current_step'])
2234
		echo '
2235
							</form>';
2236
2237
	echo '
2238
						</div>
2239
					</div>
2240
				</div>
2241
			</div>
2242
		</div></div>
2243
		<div id="footer">
2244
			<ul>
2245
				<li class="copyright"><a href="http://www.simplemachines.org/" title="Simple Machines Forum" target="_blank" class="new_win">SMF &copy; 2016, Simple Machines</a></li>
2246
			</ul>
2247
		</div>
2248
	</body>
2249
</html>';
2250
}
2251
2252
// Welcome them to the wonderful world of SMF!
2253
function template_welcome_message()
2254
{
2255
	global $incontext, $txt;
2256
2257
	echo '
2258
	<script src="http://www.simplemachines.org/smf/current-version.js?version=' . $GLOBALS['current_smf_version'] . '"></script>
2259
	<form action="', $incontext['form_url'], '" method="post">
2260
		<p>', sprintf($txt['install_welcome_desc'], $GLOBALS['current_smf_version']), '</p>
2261
		<div id="version_warning" style="margin: 2ex; padding: 2ex; border: 2px dashed #a92174; color: black; background-color: #fbbbe2; display: none;">
2262
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
2263
			<strong style="text-decoration: underline;">', $txt['error_warning_notice'], '</strong><br />
2264
			<div style="padding-left: 6ex;">
2265
				', 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>'), '
2266
			</div>
2267
		</div>';
2268
2269
	// Show the warnings, or not.
2270
	if (template_warning_divs())
2271
		echo '
2272
		<h3>', $txt['install_all_lovely'], '</h3>';
2273
2274
	// Say we want the continue button!
2275
	if (empty($incontext['error']))
2276
		$incontext['continue'] = 1;
2277
2278
	// For the latest version stuff.
2279
	echo '
2280
		<script>
2281
			// Latest version?
2282
			function smfCurrentVersion()
2283
			{
2284
				var smfVer, yourVer;
2285
2286
				if (!(\'smfVersion\' in window))
2287
					return;
2288
2289
				window.smfVersion = window.smfVersion.replace(/SMF\s?/g, \'\');
2290
2291
				smfVer = document.getElementById("smfVersion");
2292
				yourVer = document.getElementById("yourVersion");
2293
2294
				setInnerHTML(smfVer, window.smfVersion);
2295
2296
				var currentVersion = getInnerHTML(yourVer);
2297
				if (currentVersion < window.smfVersion)
2298
					document.getElementById(\'version_warning\').style.display = \'\';
2299
			}
2300
			addLoadEvent(smfCurrentVersion);
2301
		</script>';
2302
}
2303
2304
// A shortcut for any warning stuff.
2305
function template_warning_divs()
2306
{
2307
	global $txt, $incontext;
2308
2309
	// Errors are very serious..
2310
	if (!empty($incontext['error']))
2311
		echo '
2312
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
2313
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
2314
			<strong style="text-decoration: underline;">', $txt['upgrade_critical_error'], '</strong><br />
2315
			<div style="padding-left: 6ex;">
2316
				', $incontext['error'], '
2317
			</div>
2318
		</div>';
2319
	// A warning message?
2320
	elseif (!empty($incontext['warning']))
2321
		echo '
2322
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
2323
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
2324
			<strong style="text-decoration: underline;">', $txt['upgrade_warning'], '</strong><br />
2325
			<div style="padding-left: 6ex;">
2326
				', $incontext['warning'], '
2327
			</div>
2328
		</div>';
2329
2330
	return empty($incontext['error']) && empty($incontext['warning']);
2331
}
2332
2333
function template_chmod_files()
2334
{
2335
	global $txt, $incontext;
2336
2337
	echo '
2338
		<p>', $txt['ftp_setup_why_info'], '</p>
2339
		<ul style="margin: 2.5ex; font-family: monospace;">
2340
			<li>', implode('</li>
2341
			<li>', $incontext['failed_files']), '</li>
2342
		</ul>';
2343
2344
	if (isset($incontext['systemos'], $incontext['detected_path']) && $incontext['systemos'] == 'linux')
2345
		echo '
2346
		<hr />
2347
		<p>', $txt['chmod_linux_info'], '</p>
2348
		<tt># chmod a+w ', implode(' ' . $incontext['detected_path'] . '/', $incontext['failed_files']), '</tt>';
2349
2350
	// This is serious!
2351
	if (!template_warning_divs())
2352
		return;
2353
2354
	echo '
2355
		<hr />
2356
		<p>', $txt['ftp_setup_info'], '</p>';
2357
2358
	if (!empty($incontext['ftp_errors']))
2359
		echo '
2360
		<div class="error_message">
2361
			<div style="color: red;">
2362
				', $txt['error_ftp_no_connect'], '<br />
2363
				<br />
2364
				<code>', implode('<br />', $incontext['ftp_errors']), '</code>
2365
			</div>
2366
		</div>
2367
		<br />';
2368
2369
	echo '
2370
		<form action="', $incontext['form_url'], '" method="post">
2371
			<table align="center" style="width: 520px; margin: 1em 0; padding: 0; border: 0">
2372
				<tr>
2373
					<td width="26%" valign="top" class="textbox"><label for="ftp_server">', $txt['ftp_server'], ':</label></td>
2374
					<td>
2375
						<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>
2376
						<input type="text" size="30" name="ftp_server" id="ftp_server" value="', $incontext['ftp']['server'], '" style="width: 70%;" class="input_text" />
2377
						<div class="smalltext block">', $txt['ftp_server_info'], '</div>
2378
					</td>
2379
				</tr><tr>
2380
					<td width="26%" valign="top" class="textbox"><label for="ftp_username">', $txt['ftp_username'], ':</label></td>
2381
					<td>
2382
						<input type="text" size="50" name="ftp_username" id="ftp_username" value="', $incontext['ftp']['username'], '" style="width: 99%;" class="input_text" />
2383
						<div class="smalltext block">', $txt['ftp_username_info'], '</div>
2384
					</td>
2385
				</tr><tr>
2386
					<td width="26%" valign="top" class="textbox"><label for="ftp_password">', $txt['ftp_password'], ':</label></td>
2387
					<td>
2388
						<input type="password" size="50" name="ftp_password" id="ftp_password" style="width: 99%;" class="input_password" />
2389
						<div class="smalltext block">', $txt['ftp_password_info'], '</div>
2390
					</td>
2391
				</tr><tr>
2392
					<td width="26%" valign="top" class="textbox"><label for="ftp_path">', $txt['ftp_path'], ':</label></td>
2393
					<td style="padding-bottom: 1ex;">
2394
						<input type="text" size="50" name="ftp_path" id="ftp_path" value="', $incontext['ftp']['path'], '" style="width: 99%;" class="input_text" />
2395
						<div class="smalltext block">', $incontext['ftp']['path_msg'], '</div>
2396
					</td>
2397
				</tr>
2398
			</table>
2399
			<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>
2400
		</form>
2401
		<a href="', $incontext['form_url'], '">', $txt['error_message_click'], '</a> ', $txt['ftp_setup_again'];
2402
}
2403
2404
// Get the database settings prepared.
2405
function template_database_settings()
2406
{
2407
	global $incontext, $txt;
2408
2409
	echo '
2410
	<form action="', $incontext['form_url'], '" method="post">
2411
		<p>', $txt['db_settings_info'], '</p>';
2412
2413
	template_warning_divs();
2414
2415
	echo '
2416
		<table width="100%" border="0" style="margin: 1em 0;">';
2417
2418
	// More than one database type?
2419
	if (count($incontext['supported_databases']) > 1)
2420
	{
2421
		echo '
2422
			<tr>
2423
				<td width="20%" valign="top" class="textbox"><label for="db_type_input">', $txt['db_settings_type'], ':</label></td>
2424
				<td>
2425
					<select name="db_type" id="db_type_input" onchange="toggleDBInput();">';
2426
2427
	foreach ($incontext['supported_databases'] as $key => $db)
2428
			echo '
2429
						<option value="', $key, '"', isset($_POST['db_type']) && $_POST['db_type'] == $key ? ' selected' : '', '>', $db['name'], '</option>';
2430
2431
	echo '
2432
					</select>
2433
					<div class="smalltext block">', $txt['db_settings_type_info'], '</div>
2434
				</td>
2435
			</tr>';
2436
	}
2437
	else
2438
	{
2439
		echo '
2440
			<tr style="display: none;">
2441
				<td>
2442
					<input type="hidden" name="db_type" value="', $incontext['db']['type'], '" />
2443
				</td>
2444
			</tr>';
2445
	}
2446
2447
	echo '
2448
			<tr id="db_server_contain">
2449
				<td width="20%" valign="top" class="textbox"><label for="db_server_input">', $txt['db_settings_server'], ':</label></td>
2450
				<td>
2451
					<input type="text" name="db_server" id="db_server_input" value="', $incontext['db']['server'], '" size="30" class="input_text" /><br />
2452
					<div class="smalltext block">', $txt['db_settings_server_info'], '</div>
2453
				</td>
2454
			</tr><tr id="db_port_contain">
2455
				<td width="20%" valign="top" class="textbox"><label for="db_port_input">', $txt['db_settings_port'], ':</label></td>
2456
				<td>
2457
					<input type="text" name="db_port" id="db_port_input" value="', $incontext['db']['port'], '"><br>
2458
					<div class="smalltext block">', $txt['db_settings_port_info'], '</div>
2459
				</td>
2460
			</tr><tr id="db_user_contain">
2461
				<td valign="top" class="textbox"><label for="db_user_input">', $txt['db_settings_username'], ':</label></td>
2462
				<td>
2463
					<input type="text" name="db_user" id="db_user_input" value="', $incontext['db']['user'], '" size="30" class="input_text" /><br />
2464
					<div class="smalltext block">', $txt['db_settings_username_info'], '</div>
2465
				</td>
2466
			</tr><tr id="db_passwd_contain">
2467
				<td valign="top" class="textbox"><label for="db_passwd_input">', $txt['db_settings_password'], ':</label></td>
2468
				<td>
2469
					<input type="password" name="db_passwd" id="db_passwd_input" value="', $incontext['db']['pass'], '" size="30" class="input_password" /><br />
2470
					<div class="smalltext block">', $txt['db_settings_password_info'], '</div>
2471
				</td>
2472
			</tr><tr id="db_name_contain">
2473
				<td valign="top" class="textbox"><label for="db_name_input">', $txt['db_settings_database'], ':</label></td>
2474
				<td>
2475
					<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 />
2476
					<div class="smalltext block">', $txt['db_settings_database_info'], '
2477
					<span id="db_name_info_warning">', $txt['db_settings_database_info_note'], '</span></div>
2478
				</td>
2479
			</tr><tr id="db_filename_contain" style="display: none;">
2480
				<td valign="top" class="textbox"><label for="db_filename_input">', $txt['db_settings_database_file'], ':</label></td>
2481
				<td>
2482
					<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 />
2483
					<div class="smalltext block">', $txt['db_settings_database_file_info'], '</div>
2484
				</td>
2485
			</tr><tr>
2486
				<td valign="top" class="textbox"><label for="db_prefix_input">', $txt['db_settings_prefix'], ':</label></td>
2487
				<td>
2488
					<input type="text" name="db_prefix" id="db_prefix_input" value="', $incontext['db']['prefix'], '" size="30" class="input_text" /><br />
2489
					<div class="smalltext block">', $txt['db_settings_prefix_info'], '</div>
2490
				</td>
2491
			</tr>
2492
		</table>';
2493
2494
	// Toggles a warning related to db names in PostgreSQL
2495
	echo '
2496
	<script>
2497
		function toggleDBInput()
2498
		{
2499
			if (document.getElementById(\'db_type_input\').value == \'postgresql\')
2500
				document.getElementById(\'db_name_info_warning\').style.display = \'none\';
2501
			else
2502
				document.getElementById(\'db_name_info_warning\').style.display = \'\';
2503
		}
2504
		toggleDBInput();
2505
	</script>';
2506
}
2507
2508
// Stick in their forum settings.
2509
function template_forum_settings()
2510
{
2511
	global $incontext, $txt;
2512
2513
	echo '
2514
	<form action="', $incontext['form_url'], '" method="post">
2515
		<h3>', $txt['install_settings_info'], '</h3>';
2516
2517
	template_warning_divs();
2518
2519
	echo '
2520
		<table style="width: 100%; margin: 1em 0;">
2521
			<tr>
2522
				<td class="textbox" style="width: 20%; vertical-align: top;">
2523
					<label for="mbname_input">', $txt['install_settings_name'], ':</label>
2524
				</td>
2525
				<td>
2526
					<input type="text" name="mbname" id="mbname_input" value="', $txt['install_settings_name_default'], '" size="65" class="input_text" />
2527
					<div class="smalltext block">', $txt['install_settings_name_info'], '</div>
2528
				</td>
2529
			</tr>
2530
			<tr>
2531
				<td class="textbox" style="vertical-align: top;">
2532
					<label for="boardurl_input">', $txt['install_settings_url'], ':</label>
2533
				</td>
2534
				<td>
2535
					<input type="text" name="boardurl" id="boardurl_input" value="', $incontext['detected_url'], '" size="65" class="input_text" />
2536
					<br />
2537
					<div class="smalltext block">', $txt['install_settings_url_info'], '</div>
2538
				</td>
2539
			</tr>
2540
			<tr>
2541
				<td class="textbox" style="vertical-align: top;">
2542
					<label for="reg_mode">', $txt['install_settings_reg_mode'], ':</label>
2543
				</td>
2544
				<td>
2545
					<select name="reg_mode" id="reg_mode">
2546
						<optgroup label="', $txt['install_settings_reg_modes'], ':">
2547
							<option value="0" selected>', $txt['install_settings_reg_immediate'], '</option>
2548
							<option value="1">', $txt['install_settings_reg_email'], '</option>
2549
							<option value="2">', $txt['install_settings_reg_admin'], '</option>
2550
							<option value="3">', $txt['install_settings_reg_disabled'], '</option>
2551
						</optgroup>
2552
					</select>
2553
					<br />
2554
					<div class="smalltext block">', $txt['install_settings_reg_mode_info'], '</div>
2555
				</td>
2556
			</tr>
2557
			<tr>
2558
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_compress'], ':</td>
2559
				<td>
2560
					<input type="checkbox" name="compress" id="compress_check" checked class="input_check" />&nbsp;
2561
					<label for="compress_check">', $txt['install_settings_compress_title'], '</label>
2562
					<br />
2563
					<div class="smalltext block">', $txt['install_settings_compress_info'], '</div>
2564
				</td>
2565
			</tr>
2566
			<tr>
2567
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_dbsession'], ':</td>
2568
				<td>
2569
					<input type="checkbox" name="dbsession" id="dbsession_check" checked class="input_check" />&nbsp;
2570
					<label for="dbsession_check">', $txt['install_settings_dbsession_title'], '</label>
2571
					<br />
2572
					<div class="smalltext block">', $incontext['test_dbsession'] ? $txt['install_settings_dbsession_info1'] : $txt['install_settings_dbsession_info2'], '</div>
2573
				</td>
2574
			</tr>
2575
			<tr>
2576
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_utf8'], ':</td>
2577
				<td>
2578
					<input type="checkbox" name="utf8" id="utf8_check"', $incontext['utf8_default'] ? ' checked' : '', ' class="input_check"', $incontext['utf8_required'] ? ' disabled' : '', ' />&nbsp;
2579
					<label for="utf8_check">', $txt['install_settings_utf8_title'], '</label>
2580
					<br />
2581
					<div class="smalltext block">', $txt['install_settings_utf8_info'], '</div>
2582
				</td>
2583
			</tr>
2584
			<tr>
2585
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_stats'], ':</td>
2586
				<td>
2587
					<input type="checkbox" name="stats" id="stats_check" class="input_check" />&nbsp;
2588
					<label for="stats_check">', $txt['install_settings_stats_title'], '</label>
2589
					<br />
2590
					<div class="smalltext block">', $txt['install_settings_stats_info'], '</div>
2591
				</td>
2592
			</tr>
2593
			<tr>
2594
				<td class="textbox" style="vertical-align: top;">', $txt['force_ssl'], ':</td>
2595
				<td>
2596
					<input type="checkbox" name="force_ssl" id="force_ssl" class="input_check" />&nbsp;
2597
					<label for="force_ssl">', $txt['force_ssl_label'], '</label>
2598
					<br />
2599
					<div class="smalltext block">', $txt['force_ssl_info'], '</div>
2600
				</td>
2601
			</tr>
2602
		</table>
2603
	';
2604
}
2605
2606
// Show results of the database population.
2607
function template_populate_database()
2608
{
2609
	global $incontext, $txt;
2610
2611
	echo '
2612
	<form action="', $incontext['form_url'], '" method="post">
2613
		<p>', !empty($incontext['was_refresh']) ? $txt['user_refresh_install_desc'] : $txt['db_populate_info'], '</p>';
2614
2615
	if (!empty($incontext['sql_results']))
2616
	{
2617
		echo '
2618
		<ul>
2619
			<li>', implode('</li><li>', $incontext['sql_results']), '</li>
2620
		</ul>';
2621
	}
2622
2623
	if (!empty($incontext['failures']))
2624
	{
2625
		echo '
2626
				<div style="color: red;">', $txt['error_db_queries'], '</div>
2627
				<ul>';
2628
2629
		foreach ($incontext['failures'] as $line => $fail)
2630
			echo '
2631
						<li><strong>', $txt['error_db_queries_line'], $line + 1, ':</strong> ', nl2br(htmlspecialchars($fail)), '</li>';
2632
2633
		echo '
2634
				</ul>';
2635
	}
2636
2637
	echo '
2638
		<p>', $txt['db_populate_info2'], '</p>';
2639
2640
	template_warning_divs();
2641
2642
	echo '
2643
	<input type="hidden" name="pop_done" value="1" />';
2644
}
2645
2646
// Create the admin account.
2647
function template_admin_account()
2648
{
2649
	global $incontext, $txt;
2650
2651
	echo '
2652
	<form action="', $incontext['form_url'], '" method="post">
2653
		<p>', $txt['user_settings_info'], '</p>';
2654
2655
	template_warning_divs();
2656
2657
	echo '
2658
		<table width="100%" border="0" style="margin: 2em 0;">
2659
			<tr>
2660
				<td width="18%" valign="top" class="textbox"><label for="username">', $txt['user_settings_username'], ':</label></td>
2661
				<td>
2662
					<input type="text" name="username" id="username" value="', $incontext['username'], '" size="40" class="input_text" />
2663
					<div class="smalltext block">', $txt['user_settings_username_info'], '</div>
2664
				</td>
2665
			</tr><tr>
2666
				<td valign="top" class="textbox"><label for="password1">', $txt['user_settings_password'], ':</label></td>
2667
				<td>
2668
					<input type="password" name="password1" id="password1" size="40" class="input_password" />
2669
					<div class="smalltext block">', $txt['user_settings_password_info'], '</div>
2670
				</td>
2671
			</tr><tr>
2672
				<td valign="top" class="textbox"><label for="password2">', $txt['user_settings_again'], ':</label></td>
2673
				<td>
2674
					<input type="password" name="password2" id="password2" size="40" class="input_password" />
2675
					<div class="smalltext block">', $txt['user_settings_again_info'], '</div>
2676
				</td>
2677
			</tr><tr>
2678
				<td valign="top" class="textbox"><label for="email">', $txt['user_settings_admin_email'], ':</label></td>
2679
				<td>
2680
					<input type="text" name="email" id="email" value="', $incontext['email'], '" size="40" class="input_text" />
2681
					<div class="smalltext block">', $txt['user_settings_admin_email_info'], '</div>
2682
				</td>
2683
			</tr><tr>
2684
				<td valign="top" class="textbox"><label for="server_email">', $txt['user_settings_server_email'], ':</label></td>
2685
				<td>
2686
					<input type="text" name="server_email" id="server_email" value="', $incontext['server_email'], '" size="40" class="input_text" />
2687
					<div class="smalltext block">', $txt['user_settings_server_email_info'], '</div>
2688
				</td>
2689
			</tr>
2690
		</table>';
2691
2692
	if ($incontext['require_db_confirm'])
2693
		echo '
2694
		<h2>', $txt['user_settings_database'], '</h2>
2695
		<p>', $txt['user_settings_database_info'], '</p>
2696
2697
		<div style="margin-bottom: 2ex; padding-', $txt['lang_rtl'] == false ? 'left' : 'right', ': 50px;">
2698
			<input type="password" name="password3" size="30" class="input_password" />
2699
		</div>';
2700
}
2701
2702
// Tell them it's done, and to delete.
2703
function template_delete_install()
2704
{
2705
	global $incontext, $installurl, $txt, $boardurl;
2706
2707
	echo '
2708
		<p>', $txt['congratulations_help'], '</p>';
2709
2710
	template_warning_divs();
2711
2712
	// Install directory still writable?
2713
	if ($incontext['dir_still_writable'])
2714
		echo '
2715
		<em>', $txt['still_writable'], '</em><br />
2716
		<br />';
2717
2718
	// Don't show the box if it's like 99% sure it won't work :P.
2719
	if ($incontext['probably_delete_install'])
2720
		echo '
2721
		<div style="margin: 1ex; font-weight: bold;">
2722
			<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>
2723
		</div>
2724
		<script>
2725
			function doTheDelete()
2726
			{
2727
				var theCheck = document.getElementById ? document.getElementById("delete_self") : document.all.delete_self;
2728
				var tempImage = new Image();
2729
2730
				tempImage.src = "', $installurl, '?delete=1&ts_" + (new Date().getTime());
2731
				tempImage.width = 0;
2732
				theCheck.disabled = true;
2733
			}
2734
		</script>
2735
		<br />';
2736
2737
	echo '
2738
		', sprintf($txt['go_to_your_forum'], $boardurl . '/index.php'), '<br />
2739
		<br />
2740
		', $txt['good_luck'];
2741
}
2742
2743
?>
0 ignored issues
show
Best Practice introduced by
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...
2744