Completed
Push — release-2.1 ( c51392...28ef5a )
by Mert
11:31
created

ftp_connection::chmod()   B

Complexity

Conditions 7
Paths 17

Size

Total Lines 15
Code Lines 18

Duplication

Lines 15
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 15
loc 15
rs 8.2222
cc 7
eloc 18
nc 17
nop 2
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
		if (function_exists($step[2]) && $step[2]() === false)
132
			break;
133
		elseif (function_exists($step[2]))
134
			$incontext['current_step']++;
135
136
		// No warnings pass on.
137
		$incontext['warning'] = '';
138
	}
139
	$incontext['overall_percent'] += $step[3];
140
}
141
142
// Actually do the template stuff.
143
installExit();
144
145
function initialize_inputs()
146
{
147
	global $databases, $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
	if (!isset($_GET['xml']))
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
		if (!isset($_POST['ftp_username']) && isset($_SESSION['installer_temp_ftp']))
588
		{
589
			$_POST['ftp_server'] = $_SESSION['installer_temp_ftp']['server'];
590
			$_POST['ftp_port'] = $_SESSION['installer_temp_ftp']['port'];
591
			$_POST['ftp_username'] = $_SESSION['installer_temp_ftp']['username'];
592
			$_POST['ftp_password'] = $_SESSION['installer_temp_ftp']['password'];
593
			$_POST['ftp_path'] = $_SESSION['installer_temp_ftp']['path'];
594
		}
595
596
		$incontext['ftp_errors'] = array();
597
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
		while ($row = $smcFunc['db_fetch_assoc']($result))
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
	$replaces = array(
1029
		'{$db_prefix}' => $db_prefix,
1030
		'{$attachdir}' => json_encode(array(1 => dirname(__FILE__) . '/attachments')),
1031
		'{$boarddir}' => $smcFunc['db_escape_string'](dirname(__FILE__)),
1032
		'{$boardurl}' => $boardurl,
1033
		'{$enableCompressedOutput}' => isset($_POST['compress']) ? '1' : '0',
1034
		'{$databaseSession_enable}' => isset($_POST['dbsession']) ? '1' : '0',
1035
		'{$smf_version}' => $GLOBALS['current_smf_version'],
1036
		'{$current_time}' => time(),
1037
		'{$sched_task_offset}' => 82800 + mt_rand(0, 86399),
1038
		'{$registration_method}' => isset($_POST['reg_mode']) ? $_POST['reg_mode'] : 0,
1039
	);
1040
1041
	foreach ($txt as $key => $value)
1042
	{
1043
		if (substr($key, 0, 8) == 'default_')
1044
			$replaces['{$' . $key . '}'] = $smcFunc['db_escape_string']($value);
1045
	}
1046
	$replaces['{$default_reserved_names}'] = strtr($replaces['{$default_reserved_names}'], array('\\\\n' => '\\n'));
1047
1048
	// MySQL-specific stuff - storage engine and UTF8 handling
1049
	if (substr($db_type, 0, 5) == 'mysql')
1050
	{
1051
		// Just in case the query fails for some reason...
1052
		$engines = array();
1053
1054
		// Figure out storage engines - what do we have, etc.
1055
		$get_engines = $smcFunc['db_query']('', 'SHOW ENGINES', array());
1056
1057 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...
1058
		{
1059
			if ($row['Support'] == 'YES' || $row['Support'] == 'DEFAULT')
1060
				$engines[] = $row['Engine'];
1061
		}
1062
1063
		// Done with this now
1064
		$smcFunc['db_free_result']($get_engines);
1065
1066
		// InnoDB is better, so use it if possible...
1067
		$has_innodb = in_array('InnoDB', $engines);
1068
		$replaces['{$engine}'] = $has_innodb ? 'InnoDB' : 'MyISAM';
1069
		$replaces['{$memory}'] = (!$has_innodb && in_array('MEMORY', $engines)) ? 'MEMORY' : $replaces['{$engine}'];
1070
1071
		// If the UTF-8 setting was enabled, add it to the table definitions.
1072
		if (!empty($databases[$db_type]['utf8_support']) && (!empty($databases[$db_type]['utf8_required']) || isset($_POST['utf8'])))
1073
		{
1074
			$replaces['{$engine}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1075
			$replaces['{$memory}'] .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
1076
		}
1077
1078
		// One last thing - if we don't have InnoDB, we can't do transactions...
1079
		if (!$has_innodb)
1080
		{
1081
			$replaces['START TRANSACTION;'] = '';
1082
			$replaces['COMMIT;'] = '';
1083
		}
1084
	} 
1085
	else 
1086
	{
1087
		$has_innodb = false;
1088
	}
1089
1090
	// PostgreSQL-specific stuff - unlogged table
1091
	if ($db_type == 'postgresql')
1092
	{
1093
		$result = $smcFunc['db_query']('', '
1094
			SHOW server_version_num'
1095
		);
1096
		if ($result !== false)
1097
		{
1098
			while ($row = $smcFunc['db_fetch_assoc']($result))
1099
				$pg_version = $row['server_version_num'];
1100
			$smcFunc['db_free_result']($result);
1101
		}
1102
		
1103
		if(isset($pg_version) && $pg_version >= 90100)
1104
			$replaces['{$unlogged}'] = 'UNLOGGED';
1105
		else
1106
			$replaces['{$unlogged}'] = '';
1107
	}
1108
1109
	// Read in the SQL.  Turn this on and that off... internationalize... etc.
1110
	$type = ($db_type == 'mysqli' ? 'mysql' : $db_type);
1111
	$sql_lines = explode("\n", strtr(implode(' ', file(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $type . '.sql')), $replaces));
1112
1113
	// Execute the SQL.
1114
	$current_statement = '';
1115
	$exists = array();
1116
	$incontext['failures'] = array();
1117
	$incontext['sql_results'] = array(
1118
		'tables' => 0,
1119
		'inserts' => 0,
1120
		'table_dups' => 0,
1121
		'insert_dups' => 0,
1122
	);
1123
	foreach ($sql_lines as $count => $line)
1124
	{
1125
		// No comments allowed!
1126
		if (substr(trim($line), 0, 1) != '#')
1127
			$current_statement .= "\n" . rtrim($line);
1128
1129
		// Is this the end of the query string?
1130
		if (empty($current_statement) || (preg_match('~;[\s]*$~s', $line) == 0 && $count != count($sql_lines)))
1131
			continue;
1132
1133
		// Does this table already exist?  If so, don't insert more data into it!
1134
		if (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) != 0 && in_array($match[1], $exists))
1135
		{
1136
			preg_match_all('~\)[,;]~', $current_statement, $matches);
1137 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...
1138
				$incontext['sql_results']['insert_dups'] += count($matches[0]);
1139
			else
1140
				$incontext['sql_results']['insert_dups']++;
1141
1142
			$current_statement = '';
1143
			continue;
1144
		}
1145
1146
		if ($smcFunc['db_query']('', $current_statement, array('security_override' => true, 'db_error_skip' => true), $db_connection) === false)
1147
		{
1148
			// Use the appropriate function based on the DB type
1149
			if ($db_type == 'mysql' || $db_type =='mysqli')
1150
				$db_errorno = $db_type . '_errno';
1151
1152
			// Error 1050: Table already exists!
1153
			// @todo Needs to be made better!
1154
			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...
1155
			{
1156
				$exists[] = $match[1];
1157
				$incontext['sql_results']['table_dups']++;
1158
			}
1159
			// Don't error on duplicate indexes (or duplicate operators in PostgreSQL.)
1160
			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)))
1161
			{
1162
				// MySQLi requires a connection object. It's optional with MySQL and Postgres
1163
				$incontext['failures'][$count] = $smcFunc['db_error']($db_connection);
1164
			}
1165
		}
1166
		else
1167
		{
1168
			if (preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1169
				$incontext['sql_results']['tables']++;
1170
			elseif (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1171
			{
1172
				preg_match_all('~\)[,;]~', $current_statement, $matches);
1173 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...
1174
					$incontext['sql_results']['inserts'] += count($matches[0]);
1175
				else
1176
					$incontext['sql_results']['inserts']++;
1177
			}
1178
		}
1179
1180
		$current_statement = '';
1181
1182
		// Wait, wait, I'm still working here!
1183
		set_time_limit(60);
1184
	}
1185
1186
	// Sort out the context for the SQL.
1187
	foreach ($incontext['sql_results'] as $key => $number)
1188
	{
1189
		if ($number == 0)
1190
			unset($incontext['sql_results'][$key]);
1191
		else
1192
			$incontext['sql_results'][$key] = sprintf($txt['db_populate_' . $key], $number);
1193
	}
1194
1195
	// Make sure UTF will be used globally.
1196
	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'])))
1197
		$newSettings[] = array('global_character_set', 'UTF-8');
1198
1199
	// Maybe we can auto-detect better cookie settings?
1200
	preg_match('~^http[s]?://([^\.]+?)([^/]*?)(/.*)?$~', $boardurl, $matches);
1201
	if (!empty($matches))
1202
	{
1203
		// Default = both off.
1204
		$localCookies = false;
1205
		$globalCookies = false;
1206
1207
		// Okay... let's see.  Using a subdomain other than www.? (not a perfect check.)
1208
		if ($matches[2] != '' && (strpos(substr($matches[2], 1), '.') === false || in_array($matches[1], array('forum', 'board', 'community', 'forums', 'support', 'chat', 'help', 'talk', 'boards', 'www'))))
1209
			$globalCookies = true;
1210
		// If there's a / in the middle of the path, or it starts with ~... we want local.
1211
		if (isset($matches[3]) && strlen($matches[3]) > 3 && (substr($matches[3], 0, 2) == '/~' || strpos(substr($matches[3], 1), '/') !== false))
1212
			$localCookies = true;
1213
1214
		if ($globalCookies)
1215
			$newSettings[] = array('globalCookies', '1');
1216
		if ($localCookies)
1217
			$newSettings[] = array('localCookies', '1');
1218
	}
1219
1220
	// Are we allowing stat collection?
1221
	if (isset($_POST['stats']) && strpos($_POST['boardurl'], 'http://localhost') !== 0)
1222
	{
1223
		// Attempt to register the site etc.
1224
		$fp = @fsockopen("www.simplemachines.org", 80, $errno, $errstr);
1225
		if ($fp)
1226
		{
1227
			$out = "GET /smf/stats/register_stats.php?site=" . base64_encode($_POST['boardurl']) . " HTTP/1.1\r\n";
1228
			$out .= "Host: www.simplemachines.org\r\n";
1229
			$out .= "Connection: Close\r\n\r\n";
1230
			fwrite($fp, $out);
1231
1232
			$return_data = '';
1233
			while (!feof($fp))
1234
				$return_data .= fgets($fp, 128);
1235
1236
			fclose($fp);
1237
1238
			// Get the unique site ID.
1239
			preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1240
1241
			if (!empty($ID[1]))
1242
				$newSettings[] = array('allow_sm_stats', $ID[1]);
1243
		}
1244
	}
1245
1246
	// Are we enabling SSL?
1247
	if (!empty($_POST['force_ssl']))
1248
		$newSettings[] = array('force_ssl', 2);
1249
1250
	// As of PHP 5.1, setting a timezone is required.
1251
	if (!isset($modSettings['default_timezone']) && function_exists('date_default_timezone_set'))
1252
	{
1253
		$server_offset = mktime(0, 0, 0, 1, 1, 1970);
1254
		$timezone_id = 'Etc/GMT' . ($server_offset > 0 ? '+' : '') . ($server_offset / 3600);
1255
		if (date_default_timezone_set($timezone_id))
1256
			$newSettings[] = array('default_timezone', $timezone_id);
1257
	}
1258
1259
	if (!empty($newSettings))
1260
	{
1261
		$smcFunc['db_insert']('replace',
1262
			'{db_prefix}settings',
1263
			array('variable' => 'string-255', 'value' => 'string-65534'),
1264
			$newSettings,
1265
			array('variable')
1266
		);
1267
	}
1268
1269
	// Let's optimize those new tables, but not on InnoDB, ok?
1270
	if (!$has_innodb)
1271
	{
1272
		db_extend();
1273
		$tables = $smcFunc['db_list_tables']($db_name, $db_prefix . '%');
1274
		foreach ($tables as $table)
1275
		{
1276
			$smcFunc['db_optimize_table']($table) != -1 or $db_messed = true;
1277
1278
			if (!empty($db_messed))
1279
			{
1280
				$incontext['failures'][-1] = $smcFunc['db_error']();
1281
				break;
1282
			}
1283
		}
1284
	}
1285
	
1286
	// MySQL specific stuff 
1287
	IF (substr($db_type, 0, 5) != 'mysql')
1288
		return false;
1289
	
1290
	// Find database user privileges.
1291
	$privs = array();
1292
	$get_privs = $smcFunc['db_query']('', 'SHOW PRIVILEGES', array());
1293
	while ($row = $smcFunc['db_fetch_assoc']($get_privs))
1294
	{
1295
		if ($row['Privilege'] == 'Alter')
1296
			$privs[] = $row['Privilege'];
1297
	}
1298
	$smcFunc['db_free_result']($get_privs);
1299
1300
	// Check for the ALTER privilege.
1301
	if (!empty($databases[$db_type]['alter_support']) && !in_array('Alter', $privs))
1302
	{
1303
		$incontext['error'] = $txt['error_db_alter_priv'];
1304
		return false;
1305
	}
1306
1307
	if (!empty($exists))
1308
	{
1309
		$incontext['page_title'] = $txt['user_refresh_install'];
1310
		$incontext['was_refresh'] = true;
1311
	}
1312
1313
	return false;
1314
}
1315
1316
// Ask for the administrator login information.
1317
function AdminAccount()
1318
{
1319
	global $txt, $db_type, $db_connection, $smcFunc, $incontext, $db_prefix, $db_passwd, $sourcedir, $db_character_set;
1320
1321
	$incontext['sub_template'] = 'admin_account';
1322
	$incontext['page_title'] = $txt['user_settings'];
1323
	$incontext['continue'] = 1;
1324
1325
	// Skipping?
1326
	if (!empty($_POST['skip']))
1327
		return true;
1328
1329
	// Need this to check whether we need the database password.
1330
	require(dirname(__FILE__) . '/Settings.php');
1331
	load_database();
1332
1333
	require_once($sourcedir . '/Subs-Auth.php');
1334
1335
	// We need this to properly hash the password for Admin
1336
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' :
1337
		create_function('$string', '
1338
			global $sourcedir;
1339
			if (function_exists(\'mb_strtolower\'))
1340
				return mb_strtolower($string, \'UTF-8\');
1341
			require_once($sourcedir . \'/Subs-Charset.php\');
1342
			return utf8_strtolower($string);
1343
		');
1344
1345
	if (!isset($_POST['username']))
1346
		$_POST['username'] = '';
1347
	if (!isset($_POST['email']))
1348
		$_POST['email'] = '';
1349
	if (!isset($_POST['server_email']))
1350
		$_POST['server_email'] = '';
1351
1352
	$incontext['username'] = htmlspecialchars(stripslashes($_POST['username']));
1353
	$incontext['email'] = htmlspecialchars(stripslashes($_POST['email']));
1354
	$incontext['server_email'] = htmlspecialchars(stripslashes($_POST['server_email']));
1355
1356
	$incontext['require_db_confirm'] = empty($db_type);
1357
1358
	// Only allow skipping if we think they already have an account setup.
1359
	$request = $smcFunc['db_query']('', '
1360
		SELECT id_member
1361
		FROM {db_prefix}members
1362
		WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
1363
		LIMIT 1',
1364
		array(
1365
			'db_error_skip' => true,
1366
			'admin_group' => 1,
1367
		)
1368
	);
1369
	if ($smcFunc['db_num_rows']($request) != 0)
1370
		$incontext['skip'] = 1;
1371
	$smcFunc['db_free_result']($request);
1372
1373
	// Trying to create an account?
1374
	if (isset($_POST['password1']) && !empty($_POST['contbutt']))
1375
	{
1376
		// Wrong password?
1377
		if ($incontext['require_db_confirm'] && $_POST['password3'] != $db_passwd)
1378
		{
1379
			$incontext['error'] = $txt['error_db_connect'];
1380
			return false;
1381
		}
1382
		// Not matching passwords?
1383
		if ($_POST['password1'] != $_POST['password2'])
1384
		{
1385
			$incontext['error'] = $txt['error_user_settings_again_match'];
1386
			return false;
1387
		}
1388
		// No password?
1389
		if (strlen($_POST['password1']) < 4)
1390
		{
1391
			$incontext['error'] = $txt['error_user_settings_no_password'];
1392
			return false;
1393
		}
1394
		if (!file_exists($sourcedir . '/Subs.php'))
1395
		{
1396
			$incontext['error'] = $txt['error_subs_missing'];
1397
			return false;
1398
		}
1399
1400
		// Update the webmaster's email?
1401
		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...
1402
			updateSettingsFile(array('webmaster_email' => $_POST['server_email']));
1403
1404
		// Work out whether we're going to have dodgy characters and remove them.
1405
		$invalid_characters = preg_match('~[<>&"\'=\\\]~', $_POST['username']) != 0;
1406
		$_POST['username'] = preg_replace('~[<>&"\'=\\\]~', '', $_POST['username']);
1407
1408
		$result = $smcFunc['db_query']('', '
1409
			SELECT id_member, password_salt
1410
			FROM {db_prefix}members
1411
			WHERE member_name = {string:username} OR email_address = {string:email}
1412
			LIMIT 1',
1413
			array(
1414
				'username' => stripslashes($_POST['username']),
1415
				'email' => stripslashes($_POST['email']),
1416
				'db_error_skip' => true,
1417
			)
1418
		);
1419
		if ($smcFunc['db_num_rows']($result) != 0)
1420
		{
1421
			list ($incontext['member_id'], $incontext['member_salt']) = $smcFunc['db_fetch_row']($result);
1422
			$smcFunc['db_free_result']($result);
1423
1424
			$incontext['account_existed'] = $txt['error_user_settings_taken'];
1425
		}
1426
		elseif ($_POST['username'] == '' || strlen($_POST['username']) > 25)
1427
		{
1428
			// Try the previous step again.
1429
			$incontext['error'] = $_POST['username'] == '' ? $txt['error_username_left_empty'] : $txt['error_username_too_long'];
1430
			return false;
1431
		}
1432
		elseif ($invalid_characters || $_POST['username'] == '_' || $_POST['username'] == '|' || strpos($_POST['username'], '[code') !== false || strpos($_POST['username'], '[/code') !== false)
1433
		{
1434
			// Try the previous step again.
1435
			$incontext['error'] = $txt['error_invalid_characters_username'];
1436
			return false;
1437
		}
1438 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...
1439
		{
1440
			// One step back, this time fill out a proper admin email address.
1441
			$incontext['error'] = sprintf($txt['error_valid_admin_email_needed'], $_POST['username']);
1442
			return false;
1443
		}
1444 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...
1445
		{
1446
			// One step back, this time fill out a proper admin email address.
1447
			$incontext['error'] = $txt['error_valid_server_email_needed'];
1448
			return false;
1449
		}
1450
		elseif ($_POST['username'] != '')
1451
		{
1452
			$incontext['member_salt'] = substr(md5(mt_rand()), 0, 4);
1453
1454
			// Format the username properly.
1455
			$_POST['username'] = preg_replace('~[\t\n\r\x0B\0\xA0]+~', ' ', $_POST['username']);
1456
			$ip = isset($_SERVER['REMOTE_ADDR']) ? substr($_SERVER['REMOTE_ADDR'], 0, 255) : '';
1457
1458
			$_POST['password1'] = hash_password(stripslashes($_POST['username']), stripslashes($_POST['password1']));
1459
1460
			$request = $smcFunc['db_insert']('',
1461
				$db_prefix . 'members',
1462
				array(
1463
					'member_name' => 'string-25', 'real_name' => 'string-25', 'passwd' => 'string', 'email_address' => 'string',
1464
					'id_group' => 'int', 'posts' => 'int', 'date_registered' => 'int',
1465
					'password_salt' => 'string', 'lngfile' => 'string', 'personal_text' => 'string', 'avatar' => 'string',
1466
					'member_ip' => 'string', 'member_ip2' => 'string', 'buddy_list' => 'string', 'pm_ignore_list' => 'string',
1467
					'website_title' => 'string', 'website_url' => 'string',
1468
					'signature' => 'string', 'usertitle' => 'string', 'secret_question' => 'string',
1469
					'additional_groups' => 'string', 'ignore_boards' => 'string',
1470
				),
1471
				array(
1472
					stripslashes($_POST['username']), stripslashes($_POST['username']), $_POST['password1'], stripslashes($_POST['email']),
1473
					1, 0, time(),
1474
					$incontext['member_salt'], '', '', '',
1475
					$ip, $ip, '', '',
1476
					'', '',
1477
					'', '', '',
1478
					'', '',
1479
				),
1480
				array('id_member')
1481
			);
1482
1483
			// Awww, crud!
1484
			if ($request === false)
1485
			{
1486
				$incontext['error'] = $txt['error_user_settings_query'] . '<br>
1487
				<div style="margin: 2ex;">' . nl2br(htmlspecialchars($smcFunc['db_error']($db_connection))) . '</div>';
1488
				return false;
1489
			}
1490
1491
			$incontext['member_id'] = $smcFunc['db_insert_id']("{$db_prefix}members", 'id_member');
1492
		}
1493
1494
		// If we're here we're good.
1495
		return true;
1496
	}
1497
1498
	return false;
1499
}
1500
1501
// Final step, clean up and a complete message!
1502
function DeleteInstall()
1503
{
1504
	global $txt, $incontext;
1505
	global $smcFunc, $db_character_set, $context, $cookiename;
1506
	global $current_smf_version, $databases, $sourcedir, $forum_version, $modSettings, $user_info, $db_type, $boardurl;
1507
1508
	$incontext['page_title'] = $txt['congratulations'];
1509
	$incontext['sub_template'] = 'delete_install';
1510
	$incontext['continue'] = 0;
1511
1512
	require(dirname(__FILE__) . '/Settings.php');
1513
	load_database();
1514
1515
	chdir(dirname(__FILE__));
1516
1517
	require_once($sourcedir . '/Errors.php');
1518
	require_once($sourcedir . '/Logging.php');
1519
	require_once($sourcedir . '/Subs.php');
1520
	require_once($sourcedir . '/Load.php');
1521
	require_once($sourcedir . '/Security.php');
1522
	require_once($sourcedir . '/Subs-Auth.php');
1523
1524
	// Bring a warning over.
1525
	if (!empty($incontext['account_existed']))
1526
		$incontext['warning'] = $incontext['account_existed'];
1527
1528
	if (!empty($db_character_set) && !empty($databases[$db_type]['utf8_support']))
1529
		$smcFunc['db_query']('', '
1530
			SET NAMES {raw:db_character_set}',
1531
			array(
1532
				'db_character_set' => $db_character_set,
1533
				'db_error_skip' => true,
1534
			)
1535
		);
1536
1537
	// As track stats is by default enabled let's add some activity.
1538
	$smcFunc['db_insert']('ignore',
1539
		'{db_prefix}log_activity',
1540
		array('date' => 'date', 'topics' => 'int', 'posts' => 'int', 'registers' => 'int'),
1541
		array(strftime('%Y-%m-%d', time()), 1, 1, (!empty($incontext['member_id']) ? 1 : 0)),
1542
		array('date')
1543
	);
1544
1545
	// We're going to want our lovely $modSettings now.
1546
	$request = $smcFunc['db_query']('', '
1547
		SELECT variable, value
1548
		FROM {db_prefix}settings',
1549
		array(
1550
			'db_error_skip' => true,
1551
		)
1552
	);
1553
	// Only proceed if we can load the data.
1554
	if ($request)
1555
	{
1556 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...
1557
			$modSettings[$row[0]] = $row[1];
1558
		$smcFunc['db_free_result']($request);
1559
	}
1560
1561
	// Automatically log them in ;)
1562
	if (isset($incontext['member_id']) && isset($incontext['member_salt']))
1563
		setLoginCookie(3153600 * 60, $incontext['member_id'], hash_salt($_POST['password1'], $incontext['member_salt']));
1564
1565
	$result = $smcFunc['db_query']('', '
1566
		SELECT value
1567
		FROM {db_prefix}settings
1568
		WHERE variable = {string:db_sessions}',
1569
		array(
1570
			'db_sessions' => 'databaseSession_enable',
1571
			'db_error_skip' => true,
1572
		)
1573
	);
1574 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...
1575
		list ($db_sessions) = $smcFunc['db_fetch_row']($result);
1576
	$smcFunc['db_free_result']($result);
1577
1578
	if (empty($db_sessions))
1579
		$_SESSION['admin_time'] = time();
1580
	else
1581
	{
1582
		$_SERVER['HTTP_USER_AGENT'] = substr($_SERVER['HTTP_USER_AGENT'], 0, 211);
1583
1584
		$smcFunc['db_insert']('replace',
1585
			'{db_prefix}sessions',
1586
			array(
1587
				'session_id' => 'string', 'last_update' => 'int', 'data' => 'string',
1588
			),
1589
			array(
1590
				session_id(), time(), 'USER_AGENT|s:' . strlen($_SERVER['HTTP_USER_AGENT']) . ':"' . $_SERVER['HTTP_USER_AGENT'] . '";admin_time|i:' . time() . ';',
1591
			),
1592
			array('session_id')
1593
		);
1594
	}
1595
1596
	updateStats('member');
1597
	updateStats('message');
1598
	updateStats('topic');
1599
1600
	// This function is needed to do the updateStats('subject') call.
1601
	$smcFunc['strtolower'] = $db_character_set != 'utf8' && $txt['lang_character_set'] != 'UTF-8' ? 'strtolower' :
1602
		create_function('$string', '
1603
			global $sourcedir;
1604
			if (function_exists(\'mb_strtolower\'))
1605
				return mb_strtolower($string, \'UTF-8\');
1606
			require_once($sourcedir . \'/Subs-Charset.php\');
1607
			return utf8_strtolower($string);
1608
		');
1609
1610
	$request = $smcFunc['db_query']('', '
1611
		SELECT id_msg
1612
		FROM {db_prefix}messages
1613
		WHERE id_msg = 1
1614
			AND modified_time = 0
1615
		LIMIT 1',
1616
		array(
1617
			'db_error_skip' => true,
1618
		)
1619
	);
1620
	$context['utf8'] = $db_character_set === 'utf8' || $txt['lang_character_set'] === 'UTF-8';
1621
	if ($smcFunc['db_num_rows']($request) > 0)
1622
		updateStats('subject', 1, htmlspecialchars($txt['default_topic_subject']));
1623
	$smcFunc['db_free_result']($request);
1624
1625
	// Now is the perfect time to fetch the SM files.
1626
	require_once($sourcedir . '/ScheduledTasks.php');
1627
	// Sanity check that they loaded earlier!
1628
	if (isset($modSettings['recycle_board']))
1629
	{
1630
		$forum_version = $current_smf_version;  // The variable is usually defined in index.php so lets just use our variable to do it for us.
1631
		scheduled_fetchSMfiles(); // Now go get those files!
1632
1633
		// We've just installed!
1634
		$user_info['ip'] = $_SERVER['REMOTE_ADDR'];
1635
		$user_info['id'] = isset($incontext['member_id']) ? $incontext['member_id'] : 0;
1636
		logAction('install', array('version' => $forum_version), 'admin');
1637
	}
1638
1639
	// Check if we need some stupid MySQL fix.
1640
	$server_version = $smcFunc['db_server_info']();
1641
	if (($db_type == 'mysql' || $db_type == 'mysqli') && in_array(substr($server_version, 0, 6), array('5.0.50', '5.0.51')))
1642
		updateSettings(array('db_mysql_group_by_fix' => '1'));
1643
1644
	// Some final context for the template.
1645
	$incontext['dir_still_writable'] = is_writable(dirname(__FILE__)) && substr(__FILE__, 1, 2) != ':\\';
1646
	$incontext['probably_delete_install'] = isset($_SESSION['installer_temp_ftp']) || is_writable(dirname(__FILE__)) || is_writable(__FILE__);
1647
1648
	// Update hash's cost to an appropriate setting
1649
	updateSettings(array(
1650
		'bcrypt_hash_cost' => hash_benchmark(),
1651
	));
1652
1653
	return false;
1654
}
1655
1656
// http://www.faqs.org/rfcs/rfc959.html
1657
class ftp_connection
1658
{
1659
	var $connection = 'no_connection', $error = false, $last_message, $pasv = array();
1660
1661
	// Create a new FTP connection...
1662
	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...
1663
	{
1664
		if ($ftp_server !== null)
1665
			$this->connect($ftp_server, $ftp_port, $ftp_user, $ftp_pass);
1666
	}
1667
1668
	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...
1669
	{
1670
		if (substr($ftp_server, 0, 6) == 'ftp://')
1671
			$ftp_server = substr($ftp_server, 6);
1672
		elseif (substr($ftp_server, 0, 7) == 'ftps://')
1673
			$ftp_server = 'ssl://' . substr($ftp_server, 7);
1674
		if (substr($ftp_server, 0, 7) == 'http://')
1675
			$ftp_server = substr($ftp_server, 7);
1676
		$ftp_server = strtr($ftp_server, array('/' => '', ':' => '', '@' => ''));
1677
1678
		// Connect to the FTP server.
1679
		$this->connection = @fsockopen($ftp_server, $ftp_port, $err, $err, 5);
1680
		if (!$this->connection)
1681
		{
1682
			$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...
1683
			return;
1684
		}
1685
1686
		// Get the welcome message...
1687
		if (!$this->check_response(220))
1688
		{
1689
			$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...
1690
			return;
1691
		}
1692
1693
		// Send the username, it should ask for a password.
1694
		fwrite($this->connection, 'USER ' . $ftp_user . "\r\n");
1695
		if (!$this->check_response(331))
1696
		{
1697
			$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...
1698
			return;
1699
		}
1700
1701
		// Now send the password... and hope it goes okay.
1702
		fwrite($this->connection, 'PASS ' . $ftp_pass . "\r\n");
1703
		if (!$this->check_response(230))
1704
		{
1705
			$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...
1706
			return;
1707
		}
1708
	}
1709
1710 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...
1711
	{
1712
		if (!is_resource($this->connection))
1713
			return false;
1714
1715
		// No slash on the end, please...
1716
		if (substr($ftp_path, -1) == '/')
1717
			$ftp_path = substr($ftp_path, 0, -1);
1718
1719
		fwrite($this->connection, 'CWD ' . $ftp_path . "\r\n");
1720
		if (!$this->check_response(250))
1721
		{
1722
			$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...
1723
			return false;
1724
		}
1725
1726
		return true;
1727
	}
1728
1729 View Code Duplication
	function chmod($ftp_file, $chmod)
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...
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...
1730
	{
1731
		if (!is_resource($this->connection))
1732
			return false;
1733
1734
		// Convert the chmod value from octal (0777) to text ("777")
1735
		fwrite($this->connection, 'SITE CHMOD ' . decoct($chmod) . ' ' . $ftp_file . "\r\n");
1736
		if (!$this->check_response(200))
1737
		{
1738
			$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...
1739
			return false;
1740
		}
1741
1742
		return true;
1743
	}
1744
1745 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...
1746
	{
1747
		// We are actually connected, right?
1748
		if (!is_resource($this->connection))
1749
			return false;
1750
1751
		// Delete file X.
1752
		fwrite($this->connection, 'DELE ' . $ftp_file . "\r\n");
1753
		if (!$this->check_response(250))
1754
		{
1755
			fwrite($this->connection, 'RMD ' . $ftp_file . "\r\n");
1756
1757
			// Still no love?
1758
			if (!$this->check_response(250))
1759
			{
1760
				$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...
1761
				return false;
1762
			}
1763
		}
1764
1765
		return true;
1766
	}
1767
1768
	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...
1769
	{
1770
		// Wait for a response that isn't continued with -, but don't wait too long.
1771
		$time = time();
1772
		do
1773
			$this->last_message = fgets($this->connection, 1024);
1774
		while (substr($this->last_message, 3, 1) != ' ' && time() - $time < 5);
1775
1776
		// Was the desired response returned?
1777
		return is_array($desired) ? in_array(substr($this->last_message, 0, 3), $desired) : substr($this->last_message, 0, 3) == $desired;
1778
	}
1779
1780 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...
1781
	{
1782
		// We can't create a passive data connection without a primary one first being there.
1783
		if (!is_resource($this->connection))
1784
			return false;
1785
1786
		// Request a passive connection - this means, we'll talk to you, you don't talk to us.
1787
		@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...
1788
		$time = time();
1789
		do
1790
			$response = fgets($this->connection, 1024);
1791
		while (substr($response, 3, 1) != ' ' && time() - $time < 5);
1792
1793
		// If it's not 227, we weren't given an IP and port, which means it failed.
1794
		if (substr($response, 0, 4) != '227 ')
1795
		{
1796
			$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...
1797
			return false;
1798
		}
1799
1800
		// Snatch the IP and port information, or die horribly trying...
1801
		if (preg_match('~\((\d+),\s*(\d+),\s*(\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))\)~', $response, $match) == 0)
1802
		{
1803
			$this->error = 'bad_response';
1804
			return false;
1805
		}
1806
1807
		// This is pretty simple - store it for later use ;)
1808
		$this->pasv = array('ip' => $match[1] . '.' . $match[2] . '.' . $match[3] . '.' . $match[4], 'port' => $match[5] * 256 + $match[6]);
1809
1810
		return true;
1811
	}
1812
1813 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...
1814
	{
1815
		// First, we have to be connected... very important.
1816
		if (!is_resource($this->connection))
1817
			return false;
1818
1819
		// I'd like one passive mode, please!
1820
		if (!$this->passive())
1821
			return false;
1822
1823
		// Seems logical enough, so far...
1824
		fwrite($this->connection, 'STOR ' . $ftp_file . "\r\n");
1825
1826
		// Okay, now we connect to the data port.  If it doesn't work out, it's probably "file already exists", etc.
1827
		$fp = @fsockopen($this->pasv['ip'], $this->pasv['port'], $err, $err, 5);
1828
		if (!$fp || !$this->check_response(150))
1829
		{
1830
			$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...
1831
			@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...
1832
			return false;
1833
		}
1834
1835
		// This may look strange, but we're just closing it to indicate a zero-byte upload.
1836
		fclose($fp);
1837
		if (!$this->check_response(226))
1838
		{
1839
			$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...
1840
			return false;
1841
		}
1842
1843
		return true;
1844
	}
1845
1846 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...
1847
	{
1848
		// Are we even connected...?
1849
		if (!is_resource($this->connection))
1850
			return false;
1851
1852
		// Passive... non-agressive...
1853
		if (!$this->passive())
1854
			return false;
1855
1856
		// Get the listing!
1857
		fwrite($this->connection, 'LIST -1' . ($search ? 'R' : '') . ($ftp_path == '' ? '' : ' ' . $ftp_path) . "\r\n");
1858
1859
		// Connect, assuming we've got a connection.
1860
		$fp = @fsockopen($this->pasv['ip'], $this->pasv['port'], $err, $err, 5);
1861
		if (!$fp || !$this->check_response(array(150, 125)))
1862
		{
1863
			$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...
1864
			@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...
1865
			return false;
1866
		}
1867
1868
		// Read in the file listing.
1869
		$data = '';
1870
		while (!feof($fp))
1871
			$data .= fread($fp, 4096);
1872
		fclose($fp);
1873
1874
		// Everything go okay?
1875
		if (!$this->check_response(226))
1876
		{
1877
			$this->error = 'bad_response';
1878
			return false;
1879
		}
1880
1881
		return $data;
1882
	}
1883
1884
	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...
1885
	{
1886
		if ($listing === null)
1887
			$listing = $this->list_dir('', true);
1888
		$listing = explode("\n", $listing);
1889
1890
		@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...
1891
		$time = time();
1892
		do
1893
			$response = fgets($this->connection, 1024);
1894
		while (substr($response, 3, 1) != ' ' && time() - $time < 5);
1895
1896
		// Check for 257!
1897
		if (preg_match('~^257 "(.+?)" ~', $response, $match) != 0)
1898
			$current_dir = strtr($match[1], array('""' => '"'));
1899
		else
1900
			$current_dir = '';
1901
1902
		for ($i = 0, $n = count($listing); $i < $n; $i++)
1903
		{
1904
			if (trim($listing[$i]) == '' && isset($listing[$i + 1]))
1905
			{
1906
				$current_dir = substr(trim($listing[++$i]), 0, -1);
1907
				$i++;
1908
			}
1909
1910
			// Okay, this file's name is:
1911
			$listing[$i] = $current_dir . '/' . trim(strlen($listing[$i]) > 30 ? strrchr($listing[$i], ' ') : $listing[$i]);
1912
1913
			if (substr($file, 0, 1) == '*' && substr($listing[$i], -(strlen($file) - 1)) == substr($file, 1))
1914
				return $listing[$i];
1915
			if (substr($file, -1) == '*' && substr($listing[$i], 0, strlen($file) - 1) == substr($file, 0, -1))
1916
				return $listing[$i];
1917
			if (basename($listing[$i]) == $file || $listing[$i] == $file)
1918
				return $listing[$i];
1919
		}
1920
1921
		return false;
1922
	}
1923
1924 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...
1925
	{
1926
		// We must be connected to the server to do something.
1927
		if (!is_resource($this->connection))
1928
			return false;
1929
1930
		// Make this new beautiful directory!
1931
		fwrite($this->connection, 'MKD ' . $ftp_dir . "\r\n");
1932
		if (!$this->check_response(257))
1933
		{
1934
			$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...
1935
			return false;
1936
		}
1937
1938
		return true;
1939
	}
1940
1941 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...
1942
	{
1943
		$username = '';
1944
1945
		if (isset($_SERVER['DOCUMENT_ROOT']))
1946
		{
1947
			if (preg_match('~^/home[2]?/([^/]+?)/public_html~', $_SERVER['DOCUMENT_ROOT'], $match))
1948
			{
1949
				$username = $match[1];
1950
1951
				$path = strtr($_SERVER['DOCUMENT_ROOT'], array('/home/' . $match[1] . '/' => '', '/home2/' . $match[1] . '/' => ''));
1952
1953
				if (substr($path, -1) == '/')
1954
					$path = substr($path, 0, -1);
1955
1956
				if (strlen(dirname($_SERVER['PHP_SELF'])) > 1)
1957
					$path .= dirname($_SERVER['PHP_SELF']);
1958
			}
1959
			elseif (substr($filesystem_path, 0, 9) == '/var/www/')
1960
				$path = substr($filesystem_path, 8);
1961
			else
1962
				$path = strtr(strtr($filesystem_path, array('\\' => '/')), array($_SERVER['DOCUMENT_ROOT'] => ''));
1963
		}
1964
		else
1965
			$path = '';
1966
1967
		if (is_resource($this->connection) && $this->list_dir($path) == '')
1968
		{
1969
			$data = $this->list_dir('', true);
1970
1971
			if ($lookup_file === null)
1972
				$lookup_file = $_SERVER['PHP_SELF'];
1973
1974
			$found_path = dirname($this->locate('*' . basename(dirname($lookup_file)) . '/' . basename($lookup_file), $data));
1975
			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...
1976
				$found_path = dirname($this->locate(basename($lookup_file)));
1977
			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...
1978
				$path = $found_path;
1979
		}
1980
		elseif (is_resource($this->connection))
1981
			$found_path = true;
1982
1983
		return array($username, $path, isset($found_path));
1984
	}
1985
1986
	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...
1987
	{
1988
		// Goodbye!
1989
		fwrite($this->connection, "QUIT\r\n");
1990
		fclose($this->connection);
1991
1992
		return true;
1993
	}
1994
}
1995
1996
function updateSettingsFile($vars)
1997
{
1998
	// Modify Settings.php.
1999
	$settingsArray = file(dirname(__FILE__) . '/Settings.php');
2000
2001
	// @todo Do we just want to read the file in clean, and split it this way always?
2002
	if (count($settingsArray) == 1)
2003
		$settingsArray = preg_split('~[\r\n]~', $settingsArray[0]);
2004
2005
	for ($i = 0, $n = count($settingsArray); $i < $n; $i++)
2006
	{
2007
		// Remove the redirect...
2008
		if (trim($settingsArray[$i]) == 'if (file_exists(dirname(__FILE__) . \'/install.php\'))' && trim($settingsArray[$i + 1]) == '{' && trim($settingsArray[$i + 3]) == '}')
2009
		{
2010
			// Get the four lines to nothing.
2011
			$settingsArray[$i] = '';
2012
			$settingsArray[++$i] = '';
2013
			$settingsArray[++$i] = '';
2014
			$settingsArray[++$i] = '';
2015
			continue;
2016
		}
2017
2018
		if (trim($settingsArray[$i]) == '?' . '>')
2019
			$settingsArray[$i] = '';
2020
2021
		// Don't trim or bother with it if it's not a variable.
2022
		if (substr($settingsArray[$i], 0, 1) != '$')
2023
			continue;
2024
2025
		$settingsArray[$i] = rtrim($settingsArray[$i]) . "\n";
2026
2027
		foreach ($vars as $var => $val)
2028
			if (strncasecmp($settingsArray[$i], '$' . $var, 1 + strlen($var)) == 0)
2029
			{
2030
				$comment = strstr($settingsArray[$i], '#');
2031
				$settingsArray[$i] = '$' . $var . ' = \'' . $val . '\';' . ($comment != '' ? "\t\t" . $comment : "\n");
2032
				unset($vars[$var]);
2033
			}
2034
	}
2035
2036
	// Uh oh... the file wasn't empty... was it?
2037
	if (!empty($vars))
2038
	{
2039
		$settingsArray[$i++] = '';
2040
		foreach ($vars as $var => $val)
2041
			$settingsArray[$i++] = '$' . $var . ' = \'' . $val . '\';' . "\n";
2042
	}
2043
2044
	// Blank out the file - done to fix a oddity with some servers.
2045
	$fp = @fopen(dirname(__FILE__) . '/Settings.php', 'w');
2046
	if (!$fp)
2047
		return false;
2048
	fclose($fp);
2049
2050
	$fp = fopen(dirname(__FILE__) . '/Settings.php', 'r+');
2051
2052
	// Gotta have one of these ;)
2053
	if (trim($settingsArray[0]) != '<?php')
2054
		fwrite($fp, "<?php\n");
2055
2056
	$lines = count($settingsArray);
2057
	for ($i = 0; $i < $lines - 1; $i++)
2058
	{
2059
		// Don't just write a bunch of blank lines.
2060
		if ($settingsArray[$i] != '' || @$settingsArray[$i - 1] != '')
2061
			fwrite($fp, strtr($settingsArray[$i], "\r", ''));
2062
	}
2063
	fwrite($fp, $settingsArray[$i] . '?' . '>');
2064
	fclose($fp);
2065
2066
	// Even though on normal installations the filemtime should prevent this being used by the installer incorrectly
2067
	// it seems that there are times it might not. So let's MAKE it dump the cache.
2068
	if (function_exists('opcache_invalidate'))
2069
		opcache_invalidate(dirname(__FILE__) . '/Settings.php', true);
2070
2071
	return true;
2072
}
2073
2074
function updateDbLastError()
2075
{
2076
	// Write out the db_last_error file with the error timestamp
2077
	file_put_contents(dirname(__FILE__) . '/db_last_error.php', '<' . '?' . "php\n" . '$db_last_error = 0;' . "\n" . '?' . '>');
2078
2079
	return true;
2080
}
2081
2082
// Create an .htaccess file to prevent mod_security. SMF has filtering built-in.
2083
function fixModSecurity()
2084
{
2085
	$htaccess_addition = '
2086
<IfModule mod_security.c>
2087
	# Turn off mod_security filtering.  SMF is a big boy, it doesn\'t need its hands held.
2088
	SecFilterEngine Off
2089
2090
	# The below probably isn\'t needed, but better safe than sorry.
2091
	SecFilterScanPOST Off
2092
</IfModule>';
2093
2094
	if (!function_exists('apache_get_modules') || !in_array('mod_security', apache_get_modules()))
2095
		return true;
2096
	elseif (file_exists(dirname(__FILE__) . '/.htaccess') && is_writable(dirname(__FILE__) . '/.htaccess'))
2097
	{
2098
		$current_htaccess = implode('', file(dirname(__FILE__) . '/.htaccess'));
2099
2100
		// Only change something if mod_security hasn't been addressed yet.
2101
		if (strpos($current_htaccess, '<IfModule mod_security.c>') === false)
2102
		{
2103 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...
2104
			{
2105
				fwrite($ht_handle, $htaccess_addition);
2106
				fclose($ht_handle);
2107
				return true;
2108
			}
2109
			else
2110
				return false;
2111
		}
2112
		else
2113
			return true;
2114
	}
2115
	elseif (file_exists(dirname(__FILE__) . '/.htaccess'))
2116
		return strpos(implode('', file(dirname(__FILE__) . '/.htaccess')), '<IfModule mod_security.c>') !== false;
2117
	elseif (is_writable(dirname(__FILE__)))
2118
	{
2119 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...
2120
		{
2121
			fwrite($ht_handle, $htaccess_addition);
2122
			fclose($ht_handle);
2123
			return true;
2124
		}
2125
		else
2126
			return false;
2127
	}
2128
	else
2129
		return false;
2130
}
2131
2132
function template_install_above()
2133
{
2134
	global $incontext, $txt, $installurl;
2135
2136
	echo '<!DOCTYPE html>
2137
<html', $txt['lang_rtl'] == true ? ' dir="rtl"' : '', '>
2138
	<head>
2139
		<meta charset="', isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8', '">
2140
		<meta name="robots" content="noindex">
2141
		<title>', $txt['smf_installer'], '</title>
2142
		<link rel="stylesheet" href="Themes/default/css/index.css?alp21">
2143
		<link rel="stylesheet" href="Themes/default/css/install.css?alp21">
2144
		', $txt['lang_rtl'] == true ? '<link rel="stylesheet" href="Themes/default/css/rtl.css?alp21">' : '' , '
2145
2146
		<script src="Themes/default/scripts/jquery-2.1.3.min.js"></script>
2147
		<script src="Themes/default/scripts/script.js"></script>
2148
	</head>
2149
	<body><div id="footerfix">
2150
		<div id="header">
2151
			<h1 class="forumtitle">', $txt['smf_installer'], '</h1>
2152
			<img id="smflogo" src="Themes/default/images/smflogo.png" alt="Simple Machines Forum" title="Simple Machines Forum">
2153
		</div>
2154
		<div id="wrapper">
2155
			<div id="upper_section">
2156
				<div id="inner_section">
2157
					<div id="inner_wrap">';
2158
2159
	// Have we got a language drop down - if so do it on the first step only.
2160
	if (!empty($incontext['detected_languages']) && count($incontext['detected_languages']) > 1 && $incontext['current_step'] == 0)
2161
	{
2162
		echo '
2163
						<div class="news">
2164
							<form action="', $installurl, '" method="get">
2165
								<label for="installer_language">', $txt['installer_language'], ':</label>
2166
								<select id="installer_language" name="lang_file" onchange="location.href = \'', $installurl, '?lang_file=\' + this.options[this.selectedIndex].value;">';
2167
2168
		foreach ($incontext['detected_languages'] as $lang => $name)
2169
			echo '
2170
									<option', isset($_SESSION['installer_temp_lang']) && $_SESSION['installer_temp_lang'] == $lang ? ' selected' : '', ' value="', $lang, '">', $name, '</option>';
2171
2172
		echo '
2173
								</select>
2174
								<noscript><input type="submit" value="', $txt['installer_language_set'], '" class="button_submit" /></noscript>
2175
							</form>
2176
						</div>
2177
						<hr class="clear" />';
2178
	}
2179
2180
	echo '
2181
					</div>
2182
				</div>
2183
			</div>
2184
			<div id="content_section">
2185
				<div id="main_content_section">
2186
					<div id="main_steps">
2187
						<h2>', $txt['upgrade_progress'], '</h2>
2188
						<ul>';
2189
2190
	foreach ($incontext['steps'] as $num => $step)
2191
		echo '
2192
							<li class="', $num < $incontext['current_step'] ? 'stepdone' : ($num == $incontext['current_step'] ? 'stepcurrent' : 'stepwaiting'), '">', $txt['upgrade_step'], ' ', $step[0], ': ', $step[1], '</li>';
2193
2194
	echo '
2195
						</ul>
2196
					</div>
2197
					<div id="progress_bar">
2198
						<div id="overall_text">', $incontext['overall_percent'], '%</div>
2199
						<div id="overall_progress" style="width: ', $incontext['overall_percent'], '%;">&nbsp;</div>
2200
						<div class="overall_progress">', $txt['upgrade_overall_progress'], '</div>
2201
					</div>
2202
					<div id="main_screen" class="clear">
2203
						<h2>', $incontext['page_title'], '</h2>
2204
						<div class="panel">';
2205
}
2206
2207
function template_install_below()
2208
{
2209
	global $incontext, $txt;
2210
2211
	if (!empty($incontext['continue']) || !empty($incontext['skip']))
2212
	{
2213
		echo '
2214
								<div>';
2215
2216
		if (!empty($incontext['continue']))
2217
			echo '
2218
									<input type="submit" id="contbutt" name="contbutt" value="', $txt['upgrade_continue'], '" onclick="return submitThisOnce(this);" class="button_submit" />';
2219
		if (!empty($incontext['skip']))
2220
			echo '
2221
									<input type="submit" id="skip" name="skip" value="', $txt['upgrade_skip'], '" onclick="return submitThisOnce(this);" class="button_submit" />';
2222
		echo '
2223
								</div>';
2224
	}
2225
2226
	// Show the closing form tag and other data only if not in the last step
2227
	if (count($incontext['steps']) - 1 !== (int) $incontext['current_step'])
2228
		echo '
2229
							</form>';
2230
2231
	echo '
2232
						</div>
2233
					</div>
2234
				</div>
2235
			</div>
2236
		</div></div>
2237
		<div id="footer">
2238
			<ul>
2239
				<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>
2240
			</ul>
2241
		</div>
2242
	</body>
2243
</html>';
2244
}
2245
2246
// Welcome them to the wonderful world of SMF!
2247
function template_welcome_message()
2248
{
2249
	global $incontext, $txt;
2250
2251
	echo '
2252
	<script src="http://www.simplemachines.org/smf/current-version.js?version=' . $GLOBALS['current_smf_version'] . '"></script>
2253
	<form action="', $incontext['form_url'], '" method="post">
2254
		<p>', sprintf($txt['install_welcome_desc'], $GLOBALS['current_smf_version']), '</p>
2255
		<div id="version_warning" style="margin: 2ex; padding: 2ex; border: 2px dashed #a92174; color: black; background-color: #fbbbe2; display: none;">
2256
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
2257
			<strong style="text-decoration: underline;">', $txt['error_warning_notice'], '</strong><br />
2258
			<div style="padding-left: 6ex;">
2259
				', 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>'), '
2260
			</div>
2261
		</div>';
2262
2263
	// Show the warnings, or not.
2264
	if (template_warning_divs())
2265
		echo '
2266
		<h3>', $txt['install_all_lovely'], '</h3>';
2267
2268
	// Say we want the continue button!
2269
	if (empty($incontext['error']))
2270
		$incontext['continue'] = 1;
2271
2272
	// For the latest version stuff.
2273
	echo '
2274
		<script>
2275
			// Latest version?
2276
			function smfCurrentVersion()
2277
			{
2278
				var smfVer, yourVer;
2279
2280
				if (!(\'smfVersion\' in window))
2281
					return;
2282
2283
				window.smfVersion = window.smfVersion.replace(/SMF\s?/g, \'\');
2284
2285
				smfVer = document.getElementById("smfVersion");
2286
				yourVer = document.getElementById("yourVersion");
2287
2288
				setInnerHTML(smfVer, window.smfVersion);
2289
2290
				var currentVersion = getInnerHTML(yourVer);
2291
				if (currentVersion < window.smfVersion)
2292
					document.getElementById(\'version_warning\').style.display = \'\';
2293
			}
2294
			addLoadEvent(smfCurrentVersion);
2295
		</script>';
2296
}
2297
2298
// A shortcut for any warning stuff.
2299
function template_warning_divs()
2300
{
2301
	global $txt, $incontext;
2302
2303
	// Errors are very serious..
2304
	if (!empty($incontext['error']))
2305
		echo '
2306
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
2307
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
2308
			<strong style="text-decoration: underline;">', $txt['upgrade_critical_error'], '</strong><br />
2309
			<div style="padding-left: 6ex;">
2310
				', $incontext['error'], '
2311
			</div>
2312
		</div>';
2313
	// A warning message?
2314
	elseif (!empty($incontext['warning']))
2315
		echo '
2316
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
2317
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
2318
			<strong style="text-decoration: underline;">', $txt['upgrade_warning'], '</strong><br />
2319
			<div style="padding-left: 6ex;">
2320
				', $incontext['warning'], '
2321
			</div>
2322
		</div>';
2323
2324
	return empty($incontext['error']) && empty($incontext['warning']);
2325
}
2326
2327
function template_chmod_files()
2328
{
2329
	global $txt, $incontext;
2330
2331
	echo '
2332
		<p>', $txt['ftp_setup_why_info'], '</p>
2333
		<ul style="margin: 2.5ex; font-family: monospace;">
2334
			<li>', implode('</li>
2335
			<li>', $incontext['failed_files']), '</li>
2336
		</ul>';
2337
2338
	if (isset($incontext['systemos'], $incontext['detected_path']) && $incontext['systemos'] == 'linux')
2339
		echo '
2340
		<hr />
2341
		<p>', $txt['chmod_linux_info'], '</p>
2342
		<tt># chmod a+w ', implode(' ' . $incontext['detected_path'] . '/', $incontext['failed_files']), '</tt>';
2343
2344
	// This is serious!
2345
	if (!template_warning_divs())
2346
		return;
2347
2348
	echo '
2349
		<hr />
2350
		<p>', $txt['ftp_setup_info'], '</p>';
2351
2352
	if (!empty($incontext['ftp_errors']))
2353
		echo '
2354
		<div class="error_message">
2355
			<div style="color: red;">
2356
				', $txt['error_ftp_no_connect'], '<br />
2357
				<br />
2358
				<code>', implode('<br />', $incontext['ftp_errors']), '</code>
2359
			</div>
2360
		</div>
2361
		<br />';
2362
2363
	echo '
2364
		<form action="', $incontext['form_url'], '" method="post">
2365
			<table align="center" style="width: 520px; margin: 1em 0; padding: 0; border: 0">
2366
				<tr>
2367
					<td width="26%" valign="top" class="textbox"><label for="ftp_server">', $txt['ftp_server'], ':</label></td>
2368
					<td>
2369
						<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>
2370
						<input type="text" size="30" name="ftp_server" id="ftp_server" value="', $incontext['ftp']['server'], '" style="width: 70%;" class="input_text" />
2371
						<div class="smalltext block">', $txt['ftp_server_info'], '</div>
2372
					</td>
2373
				</tr><tr>
2374
					<td width="26%" valign="top" class="textbox"><label for="ftp_username">', $txt['ftp_username'], ':</label></td>
2375
					<td>
2376
						<input type="text" size="50" name="ftp_username" id="ftp_username" value="', $incontext['ftp']['username'], '" style="width: 99%;" class="input_text" />
2377
						<div class="smalltext block">', $txt['ftp_username_info'], '</div>
2378
					</td>
2379
				</tr><tr>
2380
					<td width="26%" valign="top" class="textbox"><label for="ftp_password">', $txt['ftp_password'], ':</label></td>
2381
					<td>
2382
						<input type="password" size="50" name="ftp_password" id="ftp_password" style="width: 99%;" class="input_password" />
2383
						<div class="smalltext block">', $txt['ftp_password_info'], '</div>
2384
					</td>
2385
				</tr><tr>
2386
					<td width="26%" valign="top" class="textbox"><label for="ftp_path">', $txt['ftp_path'], ':</label></td>
2387
					<td style="padding-bottom: 1ex;">
2388
						<input type="text" size="50" name="ftp_path" id="ftp_path" value="', $incontext['ftp']['path'], '" style="width: 99%;" class="input_text" />
2389
						<div class="smalltext block">', $incontext['ftp']['path_msg'], '</div>
2390
					</td>
2391
				</tr>
2392
			</table>
2393
			<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>
2394
		</form>
2395
		<a href="', $incontext['form_url'], '">', $txt['error_message_click'], '</a> ', $txt['ftp_setup_again'];
2396
}
2397
2398
// Get the database settings prepared.
2399
function template_database_settings()
2400
{
2401
	global $incontext, $txt;
2402
2403
	echo '
2404
	<form action="', $incontext['form_url'], '" method="post">
2405
		<p>', $txt['db_settings_info'], '</p>';
2406
2407
	template_warning_divs();
2408
2409
	echo '
2410
		<table width="100%" border="0" style="margin: 1em 0;">';
2411
2412
	// More than one database type?
2413
	if (count($incontext['supported_databases']) > 1)
2414
	{
2415
		echo '
2416
			<tr>
2417
				<td width="20%" valign="top" class="textbox"><label for="db_type_input">', $txt['db_settings_type'], ':</label></td>
2418
				<td>
2419
					<select name="db_type" id="db_type_input" onchange="toggleDBInput();">';
2420
2421
	foreach ($incontext['supported_databases'] as $key => $db)
2422
			echo '
2423
						<option value="', $key, '"', isset($_POST['db_type']) && $_POST['db_type'] == $key ? ' selected' : '', '>', $db['name'], '</option>';
2424
2425
	echo '
2426
					</select>
2427
					<div class="smalltext block">', $txt['db_settings_type_info'], '</div>
2428
				</td>
2429
			</tr>';
2430
	}
2431
	else
2432
	{
2433
		echo '
2434
			<tr style="display: none;">
2435
				<td>
2436
					<input type="hidden" name="db_type" value="', $incontext['db']['type'], '" />
2437
				</td>
2438
			</tr>';
2439
	}
2440
2441
	echo '
2442
			<tr id="db_server_contain">
2443
				<td width="20%" valign="top" class="textbox"><label for="db_server_input">', $txt['db_settings_server'], ':</label></td>
2444
				<td>
2445
					<input type="text" name="db_server" id="db_server_input" value="', $incontext['db']['server'], '" size="30" class="input_text" /><br />
2446
					<div class="smalltext block">', $txt['db_settings_server_info'], '</div>
2447
				</td>
2448
			</tr><tr id="db_port_contain">
2449
				<td width="20%" valign="top" class="textbox"><label for="db_port_input">', $txt['db_settings_port'], ':</label></td>
2450
				<td>
2451
					<input type="text" name="db_port" id="db_port_input" value="', $incontext['db']['port'], '"><br>
2452
					<div class="smalltext block">', $txt['db_settings_port_info'], '</div>
2453
				</td>
2454
			</tr><tr id="db_user_contain">
2455
				<td valign="top" class="textbox"><label for="db_user_input">', $txt['db_settings_username'], ':</label></td>
2456
				<td>
2457
					<input type="text" name="db_user" id="db_user_input" value="', $incontext['db']['user'], '" size="30" class="input_text" /><br />
2458
					<div class="smalltext block">', $txt['db_settings_username_info'], '</div>
2459
				</td>
2460
			</tr><tr id="db_passwd_contain">
2461
				<td valign="top" class="textbox"><label for="db_passwd_input">', $txt['db_settings_password'], ':</label></td>
2462
				<td>
2463
					<input type="password" name="db_passwd" id="db_passwd_input" value="', $incontext['db']['pass'], '" size="30" class="input_password" /><br />
2464
					<div class="smalltext block">', $txt['db_settings_password_info'], '</div>
2465
				</td>
2466
			</tr><tr id="db_name_contain">
2467
				<td valign="top" class="textbox"><label for="db_name_input">', $txt['db_settings_database'], ':</label></td>
2468
				<td>
2469
					<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 />
2470
					<div class="smalltext block">', $txt['db_settings_database_info'], '
2471
					<span id="db_name_info_warning">', $txt['db_settings_database_info_note'], '</span></div>
2472
				</td>
2473
			</tr><tr id="db_filename_contain" style="display: none;">
2474
				<td valign="top" class="textbox"><label for="db_filename_input">', $txt['db_settings_database_file'], ':</label></td>
2475
				<td>
2476
					<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 />
2477
					<div class="smalltext block">', $txt['db_settings_database_file_info'], '</div>
2478
				</td>
2479
			</tr><tr>
2480
				<td valign="top" class="textbox"><label for="db_prefix_input">', $txt['db_settings_prefix'], ':</label></td>
2481
				<td>
2482
					<input type="text" name="db_prefix" id="db_prefix_input" value="', $incontext['db']['prefix'], '" size="30" class="input_text" /><br />
2483
					<div class="smalltext block">', $txt['db_settings_prefix_info'], '</div>
2484
				</td>
2485
			</tr>
2486
		</table>';
2487
2488
	// Toggles a warning related to db names in PostgreSQL
2489
	echo '
2490
	<script>
2491
		function toggleDBInput()
2492
		{
2493
			if (document.getElementById(\'db_type_input\').value == \'postgresql\')
2494
				document.getElementById(\'db_name_info_warning\').style.display = \'none\';
2495
			else
2496
				document.getElementById(\'db_name_info_warning\').style.display = \'\';
2497
		}
2498
		toggleDBInput();
2499
	</script>';
2500
}
2501
2502
// Stick in their forum settings.
2503
function template_forum_settings()
2504
{
2505
	global $incontext, $txt;
2506
2507
	echo '
2508
	<form action="', $incontext['form_url'], '" method="post">
2509
		<h3>', $txt['install_settings_info'], '</h3>';
2510
2511
	template_warning_divs();
2512
2513
	echo '
2514
		<table style="width: 100%; margin: 1em 0;">
2515
			<tr>
2516
				<td class="textbox" style="width: 20%; vertical-align: top;">
2517
					<label for="mbname_input">', $txt['install_settings_name'], ':</label>
2518
				</td>
2519
				<td>
2520
					<input type="text" name="mbname" id="mbname_input" value="', $txt['install_settings_name_default'], '" size="65" class="input_text" />
2521
					<div class="smalltext block">', $txt['install_settings_name_info'], '</div>
2522
				</td>
2523
			</tr>
2524
			<tr>
2525
				<td class="textbox" style="vertical-align: top;">
2526
					<label for="boardurl_input">', $txt['install_settings_url'], ':</label>
2527
				</td>
2528
				<td>
2529
					<input type="text" name="boardurl" id="boardurl_input" value="', $incontext['detected_url'], '" size="65" class="input_text" />
2530
					<br />
2531
					<div class="smalltext block">', $txt['install_settings_url_info'], '</div>
2532
				</td>
2533
			</tr>
2534
			<tr>
2535
				<td class="textbox" style="vertical-align: top;">
2536
					<label for="reg_mode">', $txt['install_settings_reg_mode'], ':</label>
2537
				</td>
2538
				<td>
2539
					<select name="reg_mode" id="reg_mode">
2540
						<optgroup label="', $txt['install_settings_reg_modes'], ':">
2541
							<option value="0" selected>', $txt['install_settings_reg_immediate'], '</option>
2542
							<option value="1">', $txt['install_settings_reg_email'], '</option>
2543
							<option value="2">', $txt['install_settings_reg_admin'], '</option>
2544
							<option value="3">', $txt['install_settings_reg_disabled'], '</option>
2545
						</optgroup>
2546
					</select>
2547
					<br />
2548
					<div class="smalltext block">', $txt['install_settings_reg_mode_info'], '</div>
2549
				</td>
2550
			</tr>
2551
			<tr>
2552
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_compress'], ':</td>
2553
				<td>
2554
					<input type="checkbox" name="compress" id="compress_check" checked class="input_check" />&nbsp;
2555
					<label for="compress_check">', $txt['install_settings_compress_title'], '</label>
2556
					<br />
2557
					<div class="smalltext block">', $txt['install_settings_compress_info'], '</div>
2558
				</td>
2559
			</tr>
2560
			<tr>
2561
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_dbsession'], ':</td>
2562
				<td>
2563
					<input type="checkbox" name="dbsession" id="dbsession_check" checked class="input_check" />&nbsp;
2564
					<label for="dbsession_check">', $txt['install_settings_dbsession_title'], '</label>
2565
					<br />
2566
					<div class="smalltext block">', $incontext['test_dbsession'] ? $txt['install_settings_dbsession_info1'] : $txt['install_settings_dbsession_info2'], '</div>
2567
				</td>
2568
			</tr>
2569
			<tr>
2570
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_utf8'], ':</td>
2571
				<td>
2572
					<input type="checkbox" name="utf8" id="utf8_check"', $incontext['utf8_default'] ? ' checked' : '', ' class="input_check"', $incontext['utf8_required'] ? ' disabled' : '', ' />&nbsp;
2573
					<label for="utf8_check">', $txt['install_settings_utf8_title'], '</label>
2574
					<br />
2575
					<div class="smalltext block">', $txt['install_settings_utf8_info'], '</div>
2576
				</td>
2577
			</tr>
2578
			<tr>
2579
				<td class="textbox" style="vertical-align: top;">', $txt['install_settings_stats'], ':</td>
2580
				<td>
2581
					<input type="checkbox" name="stats" id="stats_check" class="input_check" />&nbsp;
2582
					<label for="stats_check">', $txt['install_settings_stats_title'], '</label>
2583
					<br />
2584
					<div class="smalltext block">', $txt['install_settings_stats_info'], '</div>
2585
				</td>
2586
			</tr>
2587
			<tr>
2588
				<td class="textbox" style="vertical-align: top;">', $txt['force_ssl'], ':</td>
2589
				<td>
2590
					<input type="checkbox" name="force_ssl" id="force_ssl" class="input_check" />&nbsp;
2591
					<label for="force_ssl">', $txt['force_ssl_label'], '</label>
2592
					<br />
2593
					<div class="smalltext block">', $txt['force_ssl_info'], '</div>
2594
				</td>
2595
			</tr>
2596
		</table>
2597
	';
2598
}
2599
2600
// Show results of the database population.
2601
function template_populate_database()
2602
{
2603
	global $incontext, $txt;
2604
2605
	echo '
2606
	<form action="', $incontext['form_url'], '" method="post">
2607
		<p>', !empty($incontext['was_refresh']) ? $txt['user_refresh_install_desc'] : $txt['db_populate_info'], '</p>';
2608
2609
	if (!empty($incontext['sql_results']))
2610
	{
2611
		echo '
2612
		<ul>
2613
			<li>', implode('</li><li>', $incontext['sql_results']), '</li>
2614
		</ul>';
2615
	}
2616
2617
	if (!empty($incontext['failures']))
2618
	{
2619
		echo '
2620
				<div style="color: red;">', $txt['error_db_queries'], '</div>
2621
				<ul>';
2622
2623
		foreach ($incontext['failures'] as $line => $fail)
2624
			echo '
2625
						<li><strong>', $txt['error_db_queries_line'], $line + 1, ':</strong> ', nl2br(htmlspecialchars($fail)), '</li>';
2626
2627
		echo '
2628
				</ul>';
2629
	}
2630
2631
	echo '
2632
		<p>', $txt['db_populate_info2'], '</p>';
2633
2634
	template_warning_divs();
2635
2636
	echo '
2637
	<input type="hidden" name="pop_done" value="1" />';
2638
}
2639
2640
// Create the admin account.
2641
function template_admin_account()
2642
{
2643
	global $incontext, $txt;
2644
2645
	echo '
2646
	<form action="', $incontext['form_url'], '" method="post">
2647
		<p>', $txt['user_settings_info'], '</p>';
2648
2649
	template_warning_divs();
2650
2651
	echo '
2652
		<table width="100%" border="0" style="margin: 2em 0;">
2653
			<tr>
2654
				<td width="18%" valign="top" class="textbox"><label for="username">', $txt['user_settings_username'], ':</label></td>
2655
				<td>
2656
					<input type="text" name="username" id="username" value="', $incontext['username'], '" size="40" class="input_text" />
2657
					<div class="smalltext block">', $txt['user_settings_username_info'], '</div>
2658
				</td>
2659
			</tr><tr>
2660
				<td valign="top" class="textbox"><label for="password1">', $txt['user_settings_password'], ':</label></td>
2661
				<td>
2662
					<input type="password" name="password1" id="password1" size="40" class="input_password" />
2663
					<div class="smalltext block">', $txt['user_settings_password_info'], '</div>
2664
				</td>
2665
			</tr><tr>
2666
				<td valign="top" class="textbox"><label for="password2">', $txt['user_settings_again'], ':</label></td>
2667
				<td>
2668
					<input type="password" name="password2" id="password2" size="40" class="input_password" />
2669
					<div class="smalltext block">', $txt['user_settings_again_info'], '</div>
2670
				</td>
2671
			</tr><tr>
2672
				<td valign="top" class="textbox"><label for="email">', $txt['user_settings_admin_email'], ':</label></td>
2673
				<td>
2674
					<input type="text" name="email" id="email" value="', $incontext['email'], '" size="40" class="input_text" />
2675
					<div class="smalltext block">', $txt['user_settings_admin_email_info'], '</div>
2676
				</td>
2677
			</tr><tr>
2678
				<td valign="top" class="textbox"><label for="server_email">', $txt['user_settings_server_email'], ':</label></td>
2679
				<td>
2680
					<input type="text" name="server_email" id="server_email" value="', $incontext['server_email'], '" size="40" class="input_text" />
2681
					<div class="smalltext block">', $txt['user_settings_server_email_info'], '</div>
2682
				</td>
2683
			</tr>
2684
		</table>';
2685
2686
	if ($incontext['require_db_confirm'])
2687
		echo '
2688
		<h2>', $txt['user_settings_database'], '</h2>
2689
		<p>', $txt['user_settings_database_info'], '</p>
2690
2691
		<div style="margin-bottom: 2ex; padding-', $txt['lang_rtl'] == false ? 'left' : 'right', ': 50px;">
2692
			<input type="password" name="password3" size="30" class="input_password" />
2693
		</div>';
2694
}
2695
2696
// Tell them it's done, and to delete.
2697
function template_delete_install()
2698
{
2699
	global $incontext, $installurl, $txt, $boardurl;
2700
2701
	echo '
2702
		<p>', $txt['congratulations_help'], '</p>';
2703
2704
	template_warning_divs();
2705
2706
	// Install directory still writable?
2707
	if ($incontext['dir_still_writable'])
2708
		echo '
2709
		<em>', $txt['still_writable'], '</em><br />
2710
		<br />';
2711
2712
	// Don't show the box if it's like 99% sure it won't work :P.
2713
	if ($incontext['probably_delete_install'])
2714
		echo '
2715
		<div style="margin: 1ex; font-weight: bold;">
2716
			<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>
2717
		</div>
2718
		<script>
2719
			function doTheDelete()
2720
			{
2721
				var theCheck = document.getElementById ? document.getElementById("delete_self") : document.all.delete_self;
2722
				var tempImage = new Image();
2723
2724
				tempImage.src = "', $installurl, '?delete=1&ts_" + (new Date().getTime());
2725
				tempImage.width = 0;
2726
				theCheck.disabled = true;
2727
			}
2728
		</script>
2729
		<br />';
2730
2731
	echo '
2732
		', sprintf($txt['go_to_your_forum'], $boardurl . '/index.php'), '<br />
2733
		<br />
2734
		', $txt['good_luck'];
2735
}
2736
2737
?>
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...
2738