Completed
Push — release-2.1 ( 4c82a0...64d581 )
by Rick
09:29
created

upgrade.php ➔ upgradeExit()   F

Complexity

Conditions 26
Paths 5508

Size

Total Lines 103
Code Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 26
eloc 58
nc 5508
nop 1
dl 0
loc 103
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Simple Machines Forum (SMF)
5
 *
6
 * @package SMF
7
 * @author Simple Machines http://www.simplemachines.org
8
 * @copyright 2016 Simple Machines and individual contributors
9
 * @license http://www.simplemachines.org/about/smf/license.php BSD
10
 *
11
 * @version 2.1 Beta 3
12
 */
13
14
// Version information...
15
define('SMF_VERSION', '2.1 Beta 3');
16
define('SMF_LANG_VERSION', '2.1 Beta 3');
17
18
$GLOBALS['required_php_version'] = '5.3.8';
19
$GLOBALS['required_mysql_version'] = '5.0.3';
20
21
$databases = array(
22
	'mysqli' => array(
23
		'name' => 'MySQLi',
24
		'version' => '5.0.3',
25
		'version_check' => 'global $db_connection; return min(mysqli_get_server_info($db_connection), mysqli_get_client_info());',
26
		'utf8_support' => true,
27
		'utf8_version' => '5.0.3',
28
		'utf8_version_check' => 'global $db_connection; return mysqli_get_server_info($db_connection);',
29
		'alter_support' => true,
30
	),
31
	'mysql' => array(
32
		'name' => 'MySQL',
33
		'version' => '5.0.3',
34
		'version_check' => 'return min(mysql_get_server_info(), mysql_get_client_info());',
35
		'utf8_support' => true,
36
		'utf8_version' => '5.0.3',
37
		'utf8_version_check' => 'return mysql_get_server_info();',
38
		'alter_support' => true,
39
	),
40
	'postgresql' => array(
41
		'name' => 'PostgreSQL',
42
		'version' => '8.0',
43
		'version_check' => '$version = pg_version(); return $version[\'client\'];',
44
		'always_has_db' => true,
45
	),
46
);
47
48
// General options for the script.
49
$timeLimitThreshold = 3;
50
$upgrade_path = dirname(__FILE__);
51
$upgradeurl = $_SERVER['PHP_SELF'];
52
// Where the SMF images etc are kept.
53
$smfsite = 'http://www.simplemachines.org/smf';
54
// Disable the need for admins to login?
55
$disable_security = false;
56
// How long, in seconds, must admin be inactive to allow someone else to run?
57
$upcontext['inactive_timeout'] = 10;
58
59
// All the steps in detail.
60
// Number,Name,Function,Progress Weight.
61
$upcontext['steps'] = array(
62
	0 => array(1, 'Login', 'WelcomeLogin', 2),
63
	1 => array(2, 'Upgrade Options', 'UpgradeOptions', 2),
64
	2 => array(3, 'Backup', 'BackupDatabase', 10),
65
	3 => array(4, 'Database Changes', 'DatabaseChanges', 50),
66
	4 => array(5, 'Convert to UTF-8', 'ConvertUtf8', 20),
67
	5 => array(6, 'Convert serialized strings to JSON', 'serialize_to_json', 10),
68
	// This is removed as it doesn't really work right at the moment.
69
	//4 => array(5, 'Cleanup Mods', 'CleanupMods', 10),
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
70
	6 => array(7, 'Delete Upgrade.php', 'DeleteUpgrade', 1),
71
);
72
// Just to remember which one has files in it.
73
$upcontext['database_step'] = 3;
74
@set_time_limit(600);
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...
75
if (!ini_get('safe_mode'))
76
{
77
	ini_set('mysql.connect_timeout', -1);
78
	ini_set('default_socket_timeout', 900);
79
}
80
// Clean the upgrade path if this is from the client.
81
if (!empty($_SERVER['argv']) && php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']))
82
	for ($i = 1; $i < $_SERVER['argc']; $i++)
83
	{
84
		if (preg_match('~^--path=(.+)$~', $_SERVER['argv'][$i], $match) != 0)
85
			$upgrade_path = substr($match[1], -1) == '/' ? substr($match[1], 0, -1) : $match[1];
86
	}
87
88
// Are we from the client?
89
if (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']))
90
{
91
	$command_line = true;
92
	$disable_security = 1;
93
}
94
else
95
	$command_line = false;
96
97
// Load this now just because we can.
98
require_once($upgrade_path . '/Settings.php');
99
100
// Are we logged in?
101
if (isset($upgradeData))
102
{
103
	$upcontext['user'] = unserialize(base64_decode($upgradeData));
104
105
	// Check for sensible values.
106 View Code Duplication
	if (empty($upcontext['user']['started']) || $upcontext['user']['started'] < time() - 86400)
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...
107
		$upcontext['user']['started'] = time();
108 View Code Duplication
	if (empty($upcontext['user']['updated']) || $upcontext['user']['updated'] < time() - 86400)
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...
109
		$upcontext['user']['updated'] = 0;
110
111
	$upcontext['started'] = $upcontext['user']['started'];
112
	$upcontext['updated'] = $upcontext['user']['updated'];
113
114
	$is_debug = !empty($upcontext['user']['debug']) ? true : false;
115
}
116
117
// Nothing sensible?
118
if (empty($upcontext['updated']))
119
{
120
	$upcontext['started'] = time();
121
	$upcontext['updated'] = 0;
122
	$upcontext['user'] = array(
123
		'id' => 0,
124
		'name' => 'Guest',
125
		'pass' => 0,
126
		'started' => $upcontext['started'],
127
		'updated' => $upcontext['updated'],
128
	);
129
}
130
131
// Load up some essential data...
132
loadEssentialData();
133
134
// Are we going to be mimic'ing SSI at this point?
135
if (isset($_GET['ssi']))
136
{
137
	require_once($sourcedir . '/Errors.php');
138
	require_once($sourcedir . '/Logging.php');
139
	require_once($sourcedir . '/Load.php');
140
	require_once($sourcedir . '/Security.php');
141
	require_once($sourcedir . '/Subs-Package.php');
142
143
	loadUserSettings();
144
	loadPermissions();
145
}
146
147
if (!function_exists('un_htmlspecialchars'))
148
{
149
	function un_htmlspecialchars($string)
150
	{
151
		return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES)) + array('&#039;' => '\'', '&nbsp;' => ' '));
152
	}
153
}
154
155
if (!function_exists('text2words'))
156
{
157
	function text2words($text)
158
	{
159
		// Step 1: Remove entities/things we don't consider words:
160
		$words = preg_replace('~(?:[\x0B\0\xA0\t\r\s\n(){}\\[\\]<>!@$%^*.,:+=`\~\?/\\\\]+|&(?:amp|lt|gt|quot);)+~', ' ', $text);
161
162
		// Step 2: Entities we left to letters, where applicable, lowercase.
163
		$words = preg_replace('~([^&\d]|^)[#;]~', '$1 ', un_htmlspecialchars(strtolower($words)));
164
165
		// Step 3: Ready to split apart and index!
166
		$words = explode(' ', $words);
167
		$returned_words = array();
168
		foreach ($words as $word)
169
		{
170
			$word = trim($word, '-_\'');
171
172
			if ($word != '')
173
				$returned_words[] = substr($word, 0, 20);
174
		}
175
176
		return array_unique($returned_words);
177
	}
178
}
179
180
if (!function_exists('clean_cache'))
181
{
182
	// Empty out the cache folder.
183
	function clean_cache($type = '')
184
	{
185
		global $cachedir, $sourcedir;
186
187
		// No directory = no game.
188
		if (!is_dir($cachedir))
189
			return;
190
191
		// Remove the files in SMF's own disk cache, if any
192
		$dh = opendir($cachedir);
193 View Code Duplication
		while ($file = readdir($dh))
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...
194
		{
195
			if ($file != '.' && $file != '..' && $file != 'index.php' && $file != '.htaccess' && (!$type || substr($file, 0, strlen($type)) == $type))
196
				@unlink($cachedir . '/' . $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...
197
		}
198
		closedir($dh);
199
200
		// Invalidate cache, to be sure!
201
		// ... as long as index.php can be modified, anyway.
202
		@touch($cachedir . '/' . 'index.php');
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
		clearstatcache();
204
	}
205
}
206
207
// MD5 Encryption.
208
if (!function_exists('md5_hmac'))
209
{
210
	function md5_hmac($data, $key)
211
	{
212
		if (strlen($key) > 64)
213
			$key = pack('H*', md5($key));
214
		$key = str_pad($key, 64, chr(0x00));
215
216
		$k_ipad = $key ^ str_repeat(chr(0x36), 64);
217
		$k_opad = $key ^ str_repeat(chr(0x5c), 64);
218
219
		return md5($k_opad . pack('H*', md5($k_ipad . $data)));
220
	}
221
}
222
223
// Don't do security check if on Yabbse
224
if (!isset($modSettings['smfVersion']))
225
	$disable_security = true;
226
227
// This only exists if we're on SMF ;)
228
if (isset($modSettings['smfVersion']))
229
{
230
	$request = $smcFunc['db_query']('', '
231
		SELECT variable, value
232
		FROM {db_prefix}themes
233
		WHERE id_theme = {int:id_theme}
234
			AND variable IN ({string:theme_url}, {string:theme_dir}, {string:images_url})',
235
		array(
236
			'id_theme' => 1,
237
			'theme_url' => 'theme_url',
238
			'theme_dir' => 'theme_dir',
239
			'images_url' => 'images_url',
240
			'db_error_skip' => true,
241
		)
242
	);
243 View Code Duplication
	while ($row = $smcFunc['db_fetch_assoc']($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...
244
		$modSettings[$row['variable']] = $row['value'];
245
	$smcFunc['db_free_result']($request);
246
}
247
248
if (!isset($modSettings['theme_url']))
249
{
250
	$modSettings['theme_dir'] = $boarddir . '/Themes/default';
251
	$modSettings['theme_url'] = 'Themes/default';
252
	$modSettings['images_url'] = 'Themes/default/images';
253
}
254
if (!isset($settings['default_theme_url']))
255
	$settings['default_theme_url'] = $modSettings['theme_url'];
256
if (!isset($settings['default_theme_dir']))
257
	$settings['default_theme_dir'] = $modSettings['theme_dir'];
258
259
$upcontext['is_large_forum'] = (empty($modSettings['smfVersion']) || $modSettings['smfVersion'] <= '1.1 RC1') && !empty($modSettings['totalMessages']) && $modSettings['totalMessages'] > 75000;
260
// Default title...
261
$upcontext['page_title'] = isset($modSettings['smfVersion']) ? 'Updating Your SMF Install!' : 'Upgrading from YaBB SE!';
262
263
// Have we got tracking data - if so use it (It will be clean!)
264
if (isset($_GET['data']))
265
{
266
	global $is_debug;
267
268
	$upcontext['upgrade_status'] = safe_unserialize(base64_decode($_GET['data']));
269
	$upcontext['current_step'] = $upcontext['upgrade_status']['curstep'];
270
	$upcontext['language'] = $upcontext['upgrade_status']['lang'];
271
	$upcontext['rid'] = $upcontext['upgrade_status']['rid'];
272
	$support_js = $upcontext['upgrade_status']['js'];
273
274
	// Only set this if the upgrader status says so.
275
	if (empty($is_debug))
276
		$is_debug = $upcontext['upgrade_status']['debug'];
277
278
	// Load the language.
279 View Code Duplication
	if (file_exists($modSettings['theme_dir'] . '/languages/Install.' . $upcontext['language'] . '.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...
280
		require_once($modSettings['theme_dir'] . '/languages/Install.' . $upcontext['language'] . '.php');
281
}
282
// Set the defaults.
283
else
284
{
285
	$upcontext['current_step'] = 0;
286
	$upcontext['rid'] = mt_rand(0, 5000);
287
	$upcontext['upgrade_status'] = array(
288
		'curstep' => 0,
289
		'lang' => isset($_GET['lang']) ? $_GET['lang'] : basename($language, '.lng'),
290
		'rid' => $upcontext['rid'],
291
		'pass' => 0,
292
		'debug' => 0,
293
		'js' => 0,
294
	);
295
	$upcontext['language'] = $upcontext['upgrade_status']['lang'];
296
}
297
298
// If this isn't the first stage see whether they are logging in and resuming.
299
if ($upcontext['current_step'] != 0 || !empty($upcontext['user']['step']))
300
	checkLogin();
301
302
if ($command_line)
303
	cmdStep0();
304
305
// Don't error if we're using xml.
306
if (isset($_GET['xml']))
307
	$upcontext['return_error'] = true;
308
309
// Loop through all the steps doing each one as required.
310
$upcontext['overall_percent'] = 0;
311
foreach ($upcontext['steps'] as $num => $step)
312
{
313
	if ($num >= $upcontext['current_step'])
314
	{
315
		// The current weight of this step in terms of overall progress.
316
		$upcontext['step_weight'] = $step[3];
317
		// Make sure we reset the skip button.
318
		$upcontext['skip'] = false;
319
320
		// We cannot proceed if we're not logged in.
321
		if ($num != 0 && !$disable_security && $upcontext['user']['pass'] != $upcontext['upgrade_status']['pass'])
322
		{
323
			$upcontext['steps'][0][2]();
324
			break;
325
		}
326
327
		// Call the step and if it returns false that means pause!
328 View Code Duplication
		if (function_exists($step[2]) && $step[2]() === false)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
329
			break;
330
		elseif (function_exists($step[2]))
331
			$upcontext['current_step']++;
332
	}
333
	$upcontext['overall_percent'] += $step[3];
334
}
335
336
upgradeExit();
337
338
// Exit the upgrade script.
339
function upgradeExit($fallThrough = false)
340
{
341
	global $upcontext, $upgradeurl, $boarddir, $command_line, $is_debug;
342
343
	// Save where we are...
344
	if (!empty($upcontext['current_step']) && !empty($upcontext['user']['id']))
345
	{
346
		$upcontext['user']['step'] = $upcontext['current_step'];
347
		$upcontext['user']['substep'] = $_GET['substep'];
348
		$upcontext['user']['updated'] = time();
349
		$upcontext['debug'] = $is_debug;
350
		$upgradeData = base64_encode(safe_serialize($upcontext['user']));
351
		copy($boarddir . '/Settings.php', $boarddir . '/Settings_bak.php');
352
		changeSettings(array('upgradeData' => '"' . $upgradeData . '"'));
353
		updateLastError();
354
	}
355
356
	// Handle the progress of the step, if any.
357
	if (!empty($upcontext['step_progress']) && isset($upcontext['steps'][$upcontext['current_step']]))
358
	{
359
		$upcontext['step_progress'] = round($upcontext['step_progress'], 1);
360
		$upcontext['overall_percent'] += $upcontext['step_progress'] * ($upcontext['steps'][$upcontext['current_step']][3] / 100);
361
	}
362
	$upcontext['overall_percent'] = (int) $upcontext['overall_percent'];
363
364
	// We usually dump our templates out.
365
	if (!$fallThrough)
366
	{
367
		// This should not happen my dear... HELP ME DEVELOPERS!!
368
		if (!empty($command_line))
369
		{
370
			if (function_exists('debug_print_backtrace'))
371
				debug_print_backtrace();
372
373
			echo "\n" . 'Error: Unexpected call to use the ' . (isset($upcontext['sub_template']) ? $upcontext['sub_template'] : '') . ' template. Please copy and paste all the text above and visit the SMF support forum to tell the Developers that they\'ve made a boo boo; they\'ll get you up and running again.';
374
			flush();
375
			die();
376
		}
377
378
		if (!isset($_GET['xml']))
379
			template_upgrade_above();
380
		else
381
		{
382
			header('Content-Type: text/xml; charset=UTF-8');
383
			// Sadly we need to retain the $_GET data thanks to the old upgrade scripts.
384
			$upcontext['get_data'] = array();
385
			foreach ($_GET as $k => $v)
386
			{
387
				if (substr($k, 0, 3) != 'amp' && !in_array($k, array('xml', 'substep', 'lang', 'data', 'step', 'filecount')))
388
				{
389
					$upcontext['get_data'][$k] = $v;
390
				}
391
			}
392
			template_xml_above();
393
		}
394
395
		// Call the template.
396
		if (isset($upcontext['sub_template']))
397
		{
398
			$upcontext['upgrade_status']['curstep'] = $upcontext['current_step'];
399
			$upcontext['form_url'] = $upgradeurl . '?step=' . $upcontext['current_step'] . '&amp;substep=' . $_GET['substep'] . '&amp;data=' . base64_encode(safe_serialize($upcontext['upgrade_status']));
400
401
			// Custom stuff to pass back?
402
			if (!empty($upcontext['query_string']))
403
				$upcontext['form_url'] .= $upcontext['query_string'];
404
405
			call_user_func('template_' . $upcontext['sub_template']);
406
		}
407
408
		// Was there an error?
409
		if (!empty($upcontext['forced_error_message']))
410
			echo $upcontext['forced_error_message'];
411
412
		// Show the footer.
413
		if (!isset($_GET['xml']))
414
			template_upgrade_below();
415
		else
416
			template_xml_below();
417
	}
418
419
420
	if (!empty($command_line) && $is_debug)
421
	{
422
		$active = time() - $upcontext['started'];
423
		$hours = floor($active / 3600);
424
		$minutes = intval(($active / 60) % 60);
425
		$seconds = intval($active % 60);
426
427
		$totalTime = '';
428
		if ($hours > 0)
429
			$totalTime .= $hours . ' hour' . ($hours > 1 ? 's':'') . ' ';
430
		if ($minutes > 0)
431
			$totalTime .= $minutes . ' minute' . ($minutes > 1 ? 's':'') . ' ';
432
		if ($seconds > 0)
433
			$totalTime .= $seconds . ' second' . ($seconds > 1 ? 's':'') . ' ';
434
435
		if (!empty($totalTime))
436
			echo "\n" . 'Upgrade completed in ' . $totalTime . "\n";
437
	}
438
439
	// Bang - gone!
440
	die();
441
}
442
443
// Used to direct the user to another location.
444
function redirectLocation($location, $addForm = true)
445
{
446
	global $upgradeurl, $upcontext, $command_line;
447
448
	// Command line users can't be redirected.
449
	if ($command_line)
450
		upgradeExit(true);
451
452
	// Are we providing the core info?
453
	if ($addForm)
454
	{
455
		$upcontext['upgrade_status']['curstep'] = $upcontext['current_step'];
456
		$location = $upgradeurl . '?step=' . $upcontext['current_step'] . '&substep=' . $_GET['substep'] . '&data=' . base64_encode(safe_serialize($upcontext['upgrade_status'])) . $location;
457
	}
458
459
	while (@ob_end_clean());
460
	header('Location: ' . strtr($location, array('&amp;' => '&')));
461
462
	// Exit - saving status as we go.
463
	upgradeExit(true);
464
}
465
466
// Load all essential data and connect to the DB as this is pre SSI.php
467
function loadEssentialData()
468
{
469
	global $db_server, $db_user, $db_passwd, $db_name, $db_connection, $db_prefix, $db_character_set, $db_type;
470
	global $modSettings, $sourcedir, $smcFunc;
471
472
	// Do the non-SSI stuff...
473
	if (function_exists('set_magic_quotes_runtime'))
474
		@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...
475
476
	error_reporting(E_ALL);
477
	define('SMF', 1);
478
479
	// Start the session.
480
	if (@ini_get('session.save_handler') == 'user')
481
		@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...
482
	@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...
483
484
	if (empty($smcFunc))
485
		$smcFunc = array();
486
487
	// We need this for authentication and some upgrade code
488
	require_once($sourcedir . '/Subs-Auth.php');
489
	require_once($sourcedir . '/Class-Package.php');
490
491
	$smcFunc['strtolower'] = 'smf_strtolower';
492
493
494
	// Initialize everything...
495
	initialize_inputs();
496
497
	// Get the database going!
498
	if (empty($db_type))
499
		$db_type = 'mysql';
500
	if (file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php'))
501
	{
502
		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
503
504
		// Make the connection...
505
		$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('non_fatal' => true));
506
507
		// Oh dear god!!
508
		if ($db_connection === null)
509
			die('Unable to connect to database - please check username and password are correct in Settings.php');
510
511
		if (($db_type == 'mysql' || $db_type == 'mysqli') && isset($db_character_set) && preg_match('~^\w+$~', $db_character_set) === 1)
512
			$smcFunc['db_query']('', '
513
			SET NAMES ' . $db_character_set,
514
			array(
515
				'db_error_skip' => true,
516
			)
517
		);
518
519
		// Load the modSettings data...
520
		$request = $smcFunc['db_query']('', '
521
			SELECT variable, value
522
			FROM {db_prefix}settings',
523
			array(
524
				'db_error_skip' => true,
525
			)
526
		);
527
		$modSettings = array();
528 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($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...
529
			$modSettings[$row['variable']] = $row['value'];
530
		$smcFunc['db_free_result']($request);
531
	}
532
	else
533
	{
534
		return throw_error('Cannot find ' . $sourcedir . '/Subs-Db-' . $db_type . '.php' . '. Please check you have uploaded all source files and have the correct paths set.');
535
	}
536
537
	require_once($sourcedir . '/Subs.php');
538
539
	// If they don't have the file, they're going to get a warning anyway so we won't need to clean request vars.
540
	if (file_exists($sourcedir . '/QueryString.php') && php_version_check())
541
	{
542
		require_once($sourcedir . '/QueryString.php');
543
		cleanRequest();
544
	}
545
546
	if (!isset($_GET['substep']))
547
		$_GET['substep'] = 0;
548
}
549
550
function initialize_inputs()
0 ignored issues
show
Best Practice introduced by
The function initialize_inputs() has been defined more than once; this definition is ignored, only the first definition in other/install.php (L152-263) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
551
{
552
	global $start_time, $upcontext, $db_type;
553
554
	$start_time = time();
555
556
	umask(0);
557
558
	// Fun.  Low PHP version...
559
	if (!isset($_GET))
560
	{
561
		$GLOBALS['_GET']['step'] = 0;
562
		return;
563
	}
564
565
	ob_start();
566
567
	// Better to upgrade cleanly and fall apart than to screw everything up if things take too long.
568
	ignore_user_abort(true);
569
570
	// This is really quite simple; if ?delete is on the URL, delete the upgrader...
571
	if (isset($_GET['delete']))
572
	{
573
		@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...
574
575
		$type = ($db_type == 'mysqli' ? 'mysql' : $db_type);
576
577
		// And the extra little files ;).
578
		@unlink(dirname(__FILE__) . '/upgrade_1-0.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...
579
		@unlink(dirname(__FILE__) . '/upgrade_1-1.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...
580
		@unlink(dirname(__FILE__) . '/upgrade_2-0_' . $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...
581
		@unlink(dirname(__FILE__) . '/upgrade_2-1_' . $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...
582
583
		$dh = opendir(dirname(__FILE__));
584
		while ($file = readdir($dh))
585
		{
586
			if (preg_match('~upgrade_\d-\d_([A-Za-z])+\.sql~i', $file, $matches) && isset($matches[1]))
587
				@unlink(dirname(__FILE__) . '/' . $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...
588
		}
589
		closedir($dh);
590
591
		// Legacy files while we're at it. NOTE: We only touch files we KNOW shouldn't be there.
592
		// 1.1 Sources files not in 2.0+
593
		@unlink(dirname(__FILE__) . '/Sources/ModSettings.php');
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...
594
		// 1.1 Templates that don't exist any more (e.g. renamed)
595
		@unlink(dirname(__FILE__) . '/Themes/default/Combat.template.php');
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...
596
		@unlink(dirname(__FILE__) . '/Themes/default/Modlog.template.php');
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...
597
		// 1.1 JS files were stored in the main theme folder, but in 2.0+ are in the scripts/ folder
598
		@unlink(dirname(__FILE__) . '/Themes/default/fader.js');
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...
599
		@unlink(dirname(__FILE__) . '/Themes/default/script.js');
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...
600
		@unlink(dirname(__FILE__) . '/Themes/default/spellcheck.js');
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...
601
		@unlink(dirname(__FILE__) . '/Themes/default/xml_board.js');
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...
602
		@unlink(dirname(__FILE__) . '/Themes/default/xml_topic.js');
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...
603
604
		// 2.0 Sources files not in 2.1+
605
		@unlink(dirname(__FILE__) . '/Sources/DumpDatabase.php');
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...
606
		@unlink(dirname(__FILE__) . '/Sources/LockTopic.php');
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...
607
608
		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');
609
		exit;
610
	}
611
612
	// Anybody home?
613 View Code Duplication
	if (!isset($_GET['xml']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
614
	{
615
		$upcontext['remote_files_available'] = false;
616
		$test = @fsockopen('www.simplemachines.org', 80, $errno, $errstr, 1);
617
		if ($test)
618
			$upcontext['remote_files_available'] = true;
619
		@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...
620
	}
621
622
	// Something is causing this to happen, and it's annoying.  Stop it.
623
	$temp = 'upgrade_php?step';
624
	while (strlen($temp) > 4)
625
	{
626
		if (isset($_GET[$temp]))
627
			unset($_GET[$temp]);
628
		$temp = substr($temp, 1);
629
	}
630
631
	// Force a step, defaulting to 0.
632
	$_GET['step'] = (int) @$_GET['step'];
633
	$_GET['substep'] = (int) @$_GET['substep'];
634
}
635
636
// Step 0 - Let's welcome them in and ask them to login!
637
function WelcomeLogin()
638
{
639
	global $boarddir, $sourcedir, $modSettings, $cachedir, $upgradeurl, $upcontext;
640
	global $smcFunc, $db_type, $databases, $txt, $boardurl;
641
642
	$upcontext['sub_template'] = 'welcome_message';
643
644
	$type = ($db_type == 'mysqli' ? 'mysql' : $db_type);
645
646
	// Check for some key files - one template, one language, and a new and an old source file.
647
	$check = @file_exists($modSettings['theme_dir'] . '/index.template.php')
648
		&& @file_exists($sourcedir . '/QueryString.php')
649
		&& @file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php')
650
		&& @file_exists(dirname(__FILE__) . '/upgrade_2-1_' . $type . '.sql');
651
652
	// Need legacy scripts?
653 View Code Duplication
	if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < 2.1)
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...
654
		$check &= @file_exists(dirname(__FILE__) . '/upgrade_2-0_' . $type . '.sql');
655 View Code Duplication
	if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < 2.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...
656
		$check &= @file_exists(dirname(__FILE__) . '/upgrade_1-1.sql');
657 View Code Duplication
	if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < 1.1)
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...
658
		$check &= @file_exists(dirname(__FILE__) . '/upgrade_1-0.sql');
659
660
	// This needs to exist!
661
	if (!file_exists($modSettings['theme_dir'] . '/languages/Install.' . $upcontext['language'] . '.php'))
662
		return throw_error('The upgrader could not find the &quot;Install&quot; language file for the forum default language, ' . $upcontext['language'] . '.<br><br>Please make certain you uploaded all the files included in the package, even the theme and language files for the default theme.<br>&nbsp;&nbsp;&nbsp;[<a href="' . $upgradeurl . '?lang=english">Try English</a>]');
663
	else
664
		require_once($modSettings['theme_dir'] . '/languages/Install.' . $upcontext['language'] . '.php');
665
666
	if (!$check)
667
		// Don't tell them what files exactly because it's a spot check - just like teachers don't tell which problems they are spot checking, that's dumb.
668
		return throw_error('The upgrader was unable to find some crucial files.<br><br>Please make sure you uploaded all of the files included in the package, including the Themes, Sources, and other directories.');
669
670
	// Do they meet the install requirements?
671
	if (!php_version_check())
672
		return throw_error('Warning!  You do not appear to have a version of PHP installed on your webserver that meets SMF\'s minimum installations requirements.<br><br>Please ask your host to upgrade.');
673
674
	if (!db_version_check())
675
		return throw_error('Your ' . $databases[$db_type]['name'] . ' version does not meet the minimum requirements of SMF.<br><br>Please ask your host to upgrade.');
676
677
	// Do some checks to make sure they have proper privileges
678
	db_extend('packages');
679
680
	// CREATE
681
	$create = $smcFunc['db_create_table']('{db_prefix}priv_check', array(array('name' => 'id_test', 'type' => 'int', 'size' => 10, 'unsigned' => true, 'auto' => true)), array(array('columns' => array('id_test'), 'type' => 'primary')), array(), 'overwrite');
682
683
	// ALTER
684
	$alter = $smcFunc['db_add_column']('{db_prefix}priv_check', array('name' => 'txt', 'type' => 'varchar', 'size' => 4, 'null' => false, 'default' => ''));
685
686
	// DROP
687
	$drop = $smcFunc['db_drop_table']('{db_prefix}priv_check');
688
689
	// Sorry... we need CREATE, ALTER and DROP
690 View Code Duplication
	if (!$create || !$alter || !$drop)
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...
691
		return throw_error('The ' . $databases[$db_type]['name'] . ' user you have set in Settings.php does not have proper privileges.<br><br>Please ask your host to give this user the ALTER, CREATE, and DROP privileges.');
692
693
	// Do a quick version spot check.
694
	$temp = substr(@implode('', @file($boarddir . '/index.php')), 0, 4096);
695
	preg_match('~\*\s@version\s+(.+)[\s]{2}~i', $temp, $match);
696
	if (empty($match[1]) || (trim($match[1]) != SMF_VERSION))
697
		return throw_error('The upgrader found some old or outdated files.<br><br>Please make certain you uploaded the new versions of all the files included in the package.');
698
699
	// What absolutely needs to be writable?
700
	$writable_files = array(
701
		$boarddir . '/Settings.php',
702
		$boarddir . '/Settings_bak.php',
703
		$boarddir . '/db_last_error.php',
704
		$modSettings['theme_dir'] . '/css/minified.css',
705
		$modSettings['theme_dir'] . '/scripts/minified.js',
706
		$modSettings['theme_dir'] . '/scripts/minified_deferred.js',
707
	);
708
709
	// Do we need to add this setting?
710
	$need_settings_update = empty($modSettings['custom_avatar_dir']);
711
712
	$custom_av_dir = !empty($modSettings['custom_avatar_dir']) ? $modSettings['custom_avatar_dir'] : $GLOBALS['boarddir'] .'/custom_avatar';
713
	$custom_av_url = !empty($modSettings['custom_avatar_url']) ? $modSettings['custom_avatar_url'] : $boardurl .'/custom_avatar';
714
715
	// This little fellow has to cooperate...
716
	quickFileWritable($custom_av_dir);
717
718
	// Are we good now?
719
	if(!is_writable($custom_av_dir))
720
		return throw_error(sprintf('The directory: %1$s has to be writable to continue the upgrade. Please make sure permissions are correctly set to allow this.', $custom_av_dir));
721
	elseif ($need_settings_update)
722
	{
723
		if (!function_exists('cache_put_data'))
724
			require_once($sourcedir . '/Load.php');
725
		updateSettings(array('custom_avatar_dir' => $custom_av_dir));
726
		updateSettings(array('custom_avatar_url' => $custom_av_url));
727
	}
728
729
	require_once($sourcedir . '/Security.php');
730
731
	// Check the cache directory.
732
	$cachedir_temp = empty($cachedir) ? $boarddir . '/cache' : $cachedir;
733
	if (!file_exists($cachedir_temp))
734
		@mkdir($cachedir_temp);
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...
735
	if (!file_exists($cachedir_temp))
736
		return throw_error('The cache directory could not be found.<br><br>Please make sure you have a directory called &quot;cache&quot; in your forum directory before continuing.');
737
738
	if (!file_exists($modSettings['theme_dir'] . '/languages/index.' . $upcontext['language'] . '.php') && !isset($modSettings['smfVersion']) && !isset($_GET['lang']))
739
		return throw_error('The upgrader was unable to find language files for the language specified in Settings.php.<br>SMF will not work without the primary language files installed.<br><br>Please either install them, or <a href="' . $upgradeurl . '?step=0;lang=english">use english instead</a>.');
740
	elseif (!isset($_GET['skiplang']))
741
	{
742
		$temp = substr(@implode('', @file($modSettings['theme_dir'] . '/languages/index.' . $upcontext['language'] . '.php')), 0, 4096);
743
		preg_match('~(?://|/\*)\s*Version:\s+(.+?);\s*index(?:[\s]{2}|\*/)~i', $temp, $match);
744
745
		if (empty($match[1]) || $match[1] != SMF_LANG_VERSION)
746
			return throw_error('The upgrader found some old or outdated language files, for the forum default language, ' . $upcontext['language'] . '.<br><br>Please make certain you uploaded the new versions of all the files included in the package, even the theme and language files for the default theme.<br>&nbsp;&nbsp;&nbsp;[<a href="' . $upgradeurl . '?skiplang">SKIP</a>] [<a href="' . $upgradeurl . '?lang=english">Try English</a>]');
747
	}
748
749
	if (!makeFilesWritable($writable_files))
750
		return false;
751
752
	// Check agreement.txt. (it may not exist, in which case $boarddir must be writable.)
753 View Code Duplication
	if (isset($modSettings['agreement']) && (!is_writable($boarddir) || file_exists($boarddir . '/agreement.txt')) && !is_writable($boarddir . '/agreement.txt'))
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...
754
		return throw_error('The upgrader was unable to obtain write access to agreement.txt.<br><br>If you are using a linux or unix based server, please ensure that the file is chmod\'d to 777, or if it does not exist that the directory this upgrader is in is 777.<br>If your server is running Windows, please ensure that the internet guest account has the proper permissions on it or its folder.');
755
756
	// Upgrade the agreement.
757
	elseif (isset($modSettings['agreement']))
758
	{
759
		$fp = fopen($boarddir . '/agreement.txt', 'w');
760
		fwrite($fp, $modSettings['agreement']);
761
		fclose($fp);
762
	}
763
764
	// We're going to check that their board dir setting is right in case they've been moving stuff around.
765
	if (strtr($boarddir, array('/' => '', '\\' => '')) != strtr(dirname(__FILE__), array('/' => '', '\\' => '')))
766
		$upcontext['warning'] = '
767
			It looks as if your board directory settings <em>might</em> be incorrect. Your board directory is currently set to &quot;' . $boarddir . '&quot; but should probably be &quot;' . dirname(__FILE__) . '&quot;. Settings.php currently lists your paths as:<br>
768
			<ul>
769
				<li>Board Directory: ' . $boarddir . '</li>
770
				<li>Source Directory: ' . $boarddir . '</li>
771
				<li>Cache Directory: ' . $cachedir_temp . '</li>
772
			</ul>
773
			If these seem incorrect please open Settings.php in a text editor before proceeding with this upgrade. If they are incorrect due to you moving your forum to a new location please download and execute the <a href="http://download.simplemachines.org/?tools">Repair Settings</a> tool from the Simple Machines website before continuing.';
774
775
	// Either we're logged in or we're going to present the login.
776
	if (checkLogin())
777
		return true;
778
779
	$upcontext += createToken('login');
780
781
	return false;
782
}
783
784
// Step 0.5: Does the login work?
785
function checkLogin()
786
{
787
	global $modSettings, $upcontext, $disable_security;
788
	global $smcFunc, $db_type, $support_js;
789
790
	// Are we trying to login?
791
	if (isset($_POST['contbutt']) && (!empty($_POST['user']) || $disable_security))
792
	{
793
		// If we've disabled security pick a suitable name!
794
		if (empty($_POST['user']))
795
			$_POST['user'] = 'Administrator';
796
797
		// Before 2.0 these column names were different!
798
		$oldDB = false;
799
		if (empty($db_type) || $db_type == 'mysql' || $db_type == 'mysqli')
800
		{
801
			$request = $smcFunc['db_query']('', '
802
				SHOW COLUMNS
803
				FROM {db_prefix}members
804
				LIKE {string:member_name}',
805
				array(
806
					'member_name' => 'memberName',
807
					'db_error_skip' => true,
808
				)
809
			);
810
			if ($smcFunc['db_num_rows']($request) != 0)
811
				$oldDB = true;
812
			$smcFunc['db_free_result']($request);
813
		}
814
815
		// Get what we believe to be their details.
816
		if (!$disable_security)
817
		{
818
			if ($oldDB)
819
				$request = $smcFunc['db_query']('', '
820
					SELECT id_member, memberName AS member_name, passwd, id_group,
821
					additionalGroups AS additional_groups, lngfile
822
					FROM {db_prefix}members
823
					WHERE memberName = {string:member_name}',
824
					array(
825
						'member_name' => $_POST['user'],
826
						'db_error_skip' => true,
827
					)
828
				);
829
			else
830
				$request = $smcFunc['db_query']('', '
831
					SELECT id_member, member_name, passwd, id_group, additional_groups, lngfile
832
					FROM {db_prefix}members
833
					WHERE member_name = {string:member_name}',
834
					array(
835
						'member_name' => $_POST['user'],
836
						'db_error_skip' => true,
837
					)
838
				);
839
			if ($smcFunc['db_num_rows']($request) != 0)
840
			{
841
				list ($id_member, $name, $password, $id_group, $addGroups, $user_language) = $smcFunc['db_fetch_row']($request);
842
843
				$groups = explode(',', $addGroups);
844
				$groups[] = $id_group;
845
846
				foreach ($groups as $k => $v)
847
					$groups[$k] = (int) $v;
848
849
				$sha_passwd = sha1(strtolower($name) . un_htmlspecialchars($_REQUEST['passwrd']));
850
			}
851
			else
852
				$upcontext['username_incorrect'] = true;
853
			$smcFunc['db_free_result']($request);
854
		}
855
		$upcontext['username'] = $_POST['user'];
856
857
		// Track whether javascript works!
858
		if (!empty($_POST['js_works']))
859
		{
860
			$upcontext['upgrade_status']['js'] = 1;
861
			$support_js = 1;
862
		}
863
		else
864
			$support_js = 0;
865
866
		// Note down the version we are coming from.
867
		if (!empty($modSettings['smfVersion']) && empty($upcontext['user']['version']))
868
			$upcontext['user']['version'] = $modSettings['smfVersion'];
869
870
		// Didn't get anywhere?
871
		if (!$disable_security && (empty($sha_passwd) || (!empty($password) ? $password : '') != $sha_passwd) && !hash_verify_password((!empty($name) ? $name : ''), $_REQUEST['passwrd'], (!empty($password) ? $password : '')) && empty($upcontext['username_incorrect']))
0 ignored issues
show
Bug introduced by
The variable $sha_passwd 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...
872
		{
873
			// MD5?
874
			$md5pass = md5_hmac($_REQUEST['passwrd'], strtolower($_POST['user']));
875
			if ($md5pass != $password)
0 ignored issues
show
Bug introduced by
The variable $password 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...
876
			{
877
				$upcontext['password_failed'] = true;
878
				// Disable the hashing this time.
879
				$upcontext['disable_login_hashing'] = true;
880
			}
881
		}
882
883
		if ((empty($upcontext['password_failed']) && !empty($name)) || $disable_security)
884
		{
885
			// Set the password.
886
			if (!$disable_security)
887
			{
888
				// Do we actually have permission?
889
				if (!in_array(1, $groups))
890
				{
891
					$request = $smcFunc['db_query']('', '
892
						SELECT permission
893
						FROM {db_prefix}permissions
894
						WHERE id_group IN ({array_int:groups})
895
							AND permission = {string:admin_forum}',
896
						array(
897
							'groups' => $groups,
0 ignored issues
show
Bug introduced by
The variable $groups 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...
898
							'admin_forum' => 'admin_forum',
899
							'db_error_skip' => true,
900
						)
901
					);
902
					if ($smcFunc['db_num_rows']($request) == 0)
903
						return throw_error('You need to be an admin to perform an upgrade!');
904
					$smcFunc['db_free_result']($request);
905
				}
906
907
				$upcontext['user']['id'] = $id_member;
0 ignored issues
show
Bug introduced by
The variable $id_member 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...
908
				$upcontext['user']['name'] = $name;
909
			}
910
			else
911
			{
912
				$upcontext['user']['id'] = 1;
913
				$upcontext['user']['name'] = 'Administrator';
914
			}
915
			$upcontext['user']['pass'] = mt_rand(0,60000);
916
			// This basically is used to match the GET variables to Settings.php.
917
			$upcontext['upgrade_status']['pass'] = $upcontext['user']['pass'];
918
919
			// Set the language to that of the user?
920
			if (isset($user_language) && $user_language != $upcontext['language'] && file_exists($modSettings['theme_dir'] . '/languages/index.' . basename($user_language, '.lng') . '.php'))
921
			{
922
				$user_language = basename($user_language, '.lng');
923
				$temp = substr(@implode('', @file($modSettings['theme_dir'] . '/languages/index.' . $user_language . '.php')), 0, 4096);
924
				preg_match('~(?://|/\*)\s*Version:\s+(.+?);\s*index(?:[\s]{2}|\*/)~i', $temp, $match);
925
926
				if (empty($match[1]) || $match[1] != SMF_LANG_VERSION)
927
					$upcontext['upgrade_options_warning'] = 'The language files for your selected language, ' . $user_language . ', have not been updated to the latest version. Upgrade will continue with the forum default, ' . $upcontext['language'] . '.';
928
				elseif (!file_exists($modSettings['theme_dir'] . '/languages/Install.' . basename($user_language, '.lng') . '.php'))
929
					$upcontext['upgrade_options_warning'] = 'The language files for your selected language, ' . $user_language . ', have not been uploaded/updated as the &quot;Install&quot; language file is missing. Upgrade will continue with the forum default, ' . $upcontext['language'] . '.';
930
				else
931
				{
932
					// Set this as the new language.
933
					$upcontext['language'] = $user_language;
934
					$upcontext['upgrade_status']['lang'] = $upcontext['language'];
935
936
					// Include the file.
937
					require_once($modSettings['theme_dir'] . '/languages/Install.' . $user_language . '.php');
938
				}
939
			}
940
941
			// If we're resuming set the step and substep to be correct.
942
			if (isset($_POST['cont']))
943
			{
944
				$upcontext['current_step'] = $upcontext['user']['step'];
945
				$_GET['substep'] = $upcontext['user']['substep'];
946
			}
947
948
			return true;
949
		}
950
	}
951
952
	return false;
953
}
954
955
// Step 1: Do the maintenance and backup.
956
function UpgradeOptions()
957
{
958
	global $db_prefix, $command_line, $modSettings, $is_debug, $smcFunc, $packagesdir, $tasksdir;
959
	global $boarddir, $boardurl, $sourcedir, $maintenance, $cachedir, $upcontext, $db_type, $db_server, $db_last_error;
960
961
	$upcontext['sub_template'] = 'upgrade_options';
962
	$upcontext['page_title'] = 'Upgrade Options';
963
964
	db_extend('packages');
965
	$upcontext['karma_installed'] = array('good' => false, 'bad' => false);
966
	$member_columns = $smcFunc['db_list_columns']('{db_prefix}members');
967
968
	$upcontext['karma_installed']['good'] = in_array('karma_good', $member_columns);
969
	$upcontext['karma_installed']['bad'] = in_array('karma_bad', $member_columns);
970
971
	unset($member_columns);
972
973
	// If we've not submitted then we're done.
974
	if (empty($_POST['upcont']))
975
		return false;
976
977
	require_once($sourcedir . '/Subs-Admin.php');
978
	updateSettingsFile(array('image_proxy_secret' => '\'' . substr(sha1(mt_rand()), 0, 20) . '\''));
979
980
	// Firstly, if they're enabling SM stat collection just do it.
981
	if (!empty($_POST['stats']) && substr($boardurl, 0, 16) != 'http://localhost' && empty($modSettings['allow_sm_stats']))
982
	{
983
		// Attempt to register the site etc.
984
		$fp = @fsockopen('www.simplemachines.org', 80, $errno, $errstr);
985
		if ($fp)
986
		{
987
			$out = 'GET /smf/stats/register_stats.php?site=' . base64_encode($boardurl) . ' HTTP/1.1' . "\r\n";
988
			$out .= 'Host: www.simplemachines.org' . "\r\n";
989
			$out .= 'Connection: Close' . "\r\n\r\n";
990
			fwrite($fp, $out);
991
992
			$return_data = '';
993
			while (!feof($fp))
994
				$return_data .= fgets($fp, 128);
995
996
			fclose($fp);
997
998
			// Get the unique site ID.
999
			preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1000
1001 View Code Duplication
			if (!empty($ID[1]))
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...
1002
				$smcFunc['db_insert']('replace',
1003
					$db_prefix . 'settings',
1004
					array('variable' => 'string', 'value' => 'string'),
1005
					array('allow_sm_stats', $ID[1]),
1006
					array('variable')
1007
				);
1008
		}
1009
	}
1010
	else
1011
		$smcFunc['db_query']('', '
1012
			DELETE FROM {db_prefix}settings
1013
			WHERE variable = {string:allow_sm_stats}',
1014
			array(
1015
				'allow_sm_stats' => 'allow_sm_stats',
1016
				'db_error_skip' => true,
1017
			)
1018
		);
1019
1020
	// Deleting old karma stuff?
1021
	if (!empty($_POST['delete_karma']))
1022
	{
1023
		// Delete old settings vars.
1024
		$smcFunc['db_query']('', '
1025
			DELETE FROM {db_prefix}settings
1026
			WHERE variable IN ({array_string:karma_vars})',
1027
			array(
1028
				'karma_vars' => array('karmaMode', 'karmaTimeRestrictAdmins', 'karmaWaitTime', 'karmaMinPosts', 'karmaLabel', 'karmaSmiteLabel', 'karmaApplaudLabel'),
1029
			)
1030
		);
1031
1032
		// Cleaning up old karma member settings.
1033
		if ($upcontext['karma_installed']['good'])
1034
			$smcFunc['db_query']('', '
1035
				ALTER TABLE {db_prefix}members
1036
				DROP karma_good',
1037
				array()
1038
			);
1039
1040
		// Does karma bad was enable?
1041
		if ($upcontext['karma_installed']['bad'])
1042
			$smcFunc['db_query']('', '
1043
				ALTER TABLE {db_prefix}members
1044
				DROP karma_bad',
1045
				array()
1046
			);
1047
1048
		// Cleaning up old karma permissions.
1049
		$smcFunc['db_query']('', '
1050
			DELETE FROM {db_prefix}permissions
1051
			WHERE permission = {string:karma_vars}',
1052
			array(
1053
				'karma_vars' => 'karma_edit',
1054
			)
1055
		);
1056
	}
1057
1058
	// Emptying the error log?
1059
	if (!empty($_POST['empty_error']))
1060
		$smcFunc['db_query']('truncate_table', '
1061
			TRUNCATE {db_prefix}log_errors',
1062
			array(
1063
			)
1064
		);
1065
1066
	$changes = array();
1067
1068
	// If we're overriding the language follow it through.
1069 View Code Duplication
	if (isset($_GET['lang']) && file_exists($modSettings['theme_dir'] . '/languages/index.' . $_GET['lang'] . '.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...
1070
		$changes['language'] = '\'' . $_GET['lang'] . '\'';
1071
1072
	if (!empty($_POST['maint']))
1073
	{
1074
		$changes['maintenance'] = '2';
1075
		// Remember what it was...
1076
		$upcontext['user']['main'] = $maintenance;
1077
1078
		if (!empty($_POST['maintitle']))
1079
		{
1080
			$changes['mtitle'] = '\'' . addslashes($_POST['maintitle']) . '\'';
1081
			$changes['mmessage'] = '\'' . addslashes($_POST['mainmessage']) . '\'';
1082
		}
1083
		else
1084
		{
1085
			$changes['mtitle'] = '\'Upgrading the forum...\'';
1086
			$changes['mmessage'] = '\'Don\\\'t worry, we will be back shortly with an updated forum.  It will only be a minute ;).\'';
1087
		}
1088
	}
1089
1090
	if ($command_line)
1091
		echo ' * Updating Settings.php...';
1092
1093
	// Backup the current one first.
1094
	copy($boarddir . '/Settings.php', $boarddir . '/Settings_bak.php');
1095
1096
	// Fix some old paths.
1097 View Code Duplication
	if (substr($boarddir, 0, 1) == '.')
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...
1098
		$changes['boarddir'] = '\'' . fixRelativePath($boarddir) . '\'';
1099
1100 View Code Duplication
	if (substr($sourcedir, 0, 1) == '.')
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...
1101
		$changes['sourcedir'] = '\'' . fixRelativePath($sourcedir) . '\'';
1102
1103
	if (empty($cachedir) || substr($cachedir, 0, 1) == '.')
1104
		$changes['cachedir'] = '\'' . fixRelativePath($boarddir) . '/cache\'';
1105
1106
	// Not had the database type added before?
1107
	if (empty($db_type))
1108
		$changes['db_type'] = 'mysql';
1109
1110
	// For now we offer a option, this may change in future versions when mysql is completely removed.
1111
	if (!empty($_POST['convertMysql']) && $db_type == 'mysql')
1112
		$changes['db_type'] = '\'mysqli\'';
1113
1114
	// If they have a "host:port" setup for the host, split that into separate values
1115
	// You should never have a : in the hostname if you're not on MySQL, but better safe than sorry
1116
	if (strpos($db_server, ':') !== false && ($db_type == 'mysql' || $db_type == 'mysqli'))
1117
	{
1118
		list($db_server, $db_port) = explode(':', $db_server);
1119
1120
		$changes['db_server'] = '\'' . $db_server . '\'';
1121
1122
		// Only set this if we're not using the default port
1123
		if ($db_port != ini_get('mysql' . ($db_type == 'mysqli' || !empty($_POST['convertMysql']) ? 'i' : '') . '.default_port'))
1124
			$changes['db_port'] = (int) $db_port;
1125
	}
1126
	elseif(!empty($db_port))
0 ignored issues
show
Bug introduced by
The variable $db_port seems only to be defined at a later point. As such the call to empty() seems to always evaluate to true.

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

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

Loading history...
1127
	{
1128
		// If db_port is set and is the same as the default, set it to ''
1129
		if ($db_type == 'mysql' || $db_type == 'mysqli')
1130
		{
1131
			if ($db_port == ini_get('mysql' . ($db_type == 'mysqli' || !empty($_POST['convertMysql']) ? 'i' : '') . '.default_port'))
1132
				$changes['db_port'] = '\'\'';
1133
			elseif ($db_type == 'postgresql' && $db_port == 5432)
1134
				$changes['db_port'] = '\'\'';
1135
		}
1136
	}
1137
1138
	// Maybe we haven't had this option yet?
1139
	if (empty($packagesdir))
1140
		$changes['packagesdir'] = '\'' . fixRelativePath($boarddir) . '/Packages\'';
1141
1142
	// Add support for $tasksdir var.
1143
	if (empty($tasksdir))
1144
		$changes['tasksdir'] = '\'' . fixRelativePath($sourcedir) . '/tasks\'';
1145
1146
	// @todo Maybe change the cookie name if going to 1.1, too?
1147
1148
	// Update Settings.php with the new settings.
1149
	changeSettings($changes);
1150
1151
	// Back up again before we do anything else, just in case...
1152
	copy($boarddir . '/Settings.php', $boarddir . '/Settings_bak.php');
1153
1154
	// Read the contents of the file in as a string
1155
	$settings_file = file_get_contents($boarddir . '/Settings.php');
1156
1157
	// Look to see if the new error-catching section is there...
1158
	if (stripos($settings_file, 'if (file_exists(dirname(__FILE__) . \'/db_last_error.php\'))') === false)
1159
	{
1160
		// This is what we want to add...
1161
		$error_catching_header = '
1162
########## Error-Catching ##########
1163
# Note: You shouldn\'t touch these settings.';
1164
1165
		$error_catching = '
1166
if (file_exists(dirname(__FILE__) . \'/db_last_error.php\'))
1167
	include(dirname(__FILE__) . \'/db_last_error.php\');
1168
1169
if (!isset($db_last_error))
1170
{
1171
	// File does not exist so lets try to create it
1172
	file_put_contents(dirname(__FILE__) . \'/db_last_error.php\', \'<\' . \'?\' . "php\n" . \'$db_last_error = 0;\' . "\n" . \'?\' . \'>\');
1173
	$db_last_error = 0;
1174
}
1175
';
1176
		// Before we go any further, check to see if the original code is there first...
1177
		if (stripos('########## Error-Catching ##########', $settings_file !== false))
1178
		{
1179
			$found_old = true;
1180
			// Replace the old line with the new code - assuming the header is already there
1181
			$settings_file = str_replace('$db_last_error = ' . $db_last_error . ';', $error_catching, $settings_file);
1182
		}
1183
		// What about just the db_last_error line?
1184
		elseif (stripos('$db_last_error =', $settings_file !== false))
1185
		{
1186
			$found_old = true;
1187
			// Replace the old line with the new code
1188
			$settings_file = str_replace('$db_last_error = ' . $db_last_error . ';', $error_catching_header . $error_catching, $settings_file);
1189
		}
1190
		else
1191
		{
1192
			$found_old = false;
1193
			// We want the comments as well as the code...
1194
			$error_catching = $error_catching_header . $error_catching;
1195
		}
1196
1197
		// Blank out the file - done to fix a oddity with some servers.
1198
		$fp = fopen($boarddir . '/Settings.php', 'w');
1199
		fclose($fp);
1200
1201
		// Open the file for writing
1202
		$file = fopen($boarddir . '/Settings.php', 'r+');
1203
1204
		// Write the original contents...
1205
		fwrite($file, $settings_file);
1206
1207
		// If we didn't find the old code, add the new code at the end instead...
1208
		if (!$found_old)
1209
		{
1210
			// Go to the position two bytes before the end - in front of the closing PHP tag
1211
			fseek($file, -2, SEEK_END);
1212
1213
			// Append our new data - the extra line break above will prevent us from breaking things...
1214
			fwrite($file, $error_catching);
1215
		}
1216
1217
		// Close the file
1218
		fclose($file);
1219
	}
1220
1221
	if ($command_line)
1222
		echo ' Successful.' . "\n";
1223
1224
	// Are we doing debug?
1225
	if (isset($_POST['debug']))
1226
	{
1227
		$upcontext['upgrade_status']['debug'] = true;
1228
		$is_debug = true;
1229
	}
1230
1231
	// If we're not backing up then jump one.
1232
	if (empty($_POST['backup']))
1233
		$upcontext['current_step']++;
1234
1235
	// If we've got here then let's proceed to the next step!
1236
	return true;
1237
}
1238
1239
// Backup the database - why not...
1240
function BackupDatabase()
1241
{
1242
	global $upcontext, $db_prefix, $command_line, $is_debug, $support_js, $file_steps, $smcFunc;
1243
1244
	$upcontext['sub_template'] = isset($_GET['xml']) ? 'backup_xml' : 'backup_database';
1245
	$upcontext['page_title'] = 'Backup Database';
1246
1247
	// Done it already - js wise?
1248
	if (!empty($_POST['backup_done']))
1249
		return true;
1250
1251
	// Some useful stuff here.
1252
	db_extend();
1253
1254
	// Might need this as well
1255
	db_extend('packages');
1256
1257
	// Get all the table names.
1258
	$filter = str_replace('_', '\_', preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) != 0 ? $match[2] : $db_prefix) . '%';
1259
	$db = preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) != 0 ? strtr($match[1], array('`' => '')) : false;
1260
	$tables = $smcFunc['db_list_tables']($db, $filter);
1261
1262
	$table_names = array();
1263
	foreach ($tables as $table)
1264
		if (substr($table, 0, 7) !== 'backup_')
1265
			$table_names[] = $table;
1266
1267
	$upcontext['table_count'] = count($table_names);
1268
	$upcontext['cur_table_num'] = $_GET['substep'];
1269
	$upcontext['cur_table_name'] = str_replace($db_prefix, '', isset($table_names[$_GET['substep']]) ? $table_names[$_GET['substep']] : $table_names[0]);
1270
	$upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100);
1271
	// For non-java auto submit...
1272
	$file_steps = $upcontext['table_count'];
1273
1274
	// What ones have we already done?
1275 View Code Duplication
	foreach ($table_names as $id => $table)
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...
1276
		if ($id < $_GET['substep'])
1277
			$upcontext['previous_tables'][] = $table;
1278
1279
	if ($command_line)
1280
		echo 'Backing Up Tables.';
1281
1282
	// If we don't support javascript we backup here.
1283
	if (!$support_js || isset($_GET['xml']))
1284
	{
1285
		// Backup each table!
1286
		for ($substep = $_GET['substep'], $n = count($table_names); $substep < $n; $substep++)
1287
		{
1288
			$upcontext['cur_table_name'] = str_replace($db_prefix, '', (isset($table_names[$substep + 1]) ? $table_names[$substep + 1] : $table_names[$substep]));
1289
			$upcontext['cur_table_num'] = $substep + 1;
1290
1291
			$upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100);
1292
1293
			// Do we need to pause?
1294
			nextSubstep($substep);
1295
1296
			backupTable($table_names[$substep]);
1297
1298
			// If this is XML to keep it nice for the user do one table at a time anyway!
1299
			if (isset($_GET['xml']))
1300
				return upgradeExit();
1301
		}
1302
1303
		if ($is_debug && $command_line)
1304
		{
1305
			echo "\n" . ' Successful.\'' . "\n";
1306
			flush();
1307
		}
1308
		$upcontext['step_progress'] = 100;
1309
1310
		$_GET['substep'] = 0;
1311
		// Make sure we move on!
1312
		return true;
1313
	}
1314
1315
	// Either way next place to post will be database changes!
1316
	$_GET['substep'] = 0;
1317
	return false;
1318
}
1319
1320
// Backup one table...
1321
function backupTable($table)
1322
{
1323
	global $is_debug, $command_line, $db_prefix, $smcFunc;
1324
1325
	if ($command_line)
1326
	{
1327
		echo "\n" . ' +++ Backing up \"' . str_replace($db_prefix, '', $table) . '"...';
1328
		flush();
1329
	}
1330
1331
	$smcFunc['db_backup_table']($table, 'backup_' . $table);
1332
1333
	if ($command_line)
1334
		echo ' done.';
1335
}
1336
1337
// Step 2: Everything.
1338
function DatabaseChanges()
1339
{
1340
	global $db_prefix, $modSettings, $command_line, $smcFunc;
1341
	global $upcontext, $support_js, $db_type;
1342
1343
	// Have we just completed this?
1344
	if (!empty($_POST['database_done']))
1345
		return true;
1346
1347
	$upcontext['sub_template'] = isset($_GET['xml']) ? 'database_xml' : 'database_changes';
1348
	$upcontext['page_title'] = 'Database Changes';
1349
1350
	$type = ($db_type == 'mysqli' ? 'mysql' : $db_type);
1351
1352
	// All possible files.
1353
	// Name, <version, insert_on_complete
1354
	$files = array(
1355
		array('upgrade_1-0.sql', '1.1', '1.1 RC0'),
1356
		array('upgrade_1-1.sql', '2.0', '2.0 a'),
1357
		array('upgrade_2-0_' . $type . '.sql', '2.1', '2.1 dev0'),
1358
		array('upgrade_2-1_' . $type . '.sql', '3.0', SMF_VERSION),
1359
	);
1360
1361
	// How many files are there in total?
1362
	if (isset($_GET['filecount']))
1363
		$upcontext['file_count'] = (int) $_GET['filecount'];
1364
	else
1365
	{
1366
		$upcontext['file_count'] = 0;
1367
		foreach ($files as $file)
1368
		{
1369
			if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < $file[1])
1370
				$upcontext['file_count']++;
1371
		}
1372
	}
1373
1374
	// Do each file!
1375
	$did_not_do = count($files) - $upcontext['file_count'];
1376
	$upcontext['step_progress'] = 0;
1377
	$upcontext['cur_file_num'] = 0;
1378
	foreach ($files as $file)
1379
	{
1380
		if ($did_not_do)
1381
			$did_not_do--;
1382
		else
1383
		{
1384
			$upcontext['cur_file_num']++;
1385
			$upcontext['cur_file_name'] = $file[0];
1386
			// Do we actually need to do this still?
1387
			if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < $file[1])
1388
			{
1389
				$nextFile = parse_sql(dirname(__FILE__) . '/' . $file[0]);
1390 View Code Duplication
				if ($nextFile)
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...
1391
				{
1392
					// Only update the version of this if complete.
1393
					$smcFunc['db_insert']('replace',
1394
						$db_prefix . 'settings',
1395
						array('variable' => 'string', 'value' => 'string'),
1396
						array('smfVersion', $file[2]),
1397
						array('variable')
1398
					);
1399
1400
					$modSettings['smfVersion'] = $file[2];
1401
				}
1402
1403
				// If this is XML we only do this stuff once.
1404
				if (isset($_GET['xml']))
1405
				{
1406
					// Flag to move on to the next.
1407
					$upcontext['completed_step'] = true;
1408
					// Did we complete the whole file?
1409
					if ($nextFile)
1410
						$upcontext['current_debug_item_num'] = -1;
1411
					return upgradeExit();
1412
				}
1413
				elseif ($support_js)
1414
					break;
1415
			}
1416
			// Set the progress bar to be right as if we had - even if we hadn't...
1417
			$upcontext['step_progress'] = ($upcontext['cur_file_num'] / $upcontext['file_count']) * 100;
1418
		}
1419
	}
1420
1421
	$_GET['substep'] = 0;
1422
	// So the template knows we're done.
1423
	if (!$support_js)
1424
	{
1425
		$upcontext['changes_complete'] = true;
1426
1427
		return true;
1428
	}
1429
	return false;
1430
}
1431
1432
// Clean up any mods installed...
1433
function CleanupMods()
1434
{
1435
	global $db_prefix, $upcontext, $boarddir, $packagesdir, $settings, $smcFunc, $command_line;
1436
1437
	// Sorry. Not supported for command line users.
1438
	if ($command_line)
1439
		return true;
1440
1441
	// Skipping first?
1442
	if (!empty($_POST['skip']))
1443
	{
1444
		unset($_POST['skip']);
1445
		return true;
1446
	}
1447
1448
	// If we get here withOUT SSI we need to redirect to ensure we get it!
1449
	if (!isset($_GET['ssi']) || !function_exists('mktree'))
1450
		redirectLocation('&ssi=1');
1451
1452
	$upcontext['sub_template'] = 'clean_mods';
1453
	$upcontext['page_title'] = 'Cleanup Modifications';
1454
1455
	// This can be skipped.
1456
	$upcontext['skip'] = true;
1457
1458
	// If we're on the second redirect continue...
1459
	if (isset($_POST['cleandone2']))
1460
		return true;
1461
1462
	// Do we already know about some writable files?
1463
	if (isset($_POST['writable_files']))
1464
	{
1465
		$writable_files = safe_unserialize(base64_decode($_POST['writable_files']));
1466
		if (!makeFilesWritable($writable_files))
1467
		{
1468
			// What have we left?
1469
			$upcontext['writable_files'] = $writable_files;
1470
			return false;
1471
		}
1472
	}
1473
1474
	// Make sure we have some sort of packages directory.
1475
	if (!isset($packagesdir))
1476
		$packagesdir = $boarddir . '/Packages';
1477
1478
	// Load all theme paths....
1479
	$request = $smcFunc['db_query']('', '
1480
		SELECT id_theme, variable, value
1481
		FROM {db_prefix}themes
1482
		WHERE id_member = {int:id_member}
1483
			AND variable IN ({string:theme_dir}, {string:images_url})',
1484
		array(
1485
			'id_member' => 0,
1486
			'theme_dir' => 'theme_dir',
1487
			'images_url' => 'images_url',
1488
			'db_error_skip' => true,
1489
		)
1490
	);
1491
	$theme_paths = array();
1492
	while ($row = $smcFunc['db_fetch_assoc']($request))
1493
	{
1494
		if ($row['id_theme'] == 1)
1495
			$settings['default_' . $row['variable']] = $row['value'];
1496
		elseif ($row['variable'] == 'theme_dir')
1497
			$theme_paths[$row['id_theme']][$row['variable']] = $row['value'];
1498
	}
1499
	$smcFunc['db_free_result']($request);
1500
1501
	// Are there are mods installed that may need uninstalling?
1502
	$request = $smcFunc['db_query']('', '
1503
		SELECT id_install, filename, name, themes_installed, version
1504
		FROM {db_prefix}log_packages
1505
		WHERE install_state = {int:installed}
1506
		ORDER BY time_installed DESC',
1507
		array(
1508
			'installed' => 1,
1509
			'db_error_skip' => true,
1510
		)
1511
	);
1512
	$upcontext['packages'] = array();
1513
	while ($row = $smcFunc['db_fetch_assoc']($request))
1514
	{
1515
		// Work out the status.
1516
		if (!file_exists($packagesdir . '/' . $row['filename']))
1517
		{
1518
			$status = 'Missing';
1519
			$status_color = 'red';
1520
			$result = 'Removed';
1521
		}
1522
		else
1523
		{
1524
			$status = 'Installed';
1525
			$status_color = 'green';
1526
			$result = 'No Action Needed';
1527
		}
1528
1529
		$upcontext['packages'][$row['id_install']] = array(
1530
			'id' => $row['id_install'],
1531
			'themes' => explode(',', $row['themes_installed']),
1532
			'name' => $row['name'],
1533
			'filename' => $row['filename'],
1534
			'missing_file' => file_exists($packagesdir . '/' . $row['filename']) ? 0 : 1,
1535
			'files' => array(),
1536
			'file_count' => 0,
1537
			'status' => $status,
1538
			'result' => $result,
1539
			'color' => $status_color,
1540
			'version' => $row['version'],
1541
			'needs_removing' => false,
1542
		);
1543
	}
1544
	$smcFunc['db_free_result']($request);
1545
1546
	// Don't carry on if there are none.
1547
	if (empty($upcontext['packages']))
1548
		return true;
1549
1550
	// Setup some basics.
1551
	if (!empty($upcontext['user']['version']))
1552
		$_SESSION['version_emulate'] = $upcontext['user']['version'];
1553
1554
	// Before we get started, don't report notice errors.
1555
	$oldErrorReporting = error_reporting(E_ALL ^ E_NOTICE);
1556
1557
	if (!mktree($packagesdir . '/temp', 0755))
1558
	{
1559
		deltree($packagesdir . '/temp', false);
1560
		if (!mktree($packagesdir . '/temp', 0777))
1561
		{
1562
			deltree($packagesdir . '/temp', false);
1563
			// @todo Error here - plus chmod!
1564
		}
1565
	}
1566
1567
	// Anything which reinstalled should not have its entry removed.
1568
	$reinstall_worked = array();
1569
1570
	// We're gonna be doing some removin'
1571
	$test = isset($_POST['cleandone']) ? false : true;
1572
	foreach ($upcontext['packages'] as $id => $package)
1573
	{
1574
		// Can't do anything about this....
1575
		if ($package['missing_file'])
1576
			continue;
1577
1578
		// Not testing *and* this wasn't checked?
1579
		if (!$test && (!isset($_POST['remove']) || !isset($_POST['remove'][$id])))
1580
			continue;
1581
1582
		// What are the themes this was installed into?
1583
		$cur_theme_paths = array();
1584
		foreach ($theme_paths as $tid => $data)
1585
			if ($tid != 1 && in_array($tid, $package['themes']))
1586
				$cur_theme_paths[$tid] = $data;
1587
1588
		// Get the modifications data if applicable.
1589
		$filename = $package['filename'];
1590
		$packageInfo = getPackageInfo($filename);
1591
		if (!is_array($packageInfo))
1592
			continue;
1593
1594
		$info = parsePackageInfo($packageInfo['xml'], $test, 'uninstall');
1595
		// Also get the reinstall details...
1596
		if (isset($_POST['remove']))
1597
			$infoInstall = parsePackageInfo($packageInfo['xml'], true);
1598
1599 View Code Duplication
		if (is_file($packagesdir . '/' . $filename))
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...
1600
			read_tgz_file($packagesdir . '/' . $filename, $packagesdir . '/temp');
1601
		else
1602
			copytree($packagesdir . '/' . $filename, $packagesdir . '/temp');
1603
1604
		// Work out how we uninstall...
1605
		$files = array();
1606
		foreach ($info as $change)
1607
		{
1608
			// Work out two things:
1609
			// 1) Whether it's installed at the moment - and if so whether its fully installed, and:
1610
			// 2) Whether it could be installed on the new version.
1611
			if ($change['type'] == 'modification')
1612
			{
1613
				$contents = @file_get_contents($packagesdir . '/temp/' . $upcontext['base_path'] . $change['filename']);
1614
				if ($change['boardmod'])
1615
					$results = parseBoardMod($contents, $test, $change['reverse'], $cur_theme_paths);
1616
				else
1617
					$results = parseModification($contents, $test, $change['reverse'], $cur_theme_paths);
1618
1619
				foreach ($results as $action)
1620
				{
1621
					// Something we can remove? Probably means it existed!
1622
					if (($action['type'] == 'replace' || $action['type'] == 'append' || (!empty($action['filename']) && $action['type'] == 'failure')) && !in_array($action['filename'], $files))
1623
						$files[] = $action['filename'];
1624
					if ($action['type'] == 'failure')
1625
					{
1626
						$upcontext['packages'][$id]['needs_removing'] = true;
1627
						$upcontext['packages'][$id]['status'] = 'Reinstall Required';
1628
						$upcontext['packages'][$id]['color'] = '#FD6435';
1629
					}
1630
				}
1631
			}
1632
		}
1633
1634
		// Store this info for the template as appropriate.
1635
		$upcontext['packages'][$id]['files'] = $files;
1636
		$upcontext['packages'][$id]['file_count'] = count($files);
1637
1638
		// If we've done something save the changes!
1639
		if (!$test)
1640
			package_flush_cache();
1641
1642
		// Are we attempting to reinstall this thing?
1643
		if (isset($_POST['remove']) && !$test && isset($infoInstall))
1644
		{
1645
			// Need to extract again I'm afraid.
1646 View Code Duplication
			if (is_file($packagesdir . '/' . $filename))
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...
1647
				read_tgz_file($packagesdir . '/' . $filename, $packagesdir . '/temp');
1648
			else
1649
				copytree($packagesdir . '/' . $filename, $packagesdir . '/temp');
1650
1651
			$errors = false;
1652
			$upcontext['packages'][$id]['result'] = 'Removed';
1653
			foreach ($infoInstall as $change)
1654
			{
1655
				if ($change['type'] == 'modification')
1656
				{
1657
					$contents = @file_get_contents($packagesdir . '/temp/' . $upcontext['base_path'] . $change['filename']);
1658 View Code Duplication
					if ($change['boardmod'])
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...
1659
						$results = parseBoardMod($contents, true, $change['reverse'], $cur_theme_paths);
1660
					else
1661
						$results = parseModification($contents, true, $change['reverse'], $cur_theme_paths);
1662
1663
					// Are there any errors?
1664
					foreach ($results as $action)
1665
						if ($action['type'] == 'failure')
1666
							$errors = true;
1667
				}
1668
			}
1669
			if (!$errors)
1670
			{
1671
				$reinstall_worked[] = $id;
1672
				$upcontext['packages'][$id]['result'] = 'Reinstalled';
1673
				$upcontext['packages'][$id]['color'] = 'green';
1674
				foreach ($infoInstall as $change)
1675
				{
1676
					if ($change['type'] == 'modification')
1677
					{
1678
						$contents = @file_get_contents($packagesdir . '/temp/' . $upcontext['base_path'] . $change['filename']);
1679 View Code Duplication
						if ($change['boardmod'])
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...
1680
							$results = parseBoardMod($contents, false, $change['reverse'], $cur_theme_paths);
0 ignored issues
show
Unused Code introduced by
$results 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...
1681
						else
1682
							$results = parseModification($contents, false, $change['reverse'], $cur_theme_paths);
0 ignored issues
show
Unused Code introduced by
$results 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...
1683
					}
1684
				}
1685
1686
				// Save the changes.
1687
				package_flush_cache();
1688
			}
1689
		}
1690
	}
1691
1692
	// Put errors back on a sec.
1693
	error_reporting($oldErrorReporting);
1694
1695
	// Check everything is writable.
1696
	if ($test && !empty($upcontext['packages']))
1697
	{
1698
		$writable_files = array();
1699
		foreach ($upcontext['packages'] as $package)
1700
		{
1701
			if (!empty($package['files']))
1702
				foreach ($package['files'] as $file)
1703
					$writable_files[] = $file;
1704
		}
1705
1706
		if (!empty($writable_files))
1707
		{
1708
			$writable_files = array_unique($writable_files);
1709
			$upcontext['writable_files'] = $writable_files;
1710
1711
			if (!makeFilesWritable($writable_files))
1712
				return false;
1713
		}
1714
	}
1715
1716
	if (file_exists($packagesdir . '/temp'))
1717
		deltree($packagesdir . '/temp');
1718
1719
	// Removing/Reinstalling any packages?
1720
	if (isset($_POST['remove']))
1721
	{
1722
		$deletes = array();
1723
		foreach ($_POST['remove'] as $id => $dummy)
1724
		{
1725
			if (!in_array((int) $id, $reinstall_worked))
1726
				$deletes[] = (int) $id;
1727
		}
1728
1729
		if (!empty($deletes))
1730
			upgrade_query( '
1731
				UPDATE ' . $db_prefix . 'log_packages
1732
				SET install_state = 0
1733
				WHERE id_install IN (' . implode(',', $deletes) . ')');
1734
1735
		// Ensure we don't lose our changes!
1736
		package_put_contents($packagesdir . '/installed.list', time());
1737
1738
		$upcontext['sub_template'] = 'cleanup_done';
1739
		return false;
1740
	}
1741
	else
1742
	{
1743
		$allgood = true;
1744
		// Is there actually anything that needs our attention?
1745
		foreach ($upcontext['packages'] as $package)
0 ignored issues
show
Bug introduced by
The expression $upcontext['packages'] of type string|boolean|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1746
			if ($package['color'] != 'green')
1747
				$allgood = false;
1748
1749
		if ($allgood)
1750
			return true;
1751
	}
1752
1753
	$_GET['substep'] = 0;
1754
	return isset($_POST['cleandone']) ? true : false;
1755
}
1756
1757
1758
// Delete the damn thing!
1759
function DeleteUpgrade()
1760
{
1761
	global $command_line, $language, $upcontext, $boarddir, $sourcedir, $forum_version, $user_info, $maintenance, $smcFunc, $db_type;
1762
1763
	// Now it's nice to have some of the basic SMF source files.
1764
	if (!isset($_GET['ssi']) && !$command_line)
1765
		redirectLocation('&ssi=1');
1766
1767
	$upcontext['sub_template'] = 'upgrade_complete';
1768
	$upcontext['page_title'] = 'Upgrade Complete';
1769
1770
	$endl = $command_line ? "\n" : '<br>' . "\n";
1771
1772
	$changes = array(
1773
		'language' => '\'' . (substr($language, -4) == '.lng' ? substr($language, 0, -4) : $language) . '\'',
1774
		'db_error_send' => '1',
1775
		'upgradeData' => '#remove#',
1776
	);
1777
1778
	// Are we in maintenance mode?
1779
	if (isset($upcontext['user']['main']))
1780
	{
1781
		if ($command_line)
1782
			echo ' * ';
1783
		$upcontext['removed_maintenance'] = true;
1784
		$changes['maintenance'] = $upcontext['user']['main'];
1785
	}
1786
	// Otherwise if somehow we are in 2 let's go to 1.
1787
	elseif (!empty($maintenance) && $maintenance == 2)
1788
		$changes['maintenance'] = 1;
1789
1790
	// Wipe this out...
1791
	$upcontext['user'] = array();
1792
1793
	// Make a backup of Settings.php first as otherwise earlier changes are lost.
1794
	copy($boarddir . '/Settings.php', $boarddir . '/Settings_bak.php');
1795
	changeSettings($changes);
1796
1797
	// Clean any old cache files away.
1798
	clean_cache();
1799
1800
	// Can we delete the file?
1801
	$upcontext['can_delete_script'] = is_writable(dirname(__FILE__)) || is_writable(__FILE__);
1802
1803
	// Now is the perfect time to fetch the SM files.
1804
	if ($command_line)
1805
		cli_scheduled_fetchSMfiles();
1806
	else
1807
	{
1808
		require_once($sourcedir . '/ScheduledTasks.php');
1809
		$forum_version = SMF_VERSION;  // The variable is usually defined in index.php so lets just use the constant to do it for us.
1810
		scheduled_fetchSMfiles(); // Now go get those files!
1811
	}
1812
1813
	// Log what we've done.
1814
	if (empty($user_info['id']))
1815
		$user_info['id'] = !empty($upcontext['user']['id']) ? $upcontext['user']['id'] : 0;
1816
1817
	// Log the action manually, so CLI still works.
1818
	$smcFunc['db_insert']('',
1819
		'{db_prefix}log_actions',
1820
		array(
1821
			'log_time' => 'int', 'id_log' => 'int', 'id_member' => 'int', 'ip' => 'inet', 'action' => 'string',
1822
			'id_board' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'extra' => 'string-65534',
1823
		),
1824
		array(
1825
			time(), 3, $user_info['id'], $command_line ? '127.0.0.1' : $user_info['ip'], 'upgrade',
1826
			0, 0, 0, safe_serialize(array('version' => $forum_version, 'member' => $user_info['id'])),
1827
		),
1828
		array('id_action')
1829
	);
1830
	$user_info['id'] = 0;
1831
1832
	// Save the current database version.
1833
	$server_version = $smcFunc['db_server_info']();
1834 View Code Duplication
	if (($db_type == 'mysql' || $db_type == 'mysqli') && in_array(substr($server_version, 0, 6), array('5.0.50', '5.0.51')))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1835
		updateSettings(array('db_mysql_group_by_fix' => '1'));
1836
1837
	if ($command_line)
1838
	{
1839
		echo $endl;
1840
		echo 'Upgrade Complete!', $endl;
1841
		echo 'Please delete this file as soon as possible for security reasons.', $endl;
1842
		exit;
1843
	}
1844
1845
	// Make sure it says we're done.
1846
	$upcontext['overall_percent'] = 100;
1847
	if (isset($upcontext['step_progress']))
1848
		unset($upcontext['step_progress']);
1849
1850
	$_GET['substep'] = 0;
1851
	return false;
1852
}
1853
1854
// Just like the built in one, but setup for CLI to not use themes.
1855
function cli_scheduled_fetchSMfiles()
1856
{
1857
	global $sourcedir, $language, $forum_version, $modSettings, $smcFunc;
1858
1859
	if (empty($modSettings['time_format']))
1860
		$modSettings['time_format'] = '%B %d, %Y, %I:%M:%S %p';
1861
1862
	// What files do we want to get
1863
	$request = $smcFunc['db_query']('', '
1864
		SELECT id_file, filename, path, parameters
1865
		FROM {db_prefix}admin_info_files',
1866
		array(
1867
		)
1868
	);
1869
1870
	$js_files = array();
1871 View Code Duplication
	while ($row = $smcFunc['db_fetch_assoc']($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...
1872
	{
1873
		$js_files[$row['id_file']] = array(
1874
			'filename' => $row['filename'],
1875
			'path' => $row['path'],
1876
			'parameters' => sprintf($row['parameters'], $language, urlencode($modSettings['time_format']), urlencode($forum_version)),
1877
		);
1878
	}
1879
	$smcFunc['db_free_result']($request);
1880
1881
	// We're gonna need fetch_web_data() to pull this off.
1882
	require_once($sourcedir . '/Subs-Package.php');
1883
1884
	foreach ($js_files as $ID_FILE => $file)
1885
	{
1886
		// Create the url
1887
		$server = empty($file['path']) || substr($file['path'], 0, 7) != 'http://' ? 'http://www.simplemachines.org' : '';
1888
		$url = $server . (!empty($file['path']) ? $file['path'] : $file['path']) . $file['filename'] . (!empty($file['parameters']) ? '?' . $file['parameters'] : '');
1889
1890
		// Get the file
1891
		$file_data = fetch_web_data($url);
1892
1893
		// If we got an error - give up - the site might be down.
1894
		if ($file_data === false)
1895
			return throw_error(sprintf('Could not retrieve the file %1$s.', $url));
1896
1897
		// Save the file to the database.
1898
		$smcFunc['db_query']('substring', '
1899
			UPDATE {db_prefix}admin_info_files
1900
			SET data = SUBSTRING({string:file_data}, 1, 65534)
1901
			WHERE id_file = {int:id_file}',
1902
			array(
1903
				'id_file' => $ID_FILE,
1904
				'file_data' => $file_data,
1905
			)
1906
		);
1907
	}
1908
	return true;
1909
}
1910
1911
function convertSettingsToTheme()
1912
{
1913
	global $db_prefix, $modSettings, $smcFunc;
1914
1915
	$values = array(
1916
		'show_latest_member' => @$GLOBALS['showlatestmember'],
1917
		'show_bbc' => isset($GLOBALS['showyabbcbutt']) ? $GLOBALS['showyabbcbutt'] : @$GLOBALS['showbbcbutt'],
1918
		'show_modify' => @$GLOBALS['showmodify'],
1919
		'show_user_images' => @$GLOBALS['showuserpic'],
1920
		'show_blurb' => @$GLOBALS['showusertext'],
1921
		'show_gender' => @$GLOBALS['showgenderimage'],
1922
		'show_newsfader' => @$GLOBALS['shownewsfader'],
1923
		'display_recent_bar' => @$GLOBALS['Show_RecentBar'],
1924
		'show_member_bar' => @$GLOBALS['Show_MemberBar'],
1925
		'linktree_link' => @$GLOBALS['curposlinks'],
1926
		'show_profile_buttons' => @$GLOBALS['profilebutton'],
1927
		'show_mark_read' => @$GLOBALS['showmarkread'],
1928
		'newsfader_time' => @$GLOBALS['fadertime'],
1929
		'use_image_buttons' => empty($GLOBALS['MenuType']) ? 1 : 0,
1930
		'enable_news' => @$GLOBALS['enable_news'],
1931
		'return_to_post' => @$modSettings['returnToPost'],
1932
	);
1933
1934
	$themeData = array();
1935
	foreach ($values as $variable => $value)
1936
	{
1937
		if (!isset($value) || $value === null)
1938
			$value = 0;
1939
1940
		$themeData[] = array(0, 1, $variable, $value);
1941
	}
1942 View Code Duplication
	if (!empty($themeData))
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...
1943
	{
1944
		$smcFunc['db_insert']('ignore',
1945
			$db_prefix . 'themes',
1946
			array('id_member' => 'int', 'id_theme' => 'int', 'variable' => 'string', 'value' => 'string'),
1947
			$themeData,
1948
			array('id_member', 'id_theme', 'variable')
1949
		);
1950
	}
1951
}
1952
1953
// This function only works with MySQL but that's fine as it is only used for v1.0.
1954
function convertSettingstoOptions()
1955
{
1956
	global $modSettings, $smcFunc;
1957
1958
	// Format: new_setting -> old_setting_name.
1959
	$values = array(
1960
		'calendar_start_day' => 'cal_startmonday',
1961
		'view_newest_first' => 'viewNewestFirst',
1962
		'view_newest_pm_first' => 'viewNewestFirst',
1963
	);
1964
1965
	foreach ($values as $variable => $value)
1966
	{
1967
		if (empty($modSettings[$value[0]]))
1968
			continue;
1969
1970
		$smcFunc['db_query']('', '
1971
			INSERT IGNORE INTO {db_prefix}themes
1972
				(id_member, id_theme, variable, value)
1973
			SELECT id_member, 1, {string:variable}, {string:value}
1974
			FROM {db_prefix}members',
1975
			array(
1976
				'variable' => $variable,
1977
				'value' => $modSettings[$value[0]],
1978
				'db_error_skip' => true,
1979
			)
1980
		);
1981
1982
		$smcFunc['db_query']('', '
1983
			INSERT IGNORE INTO {db_prefix}themes
1984
				(id_member, id_theme, variable, value)
1985
			VALUES (-1, 1, {string:variable}, {string:value})',
1986
			array(
1987
				'variable' => $variable,
1988
				'value' => $modSettings[$value[0]],
1989
				'db_error_skip' => true,
1990
			)
1991
		);
1992
	}
1993
}
1994
1995
function changeSettings($config_vars)
1996
{
1997
	global $boarddir;
1998
1999
	$settingsArray = file($boarddir . '/Settings_bak.php');
2000
2001
	if (count($settingsArray) == 1)
2002
		$settingsArray = preg_split('~[\r\n]~', $settingsArray[0]);
2003
2004
	for ($i = 0, $n = count($settingsArray); $i < $n; $i++)
2005
	{
2006
		// Don't trim or bother with it if it's not a variable.
2007
		if (substr($settingsArray[$i], 0, 1) == '$')
2008
		{
2009
			$settingsArray[$i] = trim($settingsArray[$i]) . "\n";
2010
2011
			foreach ($config_vars as $var => $val)
2012
			{
2013
				if (isset($settingsArray[$i]) && strncasecmp($settingsArray[$i], '$' . $var, 1 + strlen($var)) == 0)
2014
				{
2015 View Code Duplication
					if ($val == '#remove#')
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...
2016
						unset($settingsArray[$i]);
2017
					else
2018
					{
2019
						$comment = strstr(substr($settingsArray[$i], strpos($settingsArray[$i], ';')), '#');
2020
						$settingsArray[$i] = '$' . $var . ' = ' . $val . ';' . ($comment != '' ? "\t\t" . $comment : "\n");
2021
					}
2022
2023
					unset($config_vars[$var]);
2024
				}
2025
			}
2026
		}
2027 View Code Duplication
		if (isset($settingsArray[$i]))
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...
2028
		{
2029
			if (trim(substr($settingsArray[$i], 0, 2)) == '?' . '>')
2030
				$end = $i;
2031
		}
2032
	}
2033
2034
	// Assume end-of-file if the end wasn't found.
2035
	if (empty($end) || $end < 10)
2036
		$end = count($settingsArray);
2037
2038 View Code Duplication
	if (!empty($config_vars))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2039
	{
2040
		$settingsArray[$end++] = '';
2041
		foreach ($config_vars as $var => $val)
2042
		{
2043
			if ($val != '#remove#')
2044
				$settingsArray[$end++] = '$' . $var . ' = ' . $val . ';' . "\n";
2045
		}
2046
	}
2047
	// This should be the last line and even last bytes of the file.
2048
	$settingsArray[$end] = '?' . '>';
2049
2050
	// Blank out the file - done to fix a oddity with some servers.
2051
	$fp = fopen($boarddir . '/Settings.php', 'w');
2052
	fclose($fp);
2053
2054
	$fp = fopen($boarddir . '/Settings.php', 'r+');
2055
	for ($i = 0; $i < $end; $i++)
2056
	{
2057
		if (isset($settingsArray[$i]))
2058
			fwrite($fp, strtr($settingsArray[$i], "\r", ''));
2059
	}
2060
	fwrite($fp, rtrim($settingsArray[$i]));
2061
	fclose($fp);
2062
}
2063
function updateLastError()
2064
{
2065
	// clear out the db_last_error file
2066
	file_put_contents(dirname(__FILE__) . '/db_last_error.php', '<' . '?' . "php\n" . '$db_last_error = 0;' . "\n" . '?' . '>');
2067
}
2068
2069
function php_version_check()
2070
{
2071
	return version_compare(PHP_VERSION, $GLOBALS['required_php_version'], '>=');
2072
}
2073
2074
function db_version_check()
2075
{
2076
	global $db_type, $databases;
2077
2078
	$curver = eval($databases[$db_type]['version_check']);
0 ignored issues
show
Coding Style introduced by
The function db_version_check() contains an eval expression.

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

Loading history...
2079
	$curver = preg_replace('~\-.+?$~', '', $curver);
2080
2081
	return version_compare($databases[$db_type]['version'], $curver, '<=');
2082
}
2083
2084
function getMemberGroups()
2085
{
2086
	global $smcFunc;
2087
	static $member_groups = array();
2088
2089
	if (!empty($member_groups))
2090
		return $member_groups;
2091
2092
	$request = $smcFunc['db_query']('', '
2093
		SELECT group_name, id_group
2094
		FROM {db_prefix}membergroups
2095
		WHERE id_group = {int:admin_group} OR id_group > {int:old_group}',
2096
		array(
2097
			'admin_group' => 1,
2098
			'old_group' => 7,
2099
			'db_error_skip' => true,
2100
		)
2101
	);
2102
	if ($request === false)
2103
	{
2104
		$request = $smcFunc['db_query']('', '
2105
			SELECT membergroup, id_group
2106
			FROM {db_prefix}membergroups
2107
			WHERE id_group = {int:admin_group} OR id_group > {int:old_group}',
2108
			array(
2109
				'admin_group' => 1,
2110
				'old_group' => 7,
2111
				'db_error_skip' => true,
2112
			)
2113
		);
2114
	}
2115
	while ($row = $smcFunc['db_fetch_row']($request))
2116
		$member_groups[trim($row[0])] = $row[1];
2117
	$smcFunc['db_free_result']($request);
2118
2119
	return $member_groups;
2120
}
2121
2122
function fixRelativePath($path)
2123
{
2124
	global $install_path;
2125
2126
	// Fix the . at the start, clear any duplicate slashes, and fix any trailing slash...
2127
	return addslashes(preg_replace(array('~^\.([/\\\]|$)~', '~[/]+~', '~[\\\]+~', '~[/\\\]$~'), array($install_path . '$1', '/', '\\', ''), $path));
2128
}
2129
2130
function parse_sql($filename)
2131
{
2132
	global $db_prefix, $db_collation, $boarddir, $boardurl, $command_line, $file_steps, $step_progress, $custom_warning;
2133
	global $upcontext, $support_js, $is_debug, $smcFunc, $databases, $db_type, $db_character_set;
2134
2135
/*
2136
	Failure allowed on:
2137
		- INSERT INTO but not INSERT IGNORE INTO.
2138
		- UPDATE IGNORE but not UPDATE.
2139
		- ALTER TABLE and ALTER IGNORE TABLE.
2140
		- DROP TABLE.
2141
	Yes, I realize that this is a bit confusing... maybe it should be done differently?
2142
2143
	If a comment...
2144
		- begins with --- it is to be output, with a break only in debug mode. (and say successful\n\n if there was one before.)
2145
		- begins with ---# it is a debugging statement, no break - only shown at all in debug.
2146
		- is only ---#, it is "done." and then a break - only shown in debug.
2147
		- begins with ---{ it is a code block terminating at ---}.
2148
2149
	Every block of between "--- ..."s is a step.  Every "---#" section represents a substep.
2150
2151
	Replaces the following variables:
2152
		- {$boarddir}
2153
		- {$boardurl}
2154
		- {$db_prefix}
2155
		- {$db_collation}
2156
*/
2157
2158
	// May want to use extended functionality.
2159
	db_extend();
2160
	db_extend('packages');
2161
2162
	// Our custom error handler - does nothing but does stop public errors from XML!
2163
	if (!function_exists('sql_error_handler'))
2164
	{
2165
		function sql_error_handler($errno, $errstr, $errfile, $errline)
0 ignored issues
show
Unused Code introduced by
The parameter $errno 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...
2166
		{
2167
			global $support_js;
2168
2169
			if ($support_js)
2170
				return true;
2171
			else
2172
				echo 'Error: ' . $errstr . ' File: ' . $errfile . ' Line: ' . $errline;
2173
		}
2174
	}
2175
2176
	// Make our own error handler.
2177
	set_error_handler('sql_error_handler');
2178
2179
	// If we're on MySQL supporting collations then let's find out what the members table uses and put it in a global var - to allow upgrade script to match collations!
2180
	if (!empty($databases[$db_type]['utf8_support']) && version_compare($databases[$db_type]['utf8_version'], eval($databases[$db_type]['utf8_version_check']), '>'))
0 ignored issues
show
Coding Style introduced by
The function parse_sql() contains an eval expression.

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

Loading history...
2181
	{
2182
		$request = $smcFunc['db_query']('', '
2183
			SHOW TABLE STATUS
2184
			LIKE {string:table_name}',
2185
			array(
2186
				'table_name' => "{$db_prefix}members",
2187
				'db_error_skip' => true,
2188
			)
2189
		);
2190
		if ($smcFunc['db_num_rows']($request) === 0)
2191
			die('Unable to find members table!');
2192
		$table_status = $smcFunc['db_fetch_assoc']($request);
2193
		$smcFunc['db_free_result']($request);
2194
2195
		if (!empty($table_status['Collation']))
2196
		{
2197
			$request = $smcFunc['db_query']('', '
2198
				SHOW COLLATION
2199
				LIKE {string:collation}',
2200
				array(
2201
					'collation' => $table_status['Collation'],
2202
					'db_error_skip' => true,
2203
				)
2204
			);
2205
			// Got something?
2206
			if ($smcFunc['db_num_rows']($request) !== 0)
2207
				$collation_info = $smcFunc['db_fetch_assoc']($request);
2208
			$smcFunc['db_free_result']($request);
2209
2210
			// Excellent!
2211
			if (!empty($collation_info['Collation']) && !empty($collation_info['Charset']))
2212
				$db_collation = ' CHARACTER SET ' . $collation_info['Charset'] . ' COLLATE ' . $collation_info['Collation'];
2213
		}
2214
	}
2215
	if (empty($db_collation))
2216
		$db_collation = '';
2217
2218
	$endl = $command_line ? "\n" : '<br>' . "\n";
2219
2220
	$lines = file($filename);
2221
2222
	$current_type = 'sql';
2223
	$current_data = '';
2224
	$substep = 0;
2225
	$last_step = '';
2226
2227
	// Make sure all newly created tables will have the proper characters set.
2228
	if (isset($db_character_set) && $db_character_set === 'utf8')
2229
		$lines = str_replace(') ENGINE=MyISAM;', ') ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;', $lines);
2230
2231
	// Count the total number of steps within this file - for progress.
2232
	$file_steps = substr_count(implode('', $lines), '---#');
2233
	$upcontext['total_items'] = substr_count(implode('', $lines), '--- ');
2234
	$upcontext['debug_items'] = $file_steps;
2235
	$upcontext['current_item_num'] = 0;
2236
	$upcontext['current_item_name'] = '';
2237
	$upcontext['current_debug_item_num'] = 0;
2238
	$upcontext['current_debug_item_name'] = '';
2239
	// This array keeps a record of what we've done in case java is dead...
2240
	$upcontext['actioned_items'] = array();
2241
2242
	$done_something = false;
2243
2244
	foreach ($lines as $line_number => $line)
2245
	{
2246
		$do_current = $substep >= $_GET['substep'];
2247
2248
		// Get rid of any comments in the beginning of the line...
2249
		if (substr(trim($line), 0, 2) === '/*')
2250
			$line = preg_replace('~/\*.+?\*/~', '', $line);
2251
2252
		// Always flush.  Flush, flush, flush.  Flush, flush, flush, flush!  FLUSH!
2253
		if ($is_debug && !$support_js && $command_line)
2254
			flush();
2255
2256
		if (trim($line) === '')
2257
			continue;
2258
2259
		if (trim(substr($line, 0, 3)) === '---')
2260
		{
2261
			$type = substr($line, 3, 1);
2262
2263
			// An error??
2264
			if (trim($current_data) != '' && $type !== '}')
2265
			{
2266
				$upcontext['error_message'] = 'Error in upgrade script - line ' . $line_number . '!' . $endl;
2267
				if ($command_line)
2268
					echo $upcontext['error_message'];
2269
			}
2270
2271
			if ($type == ' ')
2272
			{
2273
				if (!$support_js && $do_current && $_GET['substep'] != 0 && $command_line)
2274
				{
2275
					echo ' Successful.', $endl;
2276
					flush();
2277
				}
2278
2279
				$last_step = htmlspecialchars(rtrim(substr($line, 4)));
2280
				$upcontext['current_item_num']++;
2281
				$upcontext['current_item_name'] = $last_step;
2282
2283
				if ($do_current)
2284
				{
2285
					$upcontext['actioned_items'][] = $last_step;
2286
					if ($command_line)
2287
						echo ' * ';
2288
				}
2289
			}
2290
			elseif ($type == '#')
2291
			{
2292
				$upcontext['step_progress'] += (100 / $upcontext['file_count']) / $file_steps;
2293
2294
				$upcontext['current_debug_item_num']++;
2295
				if (trim($line) != '---#')
2296
					$upcontext['current_debug_item_name'] = htmlspecialchars(rtrim(substr($line, 4)));
2297
2298
				// Have we already done something?
2299
				if (isset($_GET['xml']) && $done_something)
2300
				{
2301
					restore_error_handler();
2302
					return $upcontext['current_debug_item_num'] >= $upcontext['debug_items'] ? true : false;
2303
				}
2304
2305
				if ($do_current)
2306
				{
2307
					if (trim($line) == '---#' && $command_line)
2308
						echo ' done.', $endl;
2309
					elseif ($command_line)
2310
						echo ' +++ ', rtrim(substr($line, 4));
2311
					elseif (trim($line) != '---#')
2312
					{
2313
						if ($is_debug)
2314
							$upcontext['actioned_items'][] = htmlspecialchars(rtrim(substr($line, 4)));
2315
					}
2316
				}
2317
2318
				if ($substep < $_GET['substep'] && $substep + 1 >= $_GET['substep'])
2319
				{
2320
					if ($command_line)
2321
						echo ' * ';
2322
					else
2323
						$upcontext['actioned_items'][] = $last_step;
2324
				}
2325
2326
				// Small step - only if we're actually doing stuff.
2327
				if ($do_current)
2328
					nextSubstep(++$substep);
2329
				else
2330
					$substep++;
2331
			}
2332
			elseif ($type == '{')
2333
				$current_type = 'code';
2334
			elseif ($type == '}')
2335
			{
2336
				$current_type = 'sql';
2337
2338
				if (!$do_current)
2339
				{
2340
					$current_data = '';
2341
					continue;
2342
				}
2343
2344
				if (eval('global $db_prefix, $modSettings, $smcFunc; ' . $current_data) === false)
0 ignored issues
show
Coding Style introduced by
The function parse_sql() contains an eval expression.

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

Loading history...
2345
				{
2346
					$upcontext['error_message'] = 'Error in upgrade script ' . basename($filename) . ' on line ' . $line_number . '!' . $endl;
2347
					if ($command_line)
2348
						echo $upcontext['error_message'];
2349
				}
2350
2351
				// Done with code!
2352
				$current_data = '';
2353
				$done_something = true;
2354
			}
2355
2356
			continue;
2357
		}
2358
2359
		$current_data .= $line;
2360
		if (substr(rtrim($current_data), -1) === ';' && $current_type === 'sql')
2361
		{
2362
			if ((!$support_js || isset($_GET['xml'])))
2363
			{
2364
				if (!$do_current)
2365
				{
2366
					$current_data = '';
2367
					continue;
2368
				}
2369
2370
				$current_data = strtr(substr(rtrim($current_data), 0, -1), array('{$db_prefix}' => $db_prefix, '{$boarddir}' => $boarddir, '{$sboarddir}' => addslashes($boarddir), '{$boardurl}' => $boardurl, '{$db_collation}' => $db_collation));
2371
2372
				upgrade_query($current_data);
2373
2374
				// @todo This will be how it kinda does it once mysql all stripped out - needed for postgre (etc).
2375
				/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
2376
				$result = $smcFunc['db_query']('', $current_data, false, false);
2377
				// Went wrong?
2378
				if (!$result)
2379
				{
2380
					// Bit of a bodge - do we want the error?
2381
					if (!empty($upcontext['return_error']))
2382
					{
2383
						$upcontext['error_message'] = $smcFunc['db_error']($db_connection);
2384
						return false;
2385
					}
2386
				}*/
2387
				$done_something = true;
2388
			}
2389
			$current_data = '';
2390
		}
2391
		// If this is xml based and we're just getting the item name then that's grand.
2392
		elseif ($support_js && !isset($_GET['xml']) && $upcontext['current_debug_item_name'] != '' && $do_current)
2393
		{
2394
			restore_error_handler();
2395
			return false;
2396
		}
2397
2398
		// Clean up by cleaning any step info.
2399
		$step_progress = array();
2400
		$custom_warning = '';
2401
	}
2402
2403
	// Put back the error handler.
2404
	restore_error_handler();
2405
2406
	if ($command_line)
2407
	{
2408
		echo ' Successful.' . "\n";
2409
		flush();
2410
	}
2411
2412
	$_GET['substep'] = 0;
2413
	return true;
2414
}
2415
2416
function upgrade_query($string, $unbuffered = false)
2417
{
2418
	global $db_connection, $db_server, $db_user, $db_passwd, $db_type, $command_line, $upcontext, $upgradeurl, $modSettings;
2419
	global $db_name, $db_unbuffered, $smcFunc;
2420
2421
	// Get the query result - working around some SMF specific security - just this once!
2422
	$modSettings['disableQueryCheck'] = true;
2423
	$db_unbuffered = $unbuffered;
2424
	$result = $smcFunc['db_query']('', $string, array('security_override' => true, 'db_error_skip' => true));
2425
	$db_unbuffered = false;
2426
2427
	// Failure?!
2428
	if ($result !== false)
2429
		return $result;
2430
2431
	$db_error_message = $smcFunc['db_error']($db_connection);
2432
	// If MySQL we do something more clever.
2433
	if ($db_type == 'mysql' || $db_type == 'mysqli')
2434
	{
2435
		$mysql_errno = ($db_type == 'mysqli') ? mysqli_errno($db_connection) : mysql_errno($db_connection);
2436
		$error_query = in_array(substr(trim($string), 0, 11), array('INSERT INTO', 'UPDATE IGNO', 'ALTER TABLE', 'DROP TABLE ', 'ALTER IGNOR'));
2437
2438
		// Error numbers:
2439
		//    1016: Can't open file '....MYI'
2440
		//    1050: Table already exists.
2441
		//    1054: Unknown column name.
2442
		//    1060: Duplicate column name.
2443
		//    1061: Duplicate key name.
2444
		//    1062: Duplicate entry for unique key.
2445
		//    1068: Multiple primary keys.
2446
		//    1072: Key column '%s' doesn't exist in table.
2447
		//    1091: Can't drop key, doesn't exist.
2448
		//    1146: Table doesn't exist.
2449
		//    2013: Lost connection to server during query.
2450
2451
		if ($mysql_errno == 1016)
2452
		{
2453
			if (preg_match('~\'([^\.\']+)~', $db_error_message, $match) != 0 && !empty($match[1]))
2454
			{
2455
				if ($db_type == 'mysql')
2456
				{
2457
					mysql_query('REPAIR TABLE `' . $match[1] . '`');
2458
					$result = mysql_query($string);
2459
				}
2460
				else
2461
				{
2462
					mysqli_query($db_connection, 'REPAIR TABLE `' . $match[1] . '`');
2463
					$result = mysqli_query($db_connection, $string);
2464
				}
2465
				if ($result !== false)
2466
					return $result;
2467
			}
2468
		}
2469
		elseif ($mysql_errno == 2013)
2470
		{
2471
			$db_connection = mysql_connect($db_server, $db_user, $db_passwd);
2472
			if ($db_type == 'mysql')
2473
			{
2474
				mysql_select_db($db_name, $db_connection);
2475
				if ($db_connection)
2476
				{
2477
					$result = mysql_query($string);
2478
					if ($result !== false)
2479
						return $result;
2480
				}
2481
			}
2482
			else
2483
			{
2484
				mysqli_select_db($db_connection, $db_name);
2485
				if ($db_connection)
2486
				{
2487
					$result = mysqli_query($db_connection, $string);
2488
					if ($result !== false)
2489
						return $result;
2490
				}
2491
			}
2492
		}
2493
		// Duplicate column name... should be okay ;).
2494 View Code Duplication
		elseif (in_array($mysql_errno, array(1060, 1061, 1068, 1091)))
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...
2495
			return false;
2496
		// Duplicate insert... make sure it's the proper type of query ;).
2497 View Code Duplication
		elseif (in_array($mysql_errno, array(1054, 1062, 1146)) && $error_query)
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...
2498
			return false;
2499
		// Creating an index on a non-existent column.
2500
		elseif ($mysql_errno == 1072)
2501
			return false;
2502
		elseif ($mysql_errno == 1050 && substr(trim($string), 0, 12) == 'RENAME TABLE')
2503
			return false;
2504
	}
2505
	// If a table already exists don't go potty.
2506
	else
2507
	{
2508
		if (in_array(substr(trim($string), 0, 8), array('CREATE T', 'CREATE S', 'DROP TABL', 'ALTER TA', 'CREATE I', 'CREATE U')))
2509
		{
2510
			if (strpos($db_error_message, 'exist') !== false)
2511
				return true;
2512
		}
2513
		elseif (strpos(trim($string), 'INSERT ') !== false)
2514
		{
2515
			if (strpos($db_error_message, 'duplicate') !== false)
2516
				return true;
2517
		}
2518
	}
2519
2520
	// Get the query string so we pass everything.
2521
	$query_string = '';
2522
	foreach ($_GET as $k => $v)
2523
		$query_string .= ';' . $k . '=' . $v;
2524
	if (strlen($query_string) != 0)
2525
		$query_string = '?' . substr($query_string, 1);
2526
2527
	if ($command_line)
2528
	{
2529
		echo 'Unsuccessful!  Database error message:', "\n", $db_error_message, "\n";
2530
		die;
2531
	}
2532
2533
	// Bit of a bodge - do we want the error?
2534
	if (!empty($upcontext['return_error']))
2535
	{
2536
		$upcontext['error_message'] = $db_error_message;
2537
		$upcontext['error_string'] = $string;
2538
		return false;
2539
	}
2540
2541
	// Otherwise we have to display this somewhere appropriate if possible.
2542
	$upcontext['forced_error_message'] = '
2543
			<strong>Unsuccessful!</strong><br>
2544
2545
			<div style="margin: 2ex;">
2546
				This query:
2547
				<blockquote><pre>' . nl2br(htmlspecialchars(trim($string))) . ';</pre></blockquote>
2548
2549
				Caused the error:
2550
				<blockquote>' . nl2br(htmlspecialchars($db_error_message)) . '</blockquote>
2551
			</div>
2552
2553
			<form action="' . $upgradeurl . $query_string . '" method="post">
2554
				<input type="submit" value="Try again" class="button_submit">
2555
			</form>
2556
		</div>';
2557
2558
	upgradeExit();
2559
}
2560
2561
function smf_mysql_fetch_assoc($rs)
2562
{
2563
	global $db_type;
2564
	return ($db_type == 'mysql') ? mysql_fetch_assoc($rs) : mysqli_fetch_assoc($rs);
2565
}
2566
2567
function smf_mysql_fetch_row($rs)
2568
{
2569
	global $db_type;
2570
	return ($db_type == 'mysql') ? mysql_fetch_row($rs) : mysqli_fetch_row($rs);
2571
}
2572
2573
function smf_mysql_free_result($rs)
2574
{
2575
	global $db_type;
2576
	return ($db_type == 'mysql') ? mysql_free_result($rs) : mysqli_free_result($rs);
2577
}
2578
2579
function smf_mysql_insert_id($rs)
2580
{
2581
	global $db_type;
2582
	return ($db_type == 'mysql') ? mysql_insert_id($rs) : mysqli_insert_id($rs);
2583
}
2584
2585
function smf_mysql_num_rows($rs)
2586
{
2587
	global $db_type;
2588
	return ($db_type == 'mysql') ? mysql_num_rows($rs) : mysqli_num_rows($rs);
2589
}
2590
2591
function smf_mysql_real_escape_string($string)
2592
{
2593
	global $db_type, $db_connection;
2594
	return ($db_type == 'mysql') ? mysql_real_escape_string($string, $db_connection) : mysqli_real_escape_string($db_connection, $string);
2595
}
2596
2597
// This performs a table alter, but does it unbuffered so the script can time out professionally.
2598
function protected_alter($change, $substep, $is_test = false)
2599
{
2600
	global $db_prefix, $smcFunc;
2601
2602
	db_extend('packages');
2603
2604
	// Firstly, check whether the current index/column exists.
2605
	$found = false;
2606
	if ($change['type'] === 'column')
2607
	{
2608
		$columns = $smcFunc['db_list_columns']('{db_prefix}' . $change['table'], true);
2609
		foreach ($columns as $column)
2610
		{
2611
			// Found it?
2612
			if ($column['name'] === $change['name'])
2613
			{
2614
				$found |= 1;
2615
				// Do some checks on the data if we have it set.
2616
				if (isset($change['col_type']))
2617
					$found &= $change['col_type'] === $column['type'];
2618
				if (isset($change['null_allowed']))
2619
					$found &= $column['null'] == $change['null_allowed'];
2620
				if (isset($change['default']))
2621
					$found &= $change['default'] === $column['default'];
2622
			}
2623
		}
2624
	}
2625
	elseif ($change['type'] === 'index')
2626
	{
2627
		$request = upgrade_query( '
2628
			SHOW INDEX
2629
			FROM ' . $db_prefix . $change['table']);
2630
		if ($request !== false)
2631
		{
2632
			$cur_index = array();
2633
2634
			while ($row = $smcFunc['db_fetch_assoc']($request))
2635
				if ($row['Key_name'] === $change['name'])
2636
					$cur_index[(int) $row['Seq_in_index']] = $row['Column_name'];
2637
2638
			ksort($cur_index, SORT_NUMERIC);
2639
			$found = array_values($cur_index) === $change['target_columns'];
2640
2641
			$smcFunc['db_free_result']($request);
2642
		}
2643
	}
2644
2645
	// If we're trying to add and it's added, we're done.
2646
	if ($found && in_array($change['method'], array('add', 'change')))
2647
		return true;
2648
	// Otherwise if we're removing and it wasn't found we're also done.
2649
	elseif (!$found && in_array($change['method'], array('remove', 'change_remove')))
2650
		return true;
2651
	// Otherwise is it just a test?
2652
	elseif ($is_test)
2653
		return false;
2654
2655
	// Not found it yet? Bummer! How about we see if we're currently doing it?
2656
	$running = false;
2657
	$found = false;
2658
	while (1 == 1)
2659
	{
2660
		$request = upgrade_query('
2661
			SHOW FULL PROCESSLIST');
2662
		while ($row = $smcFunc['db_fetch_assoc']($request))
2663
		{
2664
			if (strpos($row['Info'], 'ALTER TABLE ' . $db_prefix . $change['table']) !== false && strpos($row['Info'], $change['text']) !== false)
2665
				$found = true;
2666
		}
2667
2668
		// Can't find it? Then we need to run it fools!
2669
		if (!$found && !$running)
2670
		{
2671
			$smcFunc['db_free_result']($request);
2672
2673
			$success = upgrade_query('
2674
				ALTER TABLE ' . $db_prefix . $change['table'] . '
2675
				' . $change['text'], true) !== false;
2676
2677
			if (!$success)
2678
				return false;
2679
2680
			// Return
2681
			$running = true;
2682
		}
2683
		// What if we've not found it, but we'd ran it already? Must of completed.
2684
		elseif (!$found)
2685
		{
2686
			$smcFunc['db_free_result']($request);
2687
			return true;
2688
		}
2689
2690
		// Pause execution for a sec or three.
2691
		sleep(3);
2692
2693
		// Can never be too well protected.
2694
		nextSubstep($substep);
2695
	}
2696
2697
	// Protect it.
2698
	nextSubstep($substep);
2699
}
2700
2701
// Alter a text column definition preserving its character set.
2702
function textfield_alter($change, $substep)
2703
{
2704
	global $db_prefix, $databases, $db_type, $smcFunc;
2705
2706
	// Versions of MySQL < 4.1 wouldn't benefit from character set detection.
2707
	if (empty($databases[$db_type]['utf8_support']) || version_compare($databases[$db_type]['utf8_version'], eval($databases[$db_type]['utf8_version_check']), '>'))
0 ignored issues
show
Coding Style introduced by
The function textfield_alter() contains an eval expression.

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

Loading history...
2708
	{
2709
		$column_fix = true;
2710
		$null_fix = !$change['null_allowed'];
2711
	}
2712
	else
2713
	{
2714
		$request = $smcFunc['db_query']('', '
2715
			SHOW FULL COLUMNS
2716
			FROM {db_prefix}' . $change['table'] . '
2717
			LIKE {string:column}',
2718
			array(
2719
				'column' => $change['column'],
2720
				'db_error_skip' => true,
2721
			)
2722
		);
2723
		if ($smcFunc['db_num_rows']($request) === 0)
2724
			die('Unable to find column ' . $change['column'] . ' inside table ' . $db_prefix . $change['table']);
2725
		$table_row = $smcFunc['db_fetch_assoc']($request);
2726
		$smcFunc['db_free_result']($request);
2727
2728
		// If something of the current column definition is different, fix it.
2729
		$column_fix = $table_row['Type'] !== $change['type'] || (strtolower($table_row['Null']) === 'yes') !== $change['null_allowed'] || ($table_row['Default'] === null) !== !isset($change['default']) || (isset($change['default']) && $change['default'] !== $table_row['Default']);
2730
2731
		// Columns that previously allowed null, need to be converted first.
2732
		$null_fix = strtolower($table_row['Null']) === 'yes' && !$change['null_allowed'];
2733
2734
		// Get the character set that goes with the collation of the column.
2735 View Code Duplication
		if ($column_fix && !empty($table_row['Collation']))
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...
2736
		{
2737
			$request = $smcFunc['db_query']('', '
2738
				SHOW COLLATION
2739
				LIKE {string:collation}',
2740
				array(
2741
					'collation' => $table_row['Collation'],
2742
					'db_error_skip' => true,
2743
				)
2744
			);
2745
			// No results? Just forget it all together.
2746
			if ($smcFunc['db_num_rows']($request) === 0)
2747
				unset($table_row['Collation']);
2748
			else
2749
				$collation_info = $smcFunc['db_fetch_assoc']($request);
2750
			$smcFunc['db_free_result']($request);
2751
		}
2752
	}
2753
2754
	if ($column_fix)
2755
	{
2756
		// Make sure there are no NULL's left.
2757
		if ($null_fix)
2758
			$smcFunc['db_query']('', '
2759
				UPDATE {db_prefix}' . $change['table'] . '
2760
				SET ' . $change['column'] . ' = {string:default}
2761
				WHERE ' . $change['column'] . ' IS NULL',
2762
				array(
2763
					'default' => isset($change['default']) ? $change['default'] : '',
2764
					'db_error_skip' => true,
2765
				)
2766
			);
2767
2768
		// Do the actual alteration.
2769
		$smcFunc['db_query']('', '
2770
			ALTER TABLE {db_prefix}' . $change['table'] . '
2771
			CHANGE COLUMN ' . $change['column'] . ' ' . $change['column'] . ' ' . $change['type'] . (isset($collation_info['Charset']) ? ' CHARACTER SET ' . $collation_info['Charset'] . ' COLLATE ' . $collation_info['Collation'] : '') . ($change['null_allowed'] ? '' : ' NOT NULL') . (isset($change['default']) ? ' default {string:default}' : ''),
2772
			array(
2773
				'default' => isset($change['default']) ? $change['default'] : '',
2774
				'db_error_skip' => true,
2775
			)
2776
		);
2777
	}
2778
	nextSubstep($substep);
2779
}
2780
2781
// Check if we need to alter this query.
2782
function checkChange(&$change)
2783
{
2784
	global $smcFunc, $db_type, $databases;
2785
	static $database_version, $where_field_support;
2786
2787
	// Attempt to find a database_version.
2788
	if (empty($database_version))
2789
	{
2790
		$database_version = $databases[$db_type]['version_check'];
2791
		$where_field_support = ($db_type == 'mysql' || $db_type == 'mysqli') && version_compare('5.0', $database_version, '<=');
2792
	}
2793
2794
	// Not a column we need to check on?
2795
	if (!in_array($change['name'], array('memberGroups', 'passwordSalt')))
2796
		return;
2797
2798
	// Break it up you (six|seven).
2799
	$temp = explode(' ', str_replace('NOT NULL', 'NOT_NULL', $change['text']));
2800
2801
	// Can we support a shortcut method?
2802
	if ($where_field_support)
2803
	{
2804
		// Get the details about this change.
2805
		$request = $smcFunc['db_query']('', '
2806
			SHOW FIELDS
2807
			FROM {db_prefix}{raw:table}
2808
			WHERE Field = {string:old_name} OR Field = {string:new_name}',
2809
			array(
2810
				'table' => $change['table'],
2811
				'old_name' => $temp[1],
2812
				'new_name' => $temp[2],
2813
		));
2814
		// !!! This doesn't technically work because we don't pass request into it, but it hasn't broke anything yet.
2815
		if ($smcFunc['db_num_rows'] != 1)
2816
			return;
2817
2818
		list (, $current_type) = $smcFunc['db_fetch_assoc']($request);
2819
		$smcFunc['db_free_result']($request);
2820
	}
2821
	else
2822
	{
2823
		// Do this the old fashion, sure method way.
2824
		$request = $smcFunc['db_query']('', '
2825
			SHOW FIELDS
2826
			FROM {db_prefix}{raw:table}',
2827
			array(
2828
				'table' => $change['table'],
2829
		));
2830
		// Mayday!
2831
		// !!! This doesn't technically work because we don't pass request into it, but it hasn't broke anything yet.
2832
		if ($smcFunc['db_num_rows'] == 0)
2833
			return;
2834
2835
		// Oh where, oh where has my little field gone. Oh where can it be...
2836
		while ($row = $smcFunc['db_query']($request))
2837
			if ($row['Field'] == $temp[1] || $row['Field'] == $temp[2])
2838
			{
2839
				$current_type = $row['Type'];
2840
				break;
2841
			}
2842
	}
2843
2844
	// If this doesn't match, the column may of been altered for a reason.
2845
	if (trim($current_type) != trim($temp[3]))
2846
		$temp[3] = $current_type;
0 ignored issues
show
Bug introduced by
The variable $current_type 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...
2847
2848
	// Piece this back together.
2849
	$change['text'] = str_replace('NOT_NULL', 'NOT NULL', implode(' ', $temp));
2850
}
2851
2852
// The next substep.
2853
function nextSubstep($substep)
2854
{
2855
	global $start_time, $timeLimitThreshold, $command_line, $custom_warning;
2856
	global $step_progress, $is_debug, $upcontext;
2857
2858
	if ($_GET['substep'] < $substep)
2859
		$_GET['substep'] = $substep;
2860
2861
	if ($command_line)
2862
	{
2863
		if (time() - $start_time > 1 && empty($is_debug))
2864
		{
2865
			echo '.';
2866
			$start_time = time();
2867
		}
2868
		return;
2869
	}
2870
2871
	@set_time_limit(300);
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...
2872
	if (function_exists('apache_reset_timeout'))
2873
		@apache_reset_timeout();
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...
2874
2875
	if (time() - $start_time <= $timeLimitThreshold)
2876
		return;
2877
2878
	// Do we have some custom step progress stuff?
2879
	if (!empty($step_progress))
2880
	{
2881
		$upcontext['substep_progress'] = 0;
2882
		$upcontext['substep_progress_name'] = $step_progress['name'];
2883
		if ($step_progress['current'] > $step_progress['total'])
2884
			$upcontext['substep_progress'] = 99.9;
2885
		else
2886
			$upcontext['substep_progress'] = ($step_progress['current'] / $step_progress['total']) * 100;
2887
2888
		// Make it nicely rounded.
2889
		$upcontext['substep_progress'] = round($upcontext['substep_progress'], 1);
2890
	}
2891
2892
	// If this is XML we just exit right away!
2893
	if (isset($_GET['xml']))
2894
		return upgradeExit();
2895
2896
	// We're going to pause after this!
2897
	$upcontext['pause'] = true;
2898
2899
	$upcontext['query_string'] = '';
2900
	foreach ($_GET as $k => $v)
2901
	{
2902
		if ($k != 'data' && $k != 'substep' && $k != 'step')
2903
			$upcontext['query_string'] .= ';' . $k . '=' . $v;
2904
	}
2905
2906
	// Custom warning?
2907
	if (!empty($custom_warning))
2908
		$upcontext['custom_warning'] = $custom_warning;
2909
2910
	upgradeExit();
2911
}
2912
2913
function cmdStep0()
2914
{
2915
	global $boarddir, $sourcedir, $language, $modSettings, $start_time, $cachedir, $databases, $db_type, $smcFunc, $upcontext;
2916
	global $language, $is_debug;
2917
	$start_time = time();
2918
2919
	ob_end_clean();
2920
	ob_implicit_flush(true);
2921
	@set_time_limit(600);
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...
2922
2923
	if (!isset($_SERVER['argv']))
2924
		$_SERVER['argv'] = array();
2925
	$_GET['maint'] = 1;
2926
2927
	foreach ($_SERVER['argv'] as $i => $arg)
2928
	{
2929
		if (preg_match('~^--language=(.+)$~', $arg, $match) != 0)
2930
			$_GET['lang'] = $match[1];
2931
		elseif (preg_match('~^--path=(.+)$~', $arg) != 0)
2932
			continue;
2933
		elseif ($arg == '--no-maintenance')
2934
			$_GET['maint'] = 0;
2935
		elseif ($arg == '--debug')
2936
			$is_debug = true;
2937
		elseif ($arg == '--backup')
2938
			$_POST['backup'] = 1;
2939
		elseif ($arg == '--template' && (file_exists($boarddir . '/template.php') || file_exists($boarddir . '/template.html') && !file_exists($modSettings['theme_dir'] . '/converted')))
2940
			$_GET['conv'] = 1;
2941
		elseif ($i != 0)
2942
		{
2943
			echo 'SMF Command-line Upgrader
2944
Usage: /path/to/php -f ' . basename(__FILE__) . ' -- [OPTION]...
2945
2946
    --language=LANG         Reset the forum\'s language to LANG.
2947
    --no-maintenance        Don\'t put the forum into maintenance mode.
2948
    --debug                 Output debugging information.
2949
    --backup                Create backups of tables with "backup_" prefix.';
2950
			echo "\n";
2951
			exit;
2952
		}
2953
	}
2954
2955
	if (!php_version_check())
2956
		print_error('Error: PHP ' . PHP_VERSION . ' does not match version requirements.', true);
2957
	if (!db_version_check())
2958
		print_error('Error: ' . $databases[$db_type]['name'] . ' ' . $databases[$db_type]['version'] . ' does not match minimum requirements.', true);
2959
2960
	// Do some checks to make sure they have proper privileges
2961
	db_extend('packages');
2962
2963
	// CREATE
2964
	$create = $smcFunc['db_create_table']('{db_prefix}priv_check', array(array('name' => 'id_test', 'type' => 'int', 'size' => 10, 'unsigned' => true, 'auto' => true)), array(array('columns' => array('id_test'), 'primary' => true)), array(), 'overwrite');
2965
2966
	// ALTER
2967
	$alter = $smcFunc['db_add_column']('{db_prefix}priv_check', array('name' => 'txt', 'type' => 'tinytext', 'null' => false, 'default' => ''));
2968
2969
	// DROP
2970
	$drop = $smcFunc['db_drop_table']('{db_prefix}priv_check');
2971
2972
	// Sorry... we need CREATE, ALTER and DROP
2973 View Code Duplication
	if (!$create || !$alter || !$drop)
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...
2974
		print_error("The " . $databases[$db_type]['name'] . " user you have set in Settings.php does not have proper privileges.\n\nPlease ask your host to give this user the ALTER, CREATE, and DROP privileges.", true);
2975
2976
	$check = @file_exists($modSettings['theme_dir'] . '/index.template.php')
2977
		&& @file_exists($sourcedir . '/QueryString.php')
2978
		&& @file_exists($sourcedir . '/ManageBoards.php');
2979
	if (!$check && !isset($modSettings['smfVersion']))
2980
		print_error('Error: Some files are missing or out-of-date.', true);
2981
2982
	// Do a quick version spot check.
2983
	$temp = substr(@implode('', @file($boarddir . '/index.php')), 0, 4096);
2984
	preg_match('~\*\s@version\s+(.+)[\s]{2}~i', $temp, $match);
2985
	if (empty($match[1]) || (trim($match[1]) != SMF_VERSION))
2986
		print_error('Error: Some files have not yet been updated properly.');
2987
2988
	// Make sure Settings.php is writable.
2989
		quickFileWritable($boarddir . '/Settings.php');
2990
	if (!is_writable($boarddir . '/Settings.php'))
2991
		print_error('Error: Unable to obtain write access to "Settings.php".', true);
2992
2993
	// Make sure Settings_bak.php is writable.
2994
		quickFileWritable($boarddir . '/Settings_bak.php');
2995
	if (!is_writable($boarddir . '/Settings_bak.php'))
2996
		print_error('Error: Unable to obtain write access to "Settings_bak.php".');
2997
2998 View Code Duplication
	if (isset($modSettings['agreement']) && (!is_writable($boarddir) || file_exists($boarddir . '/agreement.txt')) && !is_writable($boarddir . '/agreement.txt'))
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...
2999
		print_error('Error: Unable to obtain write access to "agreement.txt".');
3000
	elseif (isset($modSettings['agreement']))
3001
	{
3002
		$fp = fopen($boarddir . '/agreement.txt', 'w');
3003
		fwrite($fp, $modSettings['agreement']);
3004
		fclose($fp);
3005
	}
3006
3007
	// Make sure Themes is writable.
3008
	quickFileWritable($modSettings['theme_dir']);
3009
3010
	if (!is_writable($modSettings['theme_dir']) && !isset($modSettings['smfVersion']))
3011
		print_error('Error: Unable to obtain write access to "Themes".');
3012
3013
	// Make sure cache directory exists and is writable!
3014
	$cachedir_temp = empty($cachedir) ? $boarddir . '/cache' : $cachedir;
3015
	if (!file_exists($cachedir_temp))
3016
		@mkdir($cachedir_temp);
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...
3017
3018
	// Make sure the cache temp dir is writable.
3019
	quickFileWritable($cachedir_temp);
3020
3021
	if (!is_writable($cachedir_temp))
3022
		print_error('Error: Unable to obtain write access to "cache".', true);
3023
3024
	if (!file_exists($modSettings['theme_dir'] . '/languages/index.' . $upcontext['language'] . '.php') && !isset($modSettings['smfVersion']) && !isset($_GET['lang']))
3025
		print_error('Error: Unable to find language files!', true);
3026
	else
3027
	{
3028
		$temp = substr(@implode('', @file($modSettings['theme_dir'] . '/languages/index.' . $upcontext['language'] . '.php')), 0, 4096);
3029
		preg_match('~(?://|/\*)\s*Version:\s+(.+?);\s*index(?:[\s]{2}|\*/)~i', $temp, $match);
3030
3031
		if (empty($match[1]) || $match[1] != SMF_LANG_VERSION)
3032
			print_error('Error: Language files out of date.', true);
3033
		if (!file_exists($modSettings['theme_dir'] . '/languages/Install.' . $upcontext['language'] . '.php'))
3034
			print_error('Error: Install language is missing for selected language.', true);
3035
3036
		// Otherwise include it!
3037
		require_once($modSettings['theme_dir'] . '/languages/Install.' . $upcontext['language'] . '.php');
3038
	}
3039
3040
	// Make sure we skip the HTML for login.
3041
	$_POST['upcont'] = true;
3042
	$upcontext['current_step'] = 1;
3043
}
3044
3045
function print_error($message, $fatal = false)
3046
{
3047
	static $fp = null;
3048
3049
	if ($fp === null)
3050
		$fp = fopen('php://stderr', 'wb');
3051
3052
	fwrite($fp, $message . "\n");
3053
3054
	if ($fatal)
3055
		exit;
3056
}
3057
3058
function throw_error($message)
3059
{
3060
	global $upcontext;
3061
3062
	$upcontext['error_msg'] = $message;
3063
	$upcontext['sub_template'] = 'error_message';
3064
3065
	return false;
3066
}
3067
3068
// Check files are writable - make them writable if necessary...
3069
function makeFilesWritable(&$files)
3070
{
3071
	global $upcontext, $boarddir;
3072
3073
	if (empty($files))
3074
		return true;
3075
3076
	$failure = false;
3077
	// On linux, it's easy - just use is_writable!
3078
	if (substr(__FILE__, 1, 2) != ':\\')
3079
	{
3080
		$upcontext['systemos'] = 'linux';
3081
3082
		foreach ($files as $k => $file)
3083
		{
3084
			if (!is_writable($file))
3085
			{
3086
				@chmod($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...
3087
3088
				// Well, 755 hopefully worked... if not, try 777.
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
3089
				if (!is_writable($file) && !@chmod($file, 0777))
3090
					$failure = true;
3091
				// Otherwise remove it as it's good!
3092
				else
3093
					unset($files[$k]);
3094
			}
3095
			else
3096
				unset($files[$k]);
3097
		}
3098
	}
3099
	// Windows is trickier.  Let's try opening for r+...
3100
	else
3101
	{
3102
		$upcontext['systemos'] = 'windows';
3103
3104
		foreach ($files as $k => $file)
3105
		{
3106
			// Folders can't be opened for write... but the index.php in them can ;).
3107
			if (is_dir($file))
3108
				$file .= '/index.php';
3109
3110
			// Funny enough, chmod actually does do something on windows - it removes the read only attribute.
3111
			@chmod($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...
3112
			$fp = @fopen($file, 'r+');
3113
3114
			// Hmm, okay, try just for write in that case...
3115
			if (!$fp)
3116
				$fp = @fopen($file, 'w');
3117
3118
			if (!$fp)
3119
				$failure = true;
3120
			else
3121
				unset($files[$k]);
3122
			@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...
3123
		}
3124
	}
3125
3126
	if (empty($files))
3127
		return true;
3128
3129
	if (!isset($_SERVER))
3130
		return !$failure;
3131
3132
	// What still needs to be done?
3133
	$upcontext['chmod']['files'] = $files;
3134
3135
	// If it's windows it's a mess...
3136
	if ($failure && substr(__FILE__, 1, 2) == ':\\')
3137
	{
3138
		$upcontext['chmod']['ftp_error'] = 'total_mess';
3139
3140
		return false;
3141
	}
3142
	// We're going to have to use... FTP!
3143
	elseif ($failure)
3144
	{
3145
		// Load any session data we might have...
3146
		if (!isset($_POST['ftp_username']) && isset($_SESSION['installer_temp_ftp']))
3147
		{
3148
			$upcontext['chmod']['server'] = $_SESSION['installer_temp_ftp']['server'];
3149
			$upcontext['chmod']['port'] = $_SESSION['installer_temp_ftp']['port'];
3150
			$upcontext['chmod']['username'] = $_SESSION['installer_temp_ftp']['username'];
3151
			$upcontext['chmod']['password'] = $_SESSION['installer_temp_ftp']['password'];
3152
			$upcontext['chmod']['path'] = $_SESSION['installer_temp_ftp']['path'];
3153
		}
3154
		// Or have we submitted?
3155 View Code Duplication
		elseif (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...
3156
		{
3157
			$upcontext['chmod']['server'] = $_POST['ftp_server'];
3158
			$upcontext['chmod']['port'] = $_POST['ftp_port'];
3159
			$upcontext['chmod']['username'] = $_POST['ftp_username'];
3160
			$upcontext['chmod']['password'] = $_POST['ftp_password'];
3161
			$upcontext['chmod']['path'] = $_POST['ftp_path'];
3162
		}
3163
3164
		if (isset($upcontext['chmod']['username']))
3165
		{
3166
			$ftp = new ftp_connection($upcontext['chmod']['server'], $upcontext['chmod']['port'], $upcontext['chmod']['username'], $upcontext['chmod']['password']);
3167
3168
			if ($ftp->error === false)
3169
			{
3170
				// Try it without /home/abc just in case they messed up.
3171
				if (!$ftp->chdir($upcontext['chmod']['path']))
3172
				{
3173
					$upcontext['chmod']['ftp_error'] = $ftp->last_message;
3174
					$ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $upcontext['chmod']['path']));
3175
				}
3176
			}
3177
		}
3178
3179
		if (!isset($ftp) || $ftp->error !== false)
3180
		{
3181
			if (!isset($ftp))
3182
				$ftp = new ftp_connection(null);
3183
			// Save the error so we can mess with listing...
3184
			elseif ($ftp->error !== false && !isset($upcontext['chmod']['ftp_error']))
3185
				$upcontext['chmod']['ftp_error'] = $ftp->last_message === null ? '' : $ftp->last_message;
3186
3187
			list ($username, $detect_path, $found_path) = $ftp->detect_path(dirname(__FILE__));
3188
3189
			if ($found_path || !isset($upcontext['chmod']['path']))
3190
				$upcontext['chmod']['path'] = $detect_path;
3191
3192
			if (!isset($upcontext['chmod']['username']))
3193
				$upcontext['chmod']['username'] = $username;
3194
3195
			// Don't forget the login token.
3196
			$upcontext += createToken('login');
3197
3198
			return false;
3199
		}
3200
		else
3201
		{
3202
			// We want to do a relative path for FTP.
3203
			if (!in_array($upcontext['chmod']['path'], array('', '/')))
3204
			{
3205
				$ftp_root = strtr($boarddir, array($upcontext['chmod']['path'] => ''));
3206
				if (substr($ftp_root, -1) == '/' && ($upcontext['chmod']['path'] == '' || $upcontext['chmod']['path'][0] === '/'))
3207
				$ftp_root = substr($ftp_root, 0, -1);
3208
			}
3209
			else
3210
				$ftp_root = $boarddir;
3211
3212
			// Save the info for next time!
3213
			$_SESSION['installer_temp_ftp'] = array(
3214
				'server' => $upcontext['chmod']['server'],
3215
				'port' => $upcontext['chmod']['port'],
3216
				'username' => $upcontext['chmod']['username'],
3217
				'password' => $upcontext['chmod']['password'],
3218
				'path' => $upcontext['chmod']['path'],
3219
				'root' => $ftp_root,
3220
			);
3221
3222
			foreach ($files as $k => $file)
3223
			{
3224
				if (!is_writable($file))
3225
					$ftp->chmod($file, 0755);
3226
				if (!is_writable($file))
3227
					$ftp->chmod($file, 0777);
3228
3229
				// Assuming that didn't work calculate the path without the boarddir.
3230
				if (!is_writable($file))
3231
				{
3232
					if (strpos($file, $boarddir) === 0)
3233
					{
3234
						$ftp_file = strtr($file, array($_SESSION['installer_temp_ftp']['root'] => ''));
3235
						$ftp->chmod($ftp_file, 0755);
3236
						if (!is_writable($file))
3237
							$ftp->chmod($ftp_file, 0777);
3238
						// Sometimes an extra slash can help...
3239
						$ftp_file = '/' . $ftp_file;
3240
						if (!is_writable($file))
3241
							$ftp->chmod($ftp_file, 0755);
3242
						if (!is_writable($file))
3243
							$ftp->chmod($ftp_file, 0777);
3244
					}
3245
				}
3246
3247
				if (is_writable($file))
3248
					unset($files[$k]);
3249
			}
3250
3251
			$ftp->close();
3252
		}
3253
	}
3254
3255
	// What remains?
3256
	$upcontext['chmod']['files'] = $files;
3257
3258
	if (empty($files))
3259
		return true;
3260
3261
	return false;
3262
}
3263
3264
function quickFileWritable($file)
3265
{
3266
	if (is_writable($file))
3267
		return true;
3268
3269
	@chmod($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...
3270
3271
	// Try 755 and 775 first since 777 doesn't always work and could be a risk...
3272
	$chmod_values = array(0755, 0775, 0777);
3273
3274
	foreach($chmod_values as $val)
3275
	{
3276
		// If it's writable, break out of the loop
3277
		if (is_writable($file))
3278
			break;
3279
		else
3280
			@chmod($file, $val);
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...
3281
	}
3282
}
3283
function smf_strtolower($string)
3284
{
3285
	global $sourcedir;
3286
	if (function_exists('mb_strtolower'))
3287
		return mb_strtolower($string, 'UTF-8');
3288
	require_once($sourcedir . '/Subs-Charset.php');
3289
	return utf8_strtolower($string);
3290
}
3291
3292
/**
3293
 * Handles converting your database to UTF-8
3294
 */
3295
function convertUtf8()
3296
{
3297
	global $upcontext, $db_character_set, $sourcedir, $smcFunc, $modSettings, $language, $db_prefix, $db_type, $command_line, $support_js, $is_debug;
3298
3299
	// First make sure they aren't already on UTF-8 before we go anywhere...
3300
	if ($db_type == 'postgresql' || ($db_character_set === 'utf8' && !empty($modSettings['global_character_set']) && $modSettings['global_character_set'] === 'UTF-8'))
3301
	{
3302
		return true;
3303
	}
3304
	else
3305
	{
3306
		$upcontext['page_title'] = 'Converting to UTF8';
3307
		$upcontext['sub_template'] = isset($_GET['xml']) ? 'convert_xml' : 'convert_utf8';
3308
3309
		// The character sets used in SMF's language files with their db equivalent.
3310
		$charsets = array(
3311
			// Armenian
3312
			'armscii8' => 'armscii8',
3313
			// Chinese-traditional.
3314
			'big5' => 'big5',
3315
			// Chinese-simplified.
3316
			'gbk' => 'gbk',
3317
			// West European.
3318
			'ISO-8859-1' => 'latin1',
3319
			// Romanian.
3320
			'ISO-8859-2' => 'latin2',
3321
			// Turkish.
3322
			'ISO-8859-9' => 'latin5',
3323
			// Latvian
3324
			'ISO-8859-13' => 'latin7',
3325
			// West European with Euro sign.
3326
			'ISO-8859-15' => 'latin9',
3327
			// Thai.
3328
			'tis-620' => 'tis620',
3329
			// Persian, Chinese, etc.
3330
			'UTF-8' => 'utf8',
3331
			// Russian.
3332
			'windows-1251' => 'cp1251',
3333
			// Greek.
3334
			'windows-1253' => 'utf8',
3335
			// Hebrew.
3336
			'windows-1255' => 'utf8',
3337
			// Arabic.
3338
			'windows-1256' => 'cp1256',
3339
		);
3340
3341
		// Get a list of character sets supported by your MySQL server.
3342
		$request = $smcFunc['db_query']('', '
3343
			SHOW CHARACTER SET',
3344
			array(
3345
			)
3346
		);
3347
		$db_charsets = array();
3348
		while ($row = $smcFunc['db_fetch_assoc']($request))
3349
			$db_charsets[] = $row['Charset'];
3350
3351
		$smcFunc['db_free_result']($request);
3352
3353
		// Character sets supported by both MySQL and SMF's language files.
3354
		$charsets = array_intersect($charsets, $db_charsets);
3355
3356
		// Use the messages.body column as indicator for the database charset.
3357
		$request = $smcFunc['db_query']('', '
3358
			SHOW FULL COLUMNS
3359
			FROM {db_prefix}messages
3360
			LIKE {string:body_like}',
3361
			array(
3362
				'body_like' => 'body',
3363
			)
3364
		);
3365
		$column_info = $smcFunc['db_fetch_assoc']($request);
3366
		$smcFunc['db_free_result']($request);
3367
3368
		// A collation looks like latin1_swedish. We only need the character set.
3369
		list($upcontext['database_charset']) = explode('_', $column_info['Collation']);
3370
		$upcontext['database_charset'] = in_array($upcontext['database_charset'], $charsets) ? array_search($upcontext['database_charset'], $charsets) : $upcontext['database_charset'];
3371
3372
		// Detect whether a fulltext index is set.
3373
		$request = $smcFunc['db_query']('', '
3374
 			SHOW INDEX
3375
	  	    FROM {db_prefix}messages',
3376
			array(
3377
			)
3378
		);
3379
3380
		$upcontext['dropping_index'] = false;
3381
3382
		// If there's a fulltext index, we need to drop it first...
3383 View Code Duplication
		if ($request !== false || $smcFunc['db_num_rows']($request) != 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...
3384
		{
3385
			while ($row = $smcFunc['db_fetch_assoc']($request))
3386
				if ($row['Column_name'] == 'body' && (isset($row['Index_type']) && $row['Index_type'] == 'FULLTEXT' || isset($row['Comment']) && $row['Comment'] == 'FULLTEXT'))
3387
					$upcontext['fulltext_index'][] = $row['Key_name'];
3388
			$smcFunc['db_free_result']($request);
3389
3390
			if (isset($upcontext['fulltext_index']))
3391
				$upcontext['fulltext_index'] = array_unique($upcontext['fulltext_index']);
3392
		}
3393
3394
		// Drop it and make a note...
3395
		if (!empty($upcontext['fulltext_index']))
3396
		{
3397
			$upcontext['dropping_index'] = true;
3398
3399
			$smcFunc['db_query']('', '
3400
  			ALTER TABLE {db_prefix}messages
3401
	  		DROP INDEX ' . implode(',
3402
		  	DROP INDEX ', $upcontext['fulltext_index']),
3403
				array(
3404
					'db_error_skip' => true,
3405
				)
3406
			);
3407
3408
			// Update the settings table
3409
			$smcFunc['db_insert']('replace',
3410
				'{db_prefix}settings',
3411
				array('variable' => 'string', 'value' => 'string'),
3412
				array('db_search_index', ''),
3413
				array('variable')
3414
			);
3415
		}
3416
3417
		// Figure out what charset we should be converting from...
3418
		$lang_charsets = array(
3419
			'arabic' => 'windows-1256',
3420
			'armenian_east' => 'armscii-8',
3421
			'armenian_west' => 'armscii-8',
3422
			'azerbaijani_latin' => 'ISO-8859-9',
3423
			'bangla' => 'UTF-8',
3424
			'belarusian' => 'ISO-8859-5',
3425
			'bulgarian' => 'windows-1251',
3426
			'cambodian' => 'UTF-8',
3427
			'chinese_simplified' => 'gbk',
3428
			'chinese_traditional' => 'big5',
3429
			'croation' => 'ISO-8859-2',
3430
			'czech' => 'ISO-8859-2',
3431
			'czech_informal' => 'ISO-8859-2',
3432
			'english_pirate' => 'UTF-8',
3433
			'esperanto' => 'ISO-8859-3',
3434
			'estonian' => 'ISO-8859-15',
3435
			'filipino_tagalog' => 'UTF-8',
3436
			'filipino_vasayan' => 'UTF-8',
3437
			'georgian' => 'UTF-8',
3438
			'greek' => 'ISO-8859-3',
3439
			'hebrew' => 'windows-1255',
3440
			'hungarian' => 'ISO-8859-2',
3441
			'irish' => 'UTF-8',
3442
			'japanese' => 'UTF-8',
3443
			'khmer' => 'UTF-8',
3444
			'korean' => 'UTF-8',
3445
			'kurdish_kurmanji' => 'ISO-8859-9',
3446
			'kurdish_sorani' => 'windows-1256',
3447
			'lao' => 'tis-620',
3448
			'latvian' => 'ISO-8859-13',
3449
			'lithuanian' => 'ISO-8859-4',
3450
			'macedonian' => 'UTF-8',
3451
			'malayalam' => 'UTF-8',
3452
			'mongolian' => 'UTF-8',
3453
			'nepali' => 'UTF-8',
3454
			'persian' => 'UTF-8',
3455
			'polish' => 'ISO-8859-2',
3456
			'romanian' => 'ISO-8859-2',
3457
			'russian' => 'windows-1252',
3458
			'sakha' => 'UTF-8',
3459
			'serbian_cyrillic' => 'ISO-8859-5',
3460
			'serbian_latin' => 'ISO-8859-2',
3461
			'sinhala' => 'UTF-8',
3462
			'slovak' => 'ISO-8859-2',
3463
			'slovenian' => 'ISO-8859-2',
3464
			'telugu' => 'UTF-8',
3465
			'thai' => 'tis-620',
3466
			'turkish' => 'ISO-8859-9',
3467
			'turkmen' => 'ISO-8859-9',
3468
			'ukranian' => 'windows-1251',
3469
			'urdu' => 'UTF-8',
3470
			'uzbek_cyrillic' => 'ISO-8859-5',
3471
			'uzbek_latin' => 'ISO-8859-5',
3472
			'vietnamese' => 'UTF-8',
3473
			'yoruba' => 'UTF-8'
3474
		);
3475
3476
		// Default to ISO-8859-1 unless we detected another supported charset
3477
		$upcontext['charset_detected'] = (isset($lang_charsets[$language]) && isset($charsets[strtr(strtolower($upcontext['charset_detected']), array('utf' => 'UTF', 'iso' => 'ISO'))])) ? $lang_charsets[$language] : 'ISO-8859-1';
3478
3479
		$upcontext['charset_list'] = array_keys($charsets);
3480
3481
		// Translation table for the character sets not native for MySQL.
3482
		$translation_tables = array(
3483
			'windows-1255' => array(
3484
				'0x81' => '\'\'',		'0x8A' => '\'\'',		'0x8C' => '\'\'',
3485
				'0x8D' => '\'\'',		'0x8E' => '\'\'',		'0x8F' => '\'\'',
3486
				'0x90' => '\'\'',		'0x9A' => '\'\'',		'0x9C' => '\'\'',
3487
				'0x9D' => '\'\'',		'0x9E' => '\'\'',		'0x9F' => '\'\'',
3488
				'0xCA' => '\'\'',		'0xD9' => '\'\'',		'0xDA' => '\'\'',
3489
				'0xDB' => '\'\'',		'0xDC' => '\'\'',		'0xDD' => '\'\'',
3490
				'0xDE' => '\'\'',		'0xDF' => '\'\'',		'0xFB' => '\'\'',
3491
				'0xFC' => '\'\'',		'0xFF' => '\'\'',		'0xC2' => '0xFF',
3492
				'0x80' => '0xFC',		'0xE2' => '0xFB',		'0xA0' => '0xC2A0',
3493
				'0xA1' => '0xC2A1',		'0xA2' => '0xC2A2',		'0xA3' => '0xC2A3',
3494
				'0xA5' => '0xC2A5',		'0xA6' => '0xC2A6',		'0xA7' => '0xC2A7',
3495
				'0xA8' => '0xC2A8',		'0xA9' => '0xC2A9',		'0xAB' => '0xC2AB',
3496
				'0xAC' => '0xC2AC',		'0xAD' => '0xC2AD',		'0xAE' => '0xC2AE',
3497
				'0xAF' => '0xC2AF',		'0xB0' => '0xC2B0',		'0xB1' => '0xC2B1',
3498
				'0xB2' => '0xC2B2',		'0xB3' => '0xC2B3',		'0xB4' => '0xC2B4',
3499
				'0xB5' => '0xC2B5',		'0xB6' => '0xC2B6',		'0xB7' => '0xC2B7',
3500
				'0xB8' => '0xC2B8',		'0xB9' => '0xC2B9',		'0xBB' => '0xC2BB',
3501
				'0xBC' => '0xC2BC',		'0xBD' => '0xC2BD',		'0xBE' => '0xC2BE',
3502
				'0xBF' => '0xC2BF',		'0xD7' => '0xD7B3',		'0xD1' => '0xD781',
3503
				'0xD4' => '0xD7B0',		'0xD5' => '0xD7B1',		'0xD6' => '0xD7B2',
3504
				'0xE0' => '0xD790',		'0xEA' => '0xD79A',		'0xEC' => '0xD79C',
3505
				'0xED' => '0xD79D',		'0xEE' => '0xD79E',		'0xEF' => '0xD79F',
3506
				'0xF0' => '0xD7A0',		'0xF1' => '0xD7A1',		'0xF2' => '0xD7A2',
3507
				'0xF3' => '0xD7A3',		'0xF5' => '0xD7A5',		'0xF6' => '0xD7A6',
3508
				'0xF7' => '0xD7A7',		'0xF8' => '0xD7A8',		'0xF9' => '0xD7A9',
3509
				'0x82' => '0xE2809A',	'0x84' => '0xE2809E',	'0x85' => '0xE280A6',
3510
				'0x86' => '0xE280A0',	'0x87' => '0xE280A1',	'0x89' => '0xE280B0',
3511
				'0x8B' => '0xE280B9',	'0x93' => '0xE2809C',	'0x94' => '0xE2809D',
3512
				'0x95' => '0xE280A2',	'0x97' => '0xE28094',	'0x99' => '0xE284A2',
3513
				'0xC0' => '0xD6B0',		'0xC1' => '0xD6B1',		'0xC3' => '0xD6B3',
3514
				'0xC4' => '0xD6B4',		'0xC5' => '0xD6B5',		'0xC6' => '0xD6B6',
3515
				'0xC7' => '0xD6B7',		'0xC8' => '0xD6B8',		'0xC9' => '0xD6B9',
3516
				'0xCB' => '0xD6BB',		'0xCC' => '0xD6BC',		'0xCD' => '0xD6BD',
3517
				'0xCE' => '0xD6BE',		'0xCF' => '0xD6BF',		'0xD0' => '0xD780',
3518
				'0xD2' => '0xD782',		'0xE3' => '0xD793',		'0xE4' => '0xD794',
3519
				'0xE5' => '0xD795',		'0xE7' => '0xD797',		'0xE9' => '0xD799',
3520
				'0xFD' => '0xE2808E',	'0xFE' => '0xE2808F',	'0x92' => '0xE28099',
3521
				'0x83' => '0xC692',		'0xD3' => '0xD783',		'0x88' => '0xCB86',
3522
				'0x98' => '0xCB9C',		'0x91' => '0xE28098',	'0x96' => '0xE28093',
3523
				'0xBA' => '0xC3B7',		'0x9B' => '0xE280BA',	'0xAA' => '0xC397',
3524
				'0xA4' => '0xE282AA',	'0xE1' => '0xD791',		'0xE6' => '0xD796',
3525
				'0xE8' => '0xD798',		'0xEB' => '0xD79B',		'0xF4' => '0xD7A4',
3526
				'0xFA' => '0xD7AA',		'0xFF' => '0xD6B2',		'0xFC' => '0xE282AC',
3527
				'0xFB' => '0xD792',
3528
			),
3529
			'windows-1253' => array(
3530
				'0x81' => '\'\'',			'0x88' => '\'\'',			'0x8A' => '\'\'',
3531
				'0x8C' => '\'\'',			'0x8D' => '\'\'',			'0x8E' => '\'\'',
3532
				'0x8F' => '\'\'',			'0x90' => '\'\'',			'0x98' => '\'\'',
3533
				'0x9A' => '\'\'',			'0x9C' => '\'\'',			'0x9D' => '\'\'',
3534
				'0x9E' => '\'\'',			'0x9F' => '\'\'',			'0xAA' => '\'\'',
3535
				'0xD2' => '\'\'',			'0xFF' => '\'\'',			'0xCE' => '0xCE9E',
3536
				'0xB8' => '0xCE88',		'0xBA' => '0xCE8A',		'0xBC' => '0xCE8C',
3537
				'0xBE' => '0xCE8E',		'0xBF' => '0xCE8F',		'0xC0' => '0xCE90',
3538
				'0xC8' => '0xCE98',		'0xCA' => '0xCE9A',		'0xCC' => '0xCE9C',
3539
				'0xCD' => '0xCE9D',		'0xCF' => '0xCE9F',		'0xDA' => '0xCEAA',
3540
				'0xE8' => '0xCEB8',		'0xEA' => '0xCEBA',		'0xEC' => '0xCEBC',
3541
				'0xEE' => '0xCEBE',		'0xEF' => '0xCEBF',		'0xC2' => '0xFF',
3542
				'0xBD' => '0xC2BD',		'0xED' => '0xCEBD',		'0xB2' => '0xC2B2',
3543
				'0xA0' => '0xC2A0',		'0xA3' => '0xC2A3',		'0xA4' => '0xC2A4',
3544
				'0xA5' => '0xC2A5',		'0xA6' => '0xC2A6',		'0xA7' => '0xC2A7',
3545
				'0xA8' => '0xC2A8',		'0xA9' => '0xC2A9',		'0xAB' => '0xC2AB',
3546
				'0xAC' => '0xC2AC',		'0xAD' => '0xC2AD',		'0xAE' => '0xC2AE',
3547
				'0xB0' => '0xC2B0',		'0xB1' => '0xC2B1',		'0xB3' => '0xC2B3',
3548
				'0xB5' => '0xC2B5',		'0xB6' => '0xC2B6',		'0xB7' => '0xC2B7',
3549
				'0xBB' => '0xC2BB',		'0xE2' => '0xCEB2',		'0x80' => '0xD2',
3550
				'0x82' => '0xE2809A',	'0x84' => '0xE2809E',	'0x85' => '0xE280A6',
3551
				'0x86' => '0xE280A0',	'0xA1' => '0xCE85',		'0xA2' => '0xCE86',
3552
				'0x87' => '0xE280A1',	'0x89' => '0xE280B0',	'0xB9' => '0xCE89',
3553
				'0x8B' => '0xE280B9',	'0x91' => '0xE28098',	'0x99' => '0xE284A2',
3554
				'0x92' => '0xE28099',	'0x93' => '0xE2809C',	'0x94' => '0xE2809D',
3555
				'0x95' => '0xE280A2',	'0x96' => '0xE28093',	'0x97' => '0xE28094',
3556
				'0x9B' => '0xE280BA',	'0xAF' => '0xE28095',	'0xB4' => '0xCE84',
3557
				'0xC1' => '0xCE91',		'0xC3' => '0xCE93',		'0xC4' => '0xCE94',
3558
				'0xC5' => '0xCE95',		'0xC6' => '0xCE96',		'0x83' => '0xC692',
3559
				'0xC7' => '0xCE97',		'0xC9' => '0xCE99',		'0xCB' => '0xCE9B',
3560
				'0xD0' => '0xCEA0',		'0xD1' => '0xCEA1',		'0xD3' => '0xCEA3',
3561
				'0xD4' => '0xCEA4',		'0xD5' => '0xCEA5',		'0xD6' => '0xCEA6',
3562
				'0xD7' => '0xCEA7',		'0xD8' => '0xCEA8',		'0xD9' => '0xCEA9',
3563
				'0xDB' => '0xCEAB',		'0xDC' => '0xCEAC',		'0xDD' => '0xCEAD',
3564
				'0xDE' => '0xCEAE',		'0xDF' => '0xCEAF',		'0xE0' => '0xCEB0',
3565
				'0xE1' => '0xCEB1',		'0xE3' => '0xCEB3',		'0xE4' => '0xCEB4',
3566
				'0xE5' => '0xCEB5',		'0xE6' => '0xCEB6',		'0xE7' => '0xCEB7',
3567
				'0xE9' => '0xCEB9',		'0xEB' => '0xCEBB',		'0xF0' => '0xCF80',
3568
				'0xF1' => '0xCF81',		'0xF2' => '0xCF82',		'0xF3' => '0xCF83',
3569
				'0xF4' => '0xCF84',		'0xF5' => '0xCF85',		'0xF6' => '0xCF86',
3570
				'0xF7' => '0xCF87',		'0xF8' => '0xCF88',		'0xF9' => '0xCF89',
3571
				'0xFA' => '0xCF8A',		'0xFB' => '0xCF8B',		'0xFC' => '0xCF8C',
3572
				'0xFD' => '0xCF8D',		'0xFE' => '0xCF8E',		'0xFF' => '0xCE92',
3573
				'0xD2' => '0xE282AC',
3574
			),
3575
		);
3576
3577
		// Make some preparations.
3578
		if (isset($translation_tables[$upcontext['charset_detected']]))
3579
		{
3580
			$replace = '%field%';
3581
3582
			// Build a huge REPLACE statement...
3583
			foreach ($translation_tables[$upcontext['charset_detected']] as $from => $to)
3584
				$replace = 'REPLACE(' . $replace . ', ' . $from . ', ' . $to . ')';
3585
		}
3586
3587
		// Get a list of table names ahead of time... This makes it easier to set our substep and such
3588
		db_extend();
3589
		$queryTables = $smcFunc['db_list_tables'](false, $db_prefix . '%');
3590
3591
		$upcontext['table_count'] = count($queryTables);
3592
		$file_steps = $upcontext['table_count'];
0 ignored issues
show
Unused Code introduced by
$file_steps 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...
3593
3594
		for($substep = $_GET['substep']; $substep < $upcontext['table_count']; $substep++)
3595
		{
3596
			$table = $queryTables[$_GET['substep']];
3597
3598
			// Do we need to pause?
3599
			nextSubstep($substep);
3600
3601
			$getTableStatus = $smcFunc['db_query']('', '
3602
				SHOW TABLE STATUS
3603
				LIKE {string:table_name}',
3604
				array(
3605
					'table_name' => str_replace('_', '\_', $table)
3606
				)
3607
			);
3608
3609
			// Only one row so we can just fetch_assoc and free the result...
3610
			$table_info = $smcFunc['db_fetch_assoc']($getTableStatus);
3611
			$smcFunc['db_free_result']($getTableStatus);
3612
3613
			$upcontext['cur_table_num'] = $_GET['substep'];
3614
			$upcontext['cur_table_name'] = $table_info['Name'];
3615
			$upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100);
3616
3617
			// Just to make sure it doesn't time out.
3618
			if (function_exists('apache_reset_timeout'))
3619
				@apache_reset_timeout();
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...
3620
3621
			$table_charsets = array();
3622
3623
			// Loop through each column.
3624
			$queryColumns = $smcFunc['db_query']('', '
3625
				SHOW FULL COLUMNS
3626
				FROM ' . $table_info['Name'],
3627
				array(
3628
				)
3629
			);
3630
			while ($column_info = $smcFunc['db_fetch_assoc']($queryColumns))
3631
			{
3632
				// Only text'ish columns have a character set and need converting.
3633
				if (strpos($column_info['Type'], 'text') !== false || strpos($column_info['Type'], 'char') !== false)
3634
				{
3635
					$collation = empty($column_info['Collation']) || $column_info['Collation'] === 'NULL' ? $table_info['Collation'] : $column_info['Collation'];
3636
					if (!empty($collation) && $collation !== 'NULL')
3637
					{
3638
						list($charset) = explode('_', $collation);
3639
3640
						if (!isset($table_charsets[$charset]))
3641
							$table_charsets[$charset] = array();
3642
3643
						$table_charsets[$charset][] = $column_info;
3644
					}
3645
				}
3646
			}
3647
			$smcFunc['db_free_result']($queryColumns);
3648
3649
			// Only change the column if the data doesn't match the current charset.
3650
			if ((count($table_charsets) === 1 && key($table_charsets) !== $charsets[$upcontext['charset_detected']]) || count($table_charsets) > 1)
3651
			{
3652
				$updates_blob = '';
3653
				$updates_text = '';
3654
				foreach ($table_charsets as $charset => $columns)
3655
				{
3656
					if ($charset !== $charsets[$upcontext['charset_detected']])
3657
					{
3658
						foreach ($columns as $column)
3659
						{
3660
							$updates_blob .= '
3661
								CHANGE COLUMN `' . $column['Field'] . '` `' . $column['Field'] . '` ' . strtr($column['Type'], array('text' => 'blob', 'char' => 'binary')) . ($column['Null'] === 'YES' ? ' NULL' : ' NOT NULL') . (strpos($column['Type'], 'char') === false ? '' : ' default \'' . $column['Default'] . '\'') . ',';
3662
							$updates_text .= '
3663
								CHANGE COLUMN `' . $column['Field'] . '` `' . $column['Field'] . '` ' . $column['Type'] . ' CHARACTER SET ' . $charsets[$upcontext['charset_detected']] . ($column['Null'] === 'YES' ? '' : ' NOT NULL') . (strpos($column['Type'], 'char') === false ? '' : ' default \'' . $column['Default'] . '\'') . ',';
3664
						}
3665
					}
3666
				}
3667
3668
				// Change the columns to binary form.
3669
				$smcFunc['db_query']('', '
3670
					ALTER TABLE {raw:table_name}{raw:updates_blob}',
3671
					array(
3672
						'table_name' => $table_info['Name'],
3673
						'updates_blob' => substr($updates_blob, 0, -1),
3674
					)
3675
				);
3676
3677
				// Convert the character set if MySQL has no native support for it.
3678
				if (isset($translation_tables[$upcontext['charset_detected']]))
3679
				{
3680
					$update = '';
3681
					foreach ($table_charsets as $charset => $columns)
3682
						foreach ($columns as $column)
3683
							$update .= '
3684
								' . $column['Field'] . ' = ' . strtr($replace, array('%field%' => $column['Field'])) . ',';
0 ignored issues
show
Bug introduced by
The variable $replace 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...
3685
3686
					$smcFunc['db_query']('', '
3687
						UPDATE {raw:table_name}
3688
						SET {raw:updates}',
3689
						array(
3690
							'table_name' => $table_info['Name'],
3691
							'updates' => substr($update, 0, -1),
3692
						)
3693
					);
3694
				}
3695
3696
				// Change the columns back, but with the proper character set.
3697
				$smcFunc['db_query']('', '
3698
					ALTER TABLE {raw:table_name}{raw:updates_text}',
3699
					array(
3700
						'table_name' => $table_info['Name'],
3701
						'updates_text' => substr($updates_text, 0, -1),
3702
					)
3703
				);
3704
			}
3705
3706
			// Now do the actual conversion (if still needed).
3707
			if ($charsets[$upcontext['charset_detected']] !== 'utf8')
3708
			{
3709
				if ($command_line)
3710
					echo 'Converting table ' . $table_info['Name'] . ' to UTF-8...';
3711
3712
				$smcFunc['db_query']('', '
3713
					ALTER TABLE {raw:table_name}
3714
					CONVERT TO CHARACTER SET utf8',
3715
						array(
3716
								'table_name' => $table_info['Name'],
3717
						)
3718
				);
3719
3720
				if ($command_line)
3721
					echo " done.\n";
3722
			}
3723
		}
3724
3725
		$prev_charset = empty($translation_tables[$upcontext['charset_detected']]) ? $charsets[$upcontext['charset_detected']] : $translation_tables[$upcontext['charset_detected']];
3726
3727
		$smcFunc['db_insert']('replace',
3728
			'{db_prefix}settings',
3729
			array('variable' => 'string', 'value' => 'string'),
3730
			array(array('global_character_set', 'UTF-8'), array('previousCharacterSet', $prev_charset)),
3731
			array('variable')
3732
		);
3733
3734
		// Store it in Settings.php too because it's needed before db connection.
3735
		// Hopefully this works...
3736
		require_once($sourcedir . '/Subs-Admin.php');
3737
		updateSettingsFile(array('db_character_set' => '\'utf8\''));
3738
3739
		// The conversion might have messed up some serialized strings. Fix them!
3740
		$request = $smcFunc['db_query']('', '
3741
			SELECT id_action, extra
3742
			FROM {db_prefix}log_actions
3743
			WHERE action IN ({string:remove}, {string:delete})',
3744
			array(
3745
				'remove' => 'remove',
3746
				'delete' => 'delete',
3747
			)
3748
		);
3749 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($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...
3750
		{
3751
			if (@safe_unserialize($row['extra']) === false && preg_match('~^(a:3:{s:5:"topic";i:\d+;s:7:"subject";s:)(\d+):"(.+)"(;s:6:"member";s:5:"\d+";})$~', $row['extra'], $matches) === 1)
3752
				$smcFunc['db_query']('', '
3753
					UPDATE {db_prefix}log_actions
3754
					SET extra = {string:extra}
3755
					WHERE id_action = {int:current_action}',
3756
					array(
3757
						'current_action' => $row['id_action'],
3758
						'extra' => $matches[1] . strlen($matches[3]) . ':"' . $matches[3] . '"' . $matches[4],
3759
					)
3760
				);
3761
		}
3762
		$smcFunc['db_free_result']($request);
3763
3764
		if ($upcontext['dropping_index'] && $command_line)
3765
		{
3766
			echo "\nYour fulltext search index was dropped to facilitate the conversion. You will need to recreate it.";
3767
			flush();
3768
		}
3769
	}
3770
3771
	return true;
3772
}
3773
3774
function serialize_to_json()
3775
{
3776
	global $command_line, $smcFunc, $modSettings, $sourcedir, $upcontext, $support_js, $is_debug;
3777
3778
	$upcontext['sub_template'] = isset($_GET['xml']) ? 'serialize_json_xml' : 'serialize_json';
3779
	// First thing's first - did we already do this?
3780
	if (!empty($modSettings['json_done']))
3781
	{
3782
		if ($command_line)
3783
			return DeleteUpgrade();
3784
		else
3785
			return true;
3786
	}
3787
3788
	// Done it already - js wise?
3789
	if (!empty($_POST['json_done']))
3790
		return true;
3791
3792
	// List of tables affected by this function
3793
	// name => array('key', col1[,col2|true[,col3]])
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
3794
	// If 3rd item in array is true, it indicates that col1 could be empty...
3795
	$tables = array(
3796
		'background_tasks' => array('id_task', 'task_data'),
3797
		'log_actions' => array('id_action', 'extra'),
3798
		'log_online' => array('session', 'url'),
3799
		'log_packages' => array('id_install', 'db_changes', 'failed_steps', 'credits'),
3800
		'log_spider_hits' => array('id_hit', 'url'),
3801
		'log_subscribed' => array('id_sublog', 'pending_details'),
3802
		'pm_rules' => array('id_rule', 'criteria', 'actions'),
3803
		'qanda' => array('id_question', 'answers'),
3804
		'subscriptions' => array('id_subscribe', 'cost'),
3805
		'user_alerts' => array('id_alert', 'extra', true),
3806
		'user_drafts' => array('id_draft', 'to_list', true),
3807
		// These last two are a bit different - we'll handle those separately
3808
		'settings' => array(),
3809
		'themes' => array()
3810
	);
3811
3812
	// Set up some context stuff...
3813
	// Because we're not using numeric indices, we need this to figure out the current table name...
3814
	$keys = array_keys($tables);
3815
3816
	$upcontext['table_count'] = 13;
3817
	$upcontext['cur_table_num'] = $_GET['substep'];
3818
	$upcontext['cur_table_name'] = isset($keys[$_GET['substep']]) ? $keys[$_GET['substep']] : $keys[0];
3819
	$upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100);
3820
	$file_steps = $upcontext['table_count'];
0 ignored issues
show
Unused Code introduced by
$file_steps 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...
3821
3822 View Code Duplication
	foreach($keys as $id => $table)
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...
3823
		if ($id < $_GET['substep'])
3824
			$upcontext['previous_tables'][] = $table;
3825
3826
	if ($command_line)
3827
		echo 'Converting data from serialize() to json_encode().';
3828
3829
	if (!$support_js || isset($_GET['xml']))
3830
	{
3831
		// Fix the data in each table
3832
		for ($substep = $_GET['substep']; $substep < $upcontext['table_count']; $substep++)
3833
		{
3834
			$upcontext['cur_table_name'] = isset($keys[$substep + 1]) ? $keys[$substep + 1] : $keys[$substep];
3835
			$upcontext['cur_table_num'] = $substep + 1;
3836
3837
			$upcontext['step_progress'] = (int)(($upcontext['cur_table_num'] / $upcontext['table_count']) * 100);
3838
3839
			// Do we need to pause?
3840
			nextSubstep($substep);
3841
3842
			// Initialize a few things...
3843
			$where = '';
3844
			$vars = array();
3845
			$table = $keys[$substep];
3846
			$info = $tables[$table];
3847
3848
			// Now the fun - build our queries and all that fun stuff
3849
			if ($table == 'settings')
3850
			{
3851
				// Now a few settings...
3852
				$serialized_settings = array(
3853
					'attachment_basedirectories',
3854
					'attachmentUploadDir',
3855
					'cal_today_birthday',
3856
					'cal_today_event',
3857
					'cal_today_holiday',
3858
					'displayFields',
3859
					'last_attachments_directory',
3860
					'memberlist_cache',
3861
					'search_index_custom_config',
3862
					'spider_name_cache'
3863
				);
3864
3865
				// Loop through and fix these...
3866
				$new_settings = array();
3867
				if ($command_line)
3868
					echo "\n" . 'Fixing some settings...';
3869
3870
				foreach ($serialized_settings as $var)
3871
				{
3872
					if (isset($modSettings[$var]))
3873
					{
3874
						// Attempt to unserialize the setting
3875
						$temp = @safe_unserialize($modSettings[$var]);
3876
						if (!$temp && $command_line)
3877
							echo "\n - Failed to unserialize the '" . $var . "' setting. Skipping.";
3878
						elseif ($temp !== false)
3879
							$new_settings[$var] = json_encode($temp);
3880
					}
3881
				}
3882
3883
				// Update everything at once
3884
				if (!function_exists('cache_put_data'))
3885
					require_once($sourcedir . '/Load.php');
3886
				updateSettings($new_settings, true);
3887
3888
				if ($command_line)
3889
					echo ' done.';
3890
			}
3891
			elseif ($table == 'themes')
3892
			{
3893
				// Finally, fix the admin prefs. Unfortunately this is stored per theme, but hopefully they only have one theme installed at this point...
3894
				$query = $smcFunc['db_query']('', '
3895
					SELECT id_member, id_theme, value FROM {db_prefix}themes
3896
					WHERE variable = {string:admin_prefs}',
3897
						array(
3898
							'admin_prefs' => 'admin_preferences'
3899
						)
3900
				);
3901
3902
				if ($smcFunc['db_num_rows']($query) != 0)
3903
				{
3904
					while ($row = $smcFunc['db_fetch_assoc']($query))
3905
					{
3906
						$temp = @safe_unserialize($row['value']);
3907
3908
						if ($command_line)
3909
						{
3910
							if ($temp === false)
3911
								echo "\n" . 'Unserialize of admin_preferences for user ' . $row['id_member'] . ' failed. Skipping.';
3912
							else
3913
								echo "\n" . 'Fixing admin preferences...';
3914
						}
3915
3916
						if ($temp !== false)
3917
						{
3918
							$row['value'] = json_encode($temp);
3919
3920
							// Even though we have all values from the table, UPDATE is still faster than REPLACE
3921
							$smcFunc['db_query']('', '
3922
								UPDATE {db_prefix}themes
3923
								SET value = {string:prefs}
3924
								WHERE id_theme = {int:theme}
3925
									AND id_member = {int:member}',
3926
								array(
3927
									'prefs' => $row['value'],
3928
									'theme' => $row['id_theme'],
3929
									'member' => $row['id_member']
3930
								)
3931
							);
3932
3933
							if ($is_debug || $command_line)
3934
								echo ' done.';
3935
						}
3936
					}
3937
3938
					$smcFunc['db_free_result']($query);
3939
				}
3940
			}
3941
			else
3942
			{
3943
				// First item is always the key...
3944
				$key = $info[0];
3945
				unset($info[0]);
3946
3947
				// Now we know what columns we have and such...
3948
				if (count($info) == 2 && $info[2] === true)
3949
				{
3950
					$col_select = $info[1];
3951
					$where = ' WHERE ' . $info[1] . ' != {empty}';
3952
				}
3953
				else
3954
				{
3955
					$col_select = implode(', ', $info);
3956
				}
3957
3958
				$query = $smcFunc['db_query']('', '
3959
					SELECT ' . $key . ', ' . $col_select . '
3960
					FROM {db_prefix}' . $table . $where,
3961
					array()
3962
				);
3963
3964
				if ($smcFunc['db_num_rows']($query) != 0)
3965
				{
3966
					if ($command_line)
3967
					{
3968
						echo "\n" . ' +++ Fixing the "' . $table . '" table...';
3969
						flush();
3970
					}
3971
3972
					while ($row = $smcFunc['db_fetch_assoc']($query))
3973
					{
3974
						$update = '';
3975
3976
						// We already know what our key is...
3977
						foreach ($info as $col)
3978
						{
3979
							if ($col !== true && $row[$col] != '')
3980
							{
3981
								$temp = @safe_unserialize($row[$col]);
3982
3983
								if ($temp === false && $command_line)
3984
								{
3985
									echo "\nFailed to unserialize " . $row[$col] . "... Skipping\n";
3986
								}
3987
								else
3988
								{
3989
									$row[$col] = json_encode($temp);
3990
3991
									// Build our SET string and variables array
3992
									$update .= (empty($update) ? '' : ', ') . $col . ' = {string:' . $col . '}';
3993
									$vars[$col] = $row[$col];
3994
								}
3995
							}
3996
						}
3997
3998
						$vars[$key] = $row[$key];
3999
4000
						// In a few cases, we might have empty data, so don't try to update in those situations...
4001
						if (!empty($update))
4002
						{
4003
							$smcFunc['db_query']('', '
4004
								UPDATE {db_prefix}' . $table . '
4005
								SET ' . $update . '
4006
								WHERE ' . $key . ' = {' . ($key == 'session' ? 'string' : 'int') . ':' . $key . '}',
4007
								$vars
4008
							);
4009
						}
4010
					}
4011
4012
					if ($command_line)
4013
						echo ' done.';
4014
4015
					// Free up some memory...
4016
					$smcFunc['db_free_result']($query);
4017
				}
4018
			}
4019
			// If this is XML to keep it nice for the user do one table at a time anyway!
4020
			if (isset($_GET['xml']))
4021
				return upgradeExit();
4022
		}
4023
4024
		if ($command_line)
4025
		{
4026
			echo "\n" . 'Successful.' . "\n";
4027
			flush();
4028
		}
4029
		$upcontext['step_progress'] = 100;
4030
4031
		// Last but not least, insert a dummy setting so we don't have to do this again in the future...
4032
		updateSettings(array('json_done' => true));
4033
4034
		$_GET['substep'] = 0;
4035
		// Make sure we move on!
4036
		if ($command_line)
4037
			return DeleteUpgrade();
4038
4039
		return true;
4040
	}
4041
4042
	// If this fails we just move on to deleting the upgrade anyway...
4043
	$_GET['substep'] = 0;
4044
	return false;
4045
}
4046
4047
/******************************************************************************
4048
******************* Templates are below this point ****************************
4049
******************************************************************************/
4050
4051
// This is what is displayed if there's any chmod to be done. If not it returns nothing...
4052
function template_chmod()
4053
{
4054
	global $upcontext, $txt, $settings;
4055
4056
	// Don't call me twice!
4057
	if (!empty($upcontext['chmod_called']))
4058
		return;
4059
4060
	$upcontext['chmod_called'] = true;
4061
4062
	// Nothing?
4063
	if (empty($upcontext['chmod']['files']) && empty($upcontext['chmod']['ftp_error']))
4064
		return;
4065
4066
	// Was it a problem with Windows?
4067
	if (!empty($upcontext['chmod']['ftp_error']) && $upcontext['chmod']['ftp_error'] == 'total_mess')
4068
	{
4069
		echo '
4070
			<div class="error_message red">
4071
				The following files need to be writable to continue the upgrade. Please ensure the Windows permissions are correctly set to allow this:<br>
4072
				<ul style="margin: 2.5ex; font-family: monospace;">
4073
					<li>' . implode('</li>
4074
					<li>', $upcontext['chmod']['files']). '</li>
4075
				</ul>
4076
			</div>';
4077
4078
		return false;
4079
	}
4080
4081
	echo '
4082
		<div class="panel">
4083
			<h2>Your FTP connection information</h2>
4084
			<h3>The upgrader can fix any issues with file permissions to make upgrading as simple as possible. Simply enter your connection information below or alternatively click <a href="#" onclick="warning_popup();">here</a> for a list of files which need to be changed.</h3>
4085
			<script>
4086
				function warning_popup()
4087
				{
4088
					popup = window.open(\'\',\'popup\',\'height=150,width=400,scrollbars=yes\');
4089
					var content = popup.document;
4090
					content.write(\'<!DOCTYPE html>\n\');
4091
					content.write(\'<html', $txt['lang_rtl'] == true ? ' dir="rtl"' : '', '>\n\t<head>\n\t\t<meta name="robots" content="noindex">\n\t\t\');
4092
					content.write(\'<title>Warning</title>\n\t\t<link rel="stylesheet" href="', $settings['default_theme_url'], '/css/index.css">\n\t</head>\n\t<body id="popup">\n\t\t\');
4093
					content.write(\'<div class="windowbg description">\n\t\t\t<h4>The following files needs to be made writable to continue:</h4>\n\t\t\t\');
4094
					content.write(\'<p>', implode('<br>\n\t\t\t', $upcontext['chmod']['files']), '</p>\n\t\t\t\');';
4095
4096
	if (isset($upcontext['systemos']) && $upcontext['systemos'] == 'linux')
4097
		echo '
4098
					content.write(\'<hr>\n\t\t\t\');
4099
					content.write(\'<p>If you have a shell account, the convenient below command can automatically correct permissions on these files</p>\n\t\t\t\');
4100
					content.write(\'<tt># chmod a+w ', implode(' ', $upcontext['chmod']['files']), '</tt>\n\t\t\t\');';
4101
4102
	echo '
4103
					content.write(\'<a href="javascript:self.close();">close</a>\n\t\t</div>\n\t</body>\n</html>\');
4104
					content.close();
4105
				}
4106
		</script>';
4107
4108
	if (!empty($upcontext['chmod']['ftp_error']))
4109
		echo '
4110
			<div class="error_message red">
4111
				The following error was encountered when trying to connect:<br><br>
4112
				<code>', $upcontext['chmod']['ftp_error'], '</code>
4113
			</div>
4114
			<br>';
4115
4116
	if (empty($upcontext['chmod_in_form']))
4117
		echo '
4118
	<form action="', $upcontext['form_url'], '" method="post">';
4119
4120
	echo '
4121
		<table width="520" border="0" align="center" style="margin-bottom: 1ex;">
4122
			<tr>
4123
				<td width="26%" valign="top" class="textbox"><label for="ftp_server">', $txt['ftp_server'], ':</label></td>
4124
				<td>
4125
					<div style="float: right; margin-right: 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="', isset($upcontext['chmod']['port']) ? $upcontext['chmod']['port'] : '21', '" class="input_text"></div>
4126
					<input type="text" size="30" name="ftp_server" id="ftp_server" value="', isset($upcontext['chmod']['server']) ? $upcontext['chmod']['server'] : 'localhost', '" style="width: 70%;" class="input_text">
4127
					<div class="smalltext block">', $txt['ftp_server_info'], '</div>
4128
				</td>
4129
			</tr><tr>
4130
				<td width="26%" valign="top" class="textbox"><label for="ftp_username">', $txt['ftp_username'], ':</label></td>
4131
				<td>
4132
					<input type="text" size="50" name="ftp_username" id="ftp_username" value="', isset($upcontext['chmod']['username']) ? $upcontext['chmod']['username'] : '', '" style="width: 99%;" class="input_text">
4133
					<div class="smalltext block">', $txt['ftp_username_info'], '</div>
4134
				</td>
4135
			</tr><tr>
4136
				<td width="26%" valign="top" class="textbox"><label for="ftp_password">', $txt['ftp_password'], ':</label></td>
4137
				<td>
4138
					<input type="password" size="50" name="ftp_password" id="ftp_password" style="width: 99%;" class="input_password">
4139
					<div class="smalltext block">', $txt['ftp_password_info'], '</div>
4140
				</td>
4141
			</tr><tr>
4142
				<td width="26%" valign="top" class="textbox"><label for="ftp_path">', $txt['ftp_path'], ':</label></td>
4143
				<td style="padding-bottom: 1ex;">
4144
					<input type="text" size="50" name="ftp_path" id="ftp_path" value="', isset($upcontext['chmod']['path']) ? $upcontext['chmod']['path'] : '', '" style="width: 99%;" class="input_text">
4145
					<div class="smalltext block">', !empty($upcontext['chmod']['path']) ? $txt['ftp_path_found_info'] : $txt['ftp_path_info'], '</div>
4146
				</td>
4147
			</tr>
4148
		</table>
4149
4150
		<div class="righttext" style="margin: 1ex;"><input type="submit" value="', $txt['ftp_connect'], '" class="button_submit"></div>
4151
	</div>';
4152
4153
	if (empty($upcontext['chmod_in_form']))
4154
		echo '
4155
	</form>';
4156
}
4157
4158
function template_upgrade_above()
4159
{
4160
	global $modSettings, $txt, $settings, $upcontext, $upgradeurl;
4161
4162
	echo '<!DOCTYPE html>
4163
<html', $txt['lang_rtl'] == true ? ' dir="rtl"' : '', '>
4164
	<head>
4165
		<meta charset="', isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8', '">
4166
		<meta name="robots" content="noindex">
4167
		<title>', $txt['upgrade_upgrade_utility'], '</title>
4168
		<link rel="stylesheet" href="', $settings['default_theme_url'], '/css/index.css?alp21">
4169
		<link rel="stylesheet" href="', $settings['default_theme_url'], '/css/install.css?alp21">
4170
		', $txt['lang_rtl'] == true ? '<link rel="stylesheet" href="' . $settings['default_theme_url'] . '/css/rtl.css?alp21">' : '' , '
4171
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
4172
		<script src="', $settings['default_theme_url'], '/scripts/script.js"></script>
4173
		<script>
4174
			var smf_scripturl = \'', $upgradeurl, '\';
4175
			var smf_charset = \'', (empty($modSettings['global_character_set']) ? (empty($txt['lang_character_set']) ? 'UTF-8' : $txt['lang_character_set']) : $modSettings['global_character_set']), '\';
4176
			var startPercent = ', $upcontext['overall_percent'], ';
4177
4178
			// This function dynamically updates the step progress bar - and overall one as required.
4179
			function updateStepProgress(current, max, overall_weight)
4180
			{
4181
				// What out the actual percent.
4182
				var width = parseInt((current / max) * 100);
4183
				if (document.getElementById(\'step_progress\'))
4184
				{
4185
					document.getElementById(\'step_progress\').style.width = width + "%";
4186
					setInnerHTML(document.getElementById(\'step_text\'), width + "%");
4187
				}
4188
				if (overall_weight && document.getElementById(\'overall_progress\'))
4189
				{
4190
					overall_width = parseInt(startPercent + width * (overall_weight / 100));
4191
					document.getElementById(\'overall_progress\').style.width = overall_width + "%";
4192
					setInnerHTML(document.getElementById(\'overall_text\'), overall_width + "%");
4193
				}
4194
			}
4195
		</script>
4196
	</head>
4197
	<body>
4198
	<div id="footerfix">
4199
		<div id="header">
4200
			<h1 class="forumtitle">', $txt['upgrade_upgrade_utility'], '</h1>
4201
			<img id="smflogo" src="', $settings['default_theme_url'], '/images/smflogo.png" alt="Simple Machines Forum" title="Simple Machines Forum">
4202
		</div>
4203
	<div id="wrapper">
4204
		<div id="upper_section">
4205
			<div id="inner_section">
4206
				<div id="inner_wrap">
4207
				</div>
4208
			</div>
4209
		</div>
4210
		<div id="content_section">
4211
		<div id="main_content_section">
4212
			<div id="main_steps">
4213
				<h2>', $txt['upgrade_progress'], '</h2>
4214
				<ul>';
4215
4216 View Code Duplication
	foreach ($upcontext['steps'] as $num => $step)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
4217
		echo '
4218
						<li class="', $num < $upcontext['current_step'] ? 'stepdone' : ($num == $upcontext['current_step'] ? 'stepcurrent' : 'stepwaiting'), '">', $txt['upgrade_step'], ' ', $step[0], ': ', $step[1], '</li>';
4219
4220
	echo '
4221
					</ul>
4222
			</div>
4223
4224
			<div id="progress_bar">
4225
				<div id="overall_text">', $upcontext['overall_percent'], '%</div>
4226
				<div id="overall_progress" style="width: ', $upcontext['overall_percent'], '%;">
4227
					<span>', $txt['upgrade_overall_progress'], '</span>
4228
				</div>
4229
			</div>';
4230
4231
	if (isset($upcontext['step_progress']))
4232
		echo '
4233
				<br>
4234
				<br>
4235
				<div id="progress_bar_step">
4236
					<div id="step_text">', $upcontext['step_progress'], '%</div>
4237
					<div id="step_progress" style="width: ', $upcontext['step_progress'], '%;background-color: #ffd000;">
4238
						<span>', $txt['upgrade_step_progress'], '</span>
4239
					</div>
4240
				</div>';
4241
4242
	echo '
4243
				<div id="substep_bar_div" class="smalltext" style="float: left;width: 50%;margin-top: 0.6em;display: ', isset($upcontext['substep_progress']) ? '' : 'none', ';">', isset($upcontext['substep_progress_name']) ? trim(strtr($upcontext['substep_progress_name'], array('.' => ''))) : '', ':</div>
4244
				<div id="substep_bar_div2" style="float: left;font-size: 8pt; height: 12pt; border: 1px solid black; background-color: white; width: 33%; margin: 0.6em auto 0 6em; display: ', isset($upcontext['substep_progress']) ? '' : 'none', ';">
4245
					<div id="substep_text" style="color: #000; position: absolute; margin-left: -5em;">', isset($upcontext['substep_progress']) ? $upcontext['substep_progress'] : '', '%</div>
4246
					<div id="substep_progress" style="width: ', isset($upcontext['substep_progress']) ? $upcontext['substep_progress'] : 0, '%; height: 12pt; z-index: 1; background-color: #eebaf4;">&nbsp;</div>
4247
				</div>';
4248
4249
	// How long have we been running this?
4250
	$elapsed = time() - $upcontext['started'];
4251
	$mins = (int) ($elapsed / 60);
4252
	$seconds = $elapsed - $mins * 60;
4253
	echo '
4254
								<br> <br> <br> <br> <br>
4255
								<div class="smalltext" style="padding: 5px; text-align: center;"><br>', $txt['upgrade_time_elapsed'], ':
4256
									<span id="mins_elapsed">', $mins, '</span> ', $txt['upgrade_time_mins'], ', <span id="secs_elapsed">', $seconds, '</span> ', $txt['upgrade_time_secs'], '.
4257
								</div>';
4258
	echo '
4259
			</div>
4260
			</div>
4261
			<div id="main_screen" class="clear">
4262
				<h2>', $upcontext['page_title'], '</h2>
4263
				<div class="panel">
4264
					<div style="max-height: 360px; overflow: auto;">';
4265
}
4266
4267
function template_upgrade_below()
4268
{
4269
	global $upcontext, $txt;
4270
4271
	if (!empty($upcontext['pause']))
4272
		echo '
4273
								<em>', $txt['upgrade_incomplete'], '.</em><br>
4274
4275
								<h2 style="margin-top: 2ex;">', $txt['upgrade_not_quite_done'], '</h2>
4276
								<h3>
4277
									', $txt['upgrade_paused_overload'], '
4278
								</h3>';
4279
4280
	if (!empty($upcontext['custom_warning']))
4281
		echo '
4282
								<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
4283
									<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
4284
									<strong style="text-decoration: underline;">', $txt['upgrade_note'], '</strong><br>
4285
									<div style="padding-left: 6ex;">', $upcontext['custom_warning'], '</div>
4286
								</div>';
4287
4288
	echo '
4289
								<div class="righttext" style="margin: 1ex;">';
4290
4291
	if (!empty($upcontext['continue']))
4292
		echo '
4293
									<input type="submit" id="contbutt" name="contbutt" value="', $txt['upgrade_continue'], '"', $upcontext['continue'] == 2 ? ' disabled' : '', ' class="button_submit">';
4294
	if (!empty($upcontext['skip']))
4295
		echo '
4296
									<input type="submit" id="skip" name="skip" value="', $txt['upgrade_skip'], '" onclick="dontSubmit = true; document.getElementById(\'contbutt\').disabled = \'disabled\'; return true;" class="button_submit">';
4297
4298
	echo '
4299
								</div>
4300
							</form>
4301
						</div>
4302
				</div>
4303
			</div>
4304
			</div>
4305
		</div>
4306
		<div id="footer">
4307
			<ul>
4308
				<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>
4309
			</ul>
4310
		</div>
4311
	</body>
4312
</html>';
4313
4314
	// Are we on a pause?
4315
	if (!empty($upcontext['pause']))
4316
	{
4317
		echo '
4318
		<script>
4319
			window.onload = doAutoSubmit;
4320
			var countdown = 3;
4321
			var dontSubmit = false;
4322
4323
			function doAutoSubmit()
4324
			{
4325
				if (countdown == 0 && !dontSubmit)
4326
					document.upform.submit();
4327
				else if (countdown == -1)
4328
					return;
4329
4330
				document.getElementById(\'contbutt\').value = "', $txt['upgrade_continue'], ' (" + countdown + ")";
4331
				countdown--;
4332
4333
				setTimeout("doAutoSubmit();", 1000);
4334
			}
4335
		</script>';
4336
	}
4337
}
4338
4339
function template_xml_above()
4340
{
4341
	global $upcontext;
4342
4343
	echo '<', '?xml version="1.0" encoding="UTF-8"?', '>
4344
	<smf>';
4345
4346
	if (!empty($upcontext['get_data']))
4347
		foreach ($upcontext['get_data'] as $k => $v)
4348
			echo '
4349
		<get key="', $k, '">', $v, '</get>';
4350
}
4351
4352
function template_xml_below()
4353
{
4354
	echo '
4355
		</smf>';
4356
}
4357
4358
function template_error_message()
4359
{
4360
	global $upcontext;
4361
4362
	echo '
4363
	<div class="error_message red">
4364
		', $upcontext['error_msg'], '
4365
		<br>
4366
		<a href="', $_SERVER['PHP_SELF'], '">Click here to try again.</a>
4367
	</div>';
4368
}
4369
4370
function template_welcome_message()
0 ignored issues
show
Best Practice introduced by
The function template_welcome_message() has been defined more than once; this definition is ignored, only the first definition in other/install.php (L1908-1957) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
4371
{
4372
	global $upcontext, $disable_security, $settings, $txt;
4373
4374
	echo '
4375
		<script src="http://www.simplemachines.org/smf/current-version.js?version=' . SMF_VERSION . '"></script>
4376
			<h3>', sprintf($txt['upgrade_ready_proceed'], SMF_VERSION), '</h3>
4377
	<form action="', $upcontext['form_url'], '" method="post" name="upform" id="upform">
4378
		<input type="hidden" name="', $upcontext['login_token_var'], '" value="', $upcontext['login_token'], '">
4379
		<div id="version_warning" style="margin: 2ex; padding: 2ex; border: 2px dashed #a92174; color: black; background-color: #fbbbe2; display: none;">
4380
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
4381
			<strong style="text-decoration: underline;">', $txt['upgrade_warning'], '</strong><br>
4382
			<div style="padding-left: 6ex;">
4383
				', sprintf($txt['upgrade_warning_out_of_date'], SMF_VERSION), '
4384
			</div>
4385
		</div>';
4386
4387
	$upcontext['chmod_in_form'] = true;
4388
	template_chmod();
4389
4390
	// For large, pre 1.1 RC2 forums give them a warning about the possible impact of this upgrade!
4391
	if ($upcontext['is_large_forum'])
4392
		echo '
4393
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
4394
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
4395
			<strong style="text-decoration: underline;">', $txt['upgrade_warning'], '</strong><br>
4396
			<div style="padding-left: 6ex;">
4397
				', $txt['upgrade_warning_lots_data'], '
4398
			</div>
4399
		</div>';
4400
4401
	// A warning message?
4402
	if (!empty($upcontext['warning']))
4403
		echo '
4404
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
4405
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
4406
			<strong style="text-decoration: underline;">', $txt['upgrade_warning'], '</strong><br>
4407
			<div style="padding-left: 6ex;">
4408
				', $upcontext['warning'], '
4409
			</div>
4410
		</div>';
4411
4412
	// Paths are incorrect?
4413
	echo '
4414
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #804840; color: black; background-color: #fe5a44; ', (file_exists($settings['default_theme_dir'] . '/scripts/script.js') ? 'display: none;' : ''), '" id="js_script_missing_error">
4415
			<div style="float: left; width: 2ex; font-size: 2em; color: black;">!!</div>
4416
			<strong style="text-decoration: underline;">', $txt['upgrade_critical_error'], '</strong><br>
4417
			<div style="padding-left: 6ex;">
4418
				', $txt['upgrade_error_script_js'], '
4419
			</div>
4420
		</div>';
4421
4422
	// Is there someone already doing this?
4423
	if (!empty($upcontext['user']['id']) && (time() - $upcontext['started'] < 72600 || time() - $upcontext['updated'] < 3600))
4424
	{
4425
		$ago = time() - $upcontext['started'];
4426
		if ($ago < 60)
4427
			$ago = $ago . ' seconds';
4428
		elseif ($ago < 3600)
4429
			$ago = (int) ($ago / 60) . ' minutes';
4430
		else
4431
			$ago = (int) ($ago / 3600) . ' hours';
4432
4433
		$active = time() - $upcontext['updated'];
4434
		if ($active < 60)
4435
			$updated = $active . ' seconds';
4436
		elseif ($active < 3600)
4437
			$updated = (int) ($active / 60) . ' minutes';
4438
		else
4439
			$updated = (int) ($active / 3600) . ' hours';
4440
4441
		echo '
4442
		<div style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9;">
4443
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
4444
			<strong style="text-decoration: underline;">', $txt['upgrade_warning'], '</strong><br>
4445
			<div style="padding-left: 6ex;">
4446
				&quot;', $upcontext['user']['name'], '&quot; has been running the upgrade script for the last ', $ago, ' - and was last active ', $updated, ' ago.';
4447
4448
		if ($active < 600)
4449
			echo '
4450
				We recommend that you do not run this script unless you are sure that ', $upcontext['user']['name'], ' has completed their upgrade.';
4451
4452
		if ($active > $upcontext['inactive_timeout'])
4453
			echo '
4454
				<br><br>You can choose to either run the upgrade again from the beginning - or alternatively continue from the last step reached during the last upgrade.';
4455
		else
4456
			echo '
4457
				<br><br>This upgrade script cannot be run until ', $upcontext['user']['name'], ' has been inactive for at least ', ($upcontext['inactive_timeout'] > 120 ? round($upcontext['inactive_timeout'] / 60, 1) . ' minutes!' : $upcontext['inactive_timeout'] . ' seconds!');
4458
4459
		echo '
4460
			</div>
4461
		</div>';
4462
	}
4463
4464
	echo '
4465
			<strong>Admin Login: ', $disable_security ? '(DISABLED)' : '', '</strong>
4466
			<h3>For security purposes please login with your admin account to proceed with the upgrade.</h3>
4467
			<table>
4468
				<tr valign="top">
4469
					<td><strong ', $disable_security ? 'style="color: gray;"' : '', '>Username:</strong></td>
4470
					<td>
4471
						<input type="text" name="user" value="', !empty($upcontext['username']) ? $upcontext['username'] : '', '"', $disable_security ? ' disabled' : '', ' class="input_text">';
4472
4473
	if (!empty($upcontext['username_incorrect']))
4474
		echo '
4475
						<div class="smalltext" style="color: red;">Username Incorrect</div>';
4476
4477
	echo '
4478
					</td>
4479
				</tr>
4480
				<tr valign="top">
4481
					<td><strong ', $disable_security ? 'style="color: gray;"' : '', '>Password:</strong></td>
4482
					<td>
4483
						<input type="password" name="passwrd" value=""', $disable_security ? ' disabled' : '', ' class="input_password">
4484
						<input type="hidden" name="hash_passwrd" value="">';
4485
4486
	if (!empty($upcontext['password_failed']))
4487
		echo '
4488
						<div class="smalltext" style="color: red;">Password Incorrect</div>';
4489
4490
	echo '
4491
					</td>
4492
				</tr>';
4493
4494
	// Can they continue?
4495
	if (!empty($upcontext['user']['id']) && time() - $upcontext['user']['updated'] >= $upcontext['inactive_timeout'] && $upcontext['user']['step'] > 1)
4496
	{
4497
		echo '
4498
				<tr>
4499
					<td colspan="2">
4500
						<label for="cont"><input type="checkbox" id="cont" name="cont" checked class="input_check">Continue from step reached during last execution of upgrade script.</label>
4501
					</td>
4502
				</tr>';
4503
	}
4504
4505
	echo '
4506
			</table><br>
4507
			<span class="smalltext">
4508
				<strong>Note:</strong> If necessary the above security check can be bypassed for users who may administrate a server but not have admin rights on the forum. In order to bypass the above check simply open &quot;upgrade.php&quot; in a text editor and replace &quot;$disable_security = false;&quot; with &quot;$disable_security = true;&quot; and refresh this page.
4509
			</span>
4510
			<input type="hidden" name="login_attempt" id="login_attempt" value="1">
4511
			<input type="hidden" name="js_works" id="js_works" value="0">';
4512
4513
	// Say we want the continue button!
4514
	$upcontext['continue'] = !empty($upcontext['user']['id']) && time() - $upcontext['user']['updated'] < $upcontext['inactive_timeout'] ? 2 : 1;
4515
4516
	// This defines whether javascript is going to work elsewhere :D
4517
	echo '
4518
		<script>
4519
			if (\'XMLHttpRequest\' in window && document.getElementById(\'js_works\'))
4520
				document.getElementById(\'js_works\').value = 1;
4521
4522
			// Latest version?
4523
			function smfCurrentVersion()
4524
			{
4525
				var smfVer, yourVer;
4526
4527
				if (!(\'smfVersion\' in window))
4528
					return;
4529
4530
				window.smfVersion = window.smfVersion.replace(/SMF\s?/g, \'\');
4531
4532
				smfVer = document.getElementById(\'smfVersion\');
4533
				yourVer = document.getElementById(\'yourVersion\');
4534
4535
				setInnerHTML(smfVer, window.smfVersion);
4536
4537
				var currentVersion = getInnerHTML(yourVer);
4538
				if (currentVersion < window.smfVersion)
4539
					document.getElementById(\'version_warning\').style.display = \'\';
4540
			}
4541
			addLoadEvent(smfCurrentVersion);
4542
4543
			// This checks that the script file even exists!
4544
			if (typeof(smfSelectText) == \'undefined\')
4545
				document.getElementById(\'js_script_missing_error\').style.display = \'\';
4546
4547
		</script>';
4548
}
4549
4550
function template_upgrade_options()
4551
{
4552
	global $upcontext, $modSettings, $db_prefix, $mmessage, $mtitle, $db_type;
4553
4554
	echo '
4555
			<h3>Before the upgrade gets underway please review the options below - and hit continue when you\'re ready to begin.</h3>
4556
			<form action="', $upcontext['form_url'], '" method="post" name="upform" id="upform">';
4557
4558
	// Warning message?
4559
	if (!empty($upcontext['upgrade_options_warning']))
4560
		echo '
4561
		<div style="margin: 1ex; padding: 1ex; border: 1px dashed #cc3344; color: black; background-color: #ffe4e9;">
4562
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
4563
			<strong style="text-decoration: underline;">Warning!</strong><br>
4564
			<div style="padding-left: 4ex;">
4565
				', $upcontext['upgrade_options_warning'], '
4566
			</div>
4567
		</div>';
4568
4569
	echo '
4570
				<table>
4571
					<tr valign="top">
4572
						<td width="2%">
4573
							<input type="checkbox" name="backup" id="backup" value="1"', $db_type != 'mysql' && $db_type != 'mysqli' && $db_type != 'postgresql' ? ' disabled' : '', ' class="input_check">
4574
						</td>
4575
						<td width="100%">
4576
							<label for="backup">Backup tables in your database with the prefix &quot;backup_' . $db_prefix . '&quot;.</label>', isset($modSettings['smfVersion']) ? '' : ' (recommended!)', '
4577
						</td>
4578
					</tr>
4579
					<tr valign="top">
4580
						<td width="2%">
4581
							<input type="checkbox" name="maint" id="maint" value="1" checked class="input_check">
4582
						</td>
4583
						<td width="100%">
4584
							<label for="maint">Put the forum into maintenance mode during upgrade.</label> <span class="smalltext">(<a href="#" onclick="document.getElementById(\'mainmess\').style.display = document.getElementById(\'mainmess\').style.display == \'\' ? \'none\' : \'\'">Customize</a>)</span>
4585
							<div id="mainmess" style="display: none;">
4586
								<strong class="smalltext">Maintenance Title: </strong><br>
4587
								<input type="text" name="maintitle" size="30" value="', htmlspecialchars($mtitle), '" class="input_text"><br>
4588
								<strong class="smalltext">Maintenance Message: </strong><br>
4589
								<textarea name="mainmessage" rows="3" cols="50">', htmlspecialchars($mmessage), '</textarea>
4590
							</div>
4591
						</td>
4592
					</tr>';
4593
4594
	// Offer mysql users to switch to mysqli
4595
	if ($db_type == 'mysql' && function_exists('mysqli_query'))
4596
		echo '
4597
					<tr valign="top">
4598
						<td width="2%">
4599
							<input type="checkbox" name="convertMysql" id="convertMysql" value="1" checked class="input_check">
4600
						</td>
4601
						<td width="100%">
4602
							<label for="convertMysql">Use MySQLi functionality (MySQL compatible).</span>
4603
							<strong class="smalltext"><a href="http://wiki.simplemachines.org/smf/Upgrading-MySQLi-Functionality" target="_blank">More information about MySQLi</a></strong><br>
4604
						</td>
4605
					</tr>';
4606
4607
	echo '
4608
					<tr valign="top">
4609
						<td width="2%">
4610
							<input type="checkbox" name="debug" id="debug" value="1" class="input_check">
4611
						</td>
4612
						<td width="100%">
4613
							<label for="debug">Output extra debugging information</label>
4614
						</td>
4615
					</tr>
4616
					<tr valign="top">
4617
						<td width="2%">
4618
							<input type="checkbox" name="empty_error" id="empty_error" value="1" class="input_check">
4619
						</td>
4620
						<td width="100%">
4621
							<label for="empty_error">Empty error log before upgrading</label>
4622
						</td>
4623
					</tr>';
4624
4625
	if (!empty($upcontext['karma_installed']['good']) || !empty($upcontext['karma_installed']['bad']))
4626
		echo '
4627
					<tr valign="top">
4628
						<td width="2%">
4629
							<input type="checkbox" name="delete_karma" id="delete_karma" value="1" class="input_check">
4630
						</td>
4631
						<td width="100%">
4632
							<label for="delete_karma">Delete all karma settings and info from the DB</label>
4633
						</td>
4634
					</tr>';
4635
4636
	echo '
4637
					<tr valign="top">
4638
						<td width="2%">
4639
							<input type="checkbox" name="stat" id="stat" value="1"', empty($modSettings['allow_sm_stats']) ? '' : ' checked', ' class="input_check">
4640
						</td>
4641
						<td width="100%">
4642
							<label for="stat">
4643
								Allow Simple Machines to Collect Basic Stats Monthly.<br>
4644
								<span class="smalltext">If enabled, this will allow Simple Machines to visit your site once a month to collect basic statistics. This will help us make decisions as to which configurations to optimise the software for. For more information please visit our <a href="http://www.simplemachines.org/about/stats.php" target="_blank">info page</a>.</span>
4645
							</label>
4646
						</td>
4647
					</tr>
4648
				</table>
4649
				<input type="hidden" name="upcont" value="1">';
4650
4651
	// We need a normal continue button here!
4652
	$upcontext['continue'] = 1;
4653
}
4654
4655
// Template for the database backup tool/
4656
function template_backup_database()
4657
{
4658
	global $upcontext, $support_js, $is_debug;
4659
4660
	echo '
4661
			<h3>Please wait while a backup is created. For large forums this may take some time!</h3>';
4662
4663
	echo '
4664
			<form action="', $upcontext['form_url'], '" name="upform" id="upform" method="post">
4665
			<input type="hidden" name="backup_done" id="backup_done" value="0">
4666
			<strong>Completed <span id="tab_done">', $upcontext['cur_table_num'], '</span> out of ', $upcontext['table_count'], ' tables.</strong>
4667
			<span id="debuginfo"></span>';
4668
4669
	// Dont any tables so far?
4670
	if (!empty($upcontext['previous_tables']))
4671
		foreach ($upcontext['previous_tables'] as $table)
4672
			echo '
4673
			<br>Completed Table: &quot;', $table, '&quot;.';
4674
4675
	echo '
4676
			<h3 id="current_tab_div">Current Table: &quot;<span id="current_table">', $upcontext['cur_table_name'], '</span>&quot;</h3>
4677
			<br><span id="commess" style="font-weight: bold; display: ', $upcontext['cur_table_num'] == $upcontext['table_count'] ? 'inline' : 'none', ';">Backup Complete! Click Continue to Proceed.</span>';
4678
4679
	// Continue please!
4680
	$upcontext['continue'] = $support_js ? 2 : 1;
4681
4682
	// If javascript allows we want to do this using XML.
4683
	if ($support_js)
4684
	{
4685
		echo '
4686
		<script>
4687
			var lastTable = ', $upcontext['cur_table_num'], ';
4688
			function getNextTables()
4689
			{
4690
				getXMLDocument(\'', $upcontext['form_url'], '&xml&substep=\' + lastTable, onBackupUpdate);
4691
			}
4692
4693
			// Got an update!
4694
			function onBackupUpdate(oXMLDoc)
4695
			{
4696
				var sCurrentTableName = "";
4697
				var iTableNum = 0;
4698
				var sCompletedTableName = getInnerHTML(document.getElementById(\'current_table\'));
4699
				for (var i = 0; i < oXMLDoc.getElementsByTagName("table")[0].childNodes.length; i++)
4700
					sCurrentTableName += oXMLDoc.getElementsByTagName("table")[0].childNodes[i].nodeValue;
4701
				iTableNum = oXMLDoc.getElementsByTagName("table")[0].getAttribute("num");
4702
4703
				// Update the page.
4704
				setInnerHTML(document.getElementById(\'tab_done\'), iTableNum);
4705
				setInnerHTML(document.getElementById(\'current_table\'), sCurrentTableName);
4706
				lastTable = iTableNum;
4707
				updateStepProgress(iTableNum, ', $upcontext['table_count'], ', ', $upcontext['step_weight'] * ((100 - $upcontext['step_progress']) / 100), ');';
4708
4709
		// If debug flood the screen.
4710
		if ($is_debug)
4711
			echo '
4712
				setOuterHTML(document.getElementById(\'debuginfo\'), \'<br>Completed Table: &quot;\' + sCompletedTableName + \'&quot;.<span id="debuginfo"><\' + \'/span>\');
4713
4714
				if (document.getElementById(\'debuginfo\').scrollHeight)
4715
					document.getElementById(\'debuginfo\').scrollTop = document.getElementById(\'debuginfo\').scrollHeight;';
4716
4717
		echo '
4718
				// Get the next update...
4719
				if (iTableNum == ', $upcontext['table_count'], ')
4720
				{
4721
					document.getElementById(\'commess\').style.display = "";
4722
					document.getElementById(\'current_tab_div\').style.display = "none";
4723
					document.getElementById(\'contbutt\').disabled = 0;
4724
					document.getElementById(\'backup_done\').value = 1;
4725
				}
4726
				else
4727
					getNextTables();
4728
			}
4729
			getNextTables();
4730
		</script>';
4731
	}
4732
}
4733
4734
function template_backup_xml()
4735
{
4736
	global $upcontext;
4737
4738
	echo '
4739
	<table num="', $upcontext['cur_table_num'], '">', $upcontext['cur_table_name'], '</table>';
4740
}
4741
4742
// Here is the actual "make the changes" template!
4743
function template_database_changes()
4744
{
4745
	global $upcontext, $support_js, $is_debug, $timeLimitThreshold;
4746
4747
	if (empty($is_debug) && !empty($upcontext['upgrade_status']['debug']))
4748
		$is_debug = true;
4749
4750
	echo '
4751
		<h3>Executing database changes</h3>
4752
		<h4 style="font-style: italic;">Please be patient - this may take some time on large forums. The time elapsed increments from the server to show progress is being made!</h4>';
4753
4754
	echo '
4755
		<form action="', $upcontext['form_url'], '&amp;filecount=', $upcontext['file_count'], '" name="upform" id="upform" method="post">
4756
		<input type="hidden" name="database_done" id="database_done" value="0">';
4757
4758
	// No javascript looks rubbish!
4759
	if (!$support_js)
4760
	{
4761
		foreach ($upcontext['actioned_items'] as $num => $item)
4762
		{
4763
			if ($num != 0)
4764
				echo ' Successful!';
4765
			echo '<br>' . $item;
4766
		}
4767 View Code Duplication
		if (!empty($upcontext['changes_complete']))
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...
4768
		{
4769
			if ($is_debug)
4770
			{
4771
				$active = time() - $upcontext['started'];
4772
				$hours = floor($active / 3600);
4773
				$minutes = intval(($active / 60) % 60);
4774
				$seconds = intval($active % 60);
4775
4776
				$totalTime = '';
4777
				if ($hours > 0)
4778
					$totalTime .= $hours . ' hour' . ($hours > 1 ? 's':'') . ' ';
4779
				if ($minutes > 0)
4780
					$totalTime .= $minutes . ' minute' . ($minutes > 1 ? 's':'') . ' ';
4781
				if ($seconds > 0)
4782
					$totalTime .= $seconds . ' second' . ($seconds > 1 ? 's':'') . ' ';
4783
			}
4784
4785
			if ($is_debug && !empty($totalTime))
4786
				echo ' Successful! Completed in ', $totalTime, '<br><br>';
4787
			else
4788
				echo ' Successful!<br><br>';
4789
4790
			echo '<span id="commess" style="font-weight: bold;">1 Database Updates Complete! Click Continue to Proceed.</span><br>';
4791
		}
4792
	}
4793
	else
4794
	{
4795
		// Tell them how many files we have in total.
4796
		if ($upcontext['file_count'] > 1)
4797
			echo '
4798
		<strong id="info1">Executing upgrade script <span id="file_done">', $upcontext['cur_file_num'], '</span> of ', $upcontext['file_count'], '.</strong>';
4799
4800
		echo '
4801
		<h3 id="info2"><strong>Executing:</strong> &quot;<span id="cur_item_name">', $upcontext['current_item_name'], '</span>&quot; (<span id="item_num">', $upcontext['current_item_num'], '</span> of <span id="total_items"><span id="item_count">', $upcontext['total_items'], '</span>', $upcontext['file_count'] > 1 ? ' - of this script' : '', ')</span></h3>
4802
		<br><span id="commess" style="font-weight: bold; display: ', !empty($upcontext['changes_complete']) || $upcontext['current_debug_item_num'] == $upcontext['debug_items'] ? 'inline' : 'none', ';">Database Updates Complete! Click Continue to Proceed.</span>';
4803
4804 View Code Duplication
		if ($is_debug)
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...
4805
		{
4806
			if ($upcontext['current_debug_item_num'] == $upcontext['debug_items'])
4807
			{
4808
				$active = time() - $upcontext['started'];
4809
				$hours = floor($active / 3600);
4810
				$minutes = intval(($active / 60) % 60);
4811
				$seconds = intval($active % 60);
4812
4813
				$totalTime = '';
4814
				if ($hours > 0)
4815
					$totalTime .= $hours . ' hour' . ($hours > 1 ? 's':'') . ' ';
4816
				if ($minutes > 0)
4817
					$totalTime .= $minutes . ' minute' . ($minutes > 1 ? 's':'') . ' ';
4818
				if ($seconds > 0)
4819
					$totalTime .= $seconds . ' second' . ($seconds > 1 ? 's':'') . ' ';
4820
			}
4821
4822
			echo '
4823
			<br><span id="upgradeCompleted">';
4824
4825
			if (!empty($totalTime))
4826
				echo 'Completed in ', $totalTime, '<br>';
4827
4828
			echo '</span>
4829
			<div id="debug_section" style="height: 200px; overflow: auto;">
4830
			<span id="debuginfo"></span>
4831
			</div>';
4832
		}
4833
	}
4834
4835
	// Place for the XML error message.
4836
	echo '
4837
		<div id="error_block" style="margin: 2ex; padding: 2ex; border: 2px dashed #cc3344; color: black; background-color: #ffe4e9; display: ', empty($upcontext['error_message']) ? 'none' : '', ';">
4838
			<div style="float: left; width: 2ex; font-size: 2em; color: red;">!!</div>
4839
			<strong style="text-decoration: underline;">Error!</strong><br>
4840
			<div style="padding-left: 6ex;" id="error_message">', isset($upcontext['error_message']) ? $upcontext['error_message'] : 'Unknown Error!', '</div>
4841
		</div>';
4842
4843
	// We want to continue at some point!
4844
	$upcontext['continue'] = $support_js ? 2 : 1;
4845
4846
	// If javascript allows we want to do this using XML.
4847
	if ($support_js)
4848
	{
4849
		echo '
4850
		<script>
4851
			var lastItem = ', $upcontext['current_debug_item_num'], ';
4852
			var sLastString = "', strtr($upcontext['current_debug_item_name'], array('"' => '&quot;')), '";
4853
			var iLastSubStepProgress = -1;
4854
			var curFile = ', $upcontext['cur_file_num'], ';
4855
			var totalItems = 0;
4856
			var prevFile = 0;
4857
			var retryCount = 0;
4858
			var testvar = 0;
4859
			var timeOutID = 0;
4860
			var getData = "";
4861
			var debugItems = ', $upcontext['debug_items'], ';';
4862
4863
		if ($is_debug)
4864
			echo '
4865
			var upgradeStartTime = ' . $upcontext['started'] . ';';
4866
4867
		echo '
4868
			function getNextItem()
4869
			{
4870
				// We want to track this...
4871
				if (timeOutID)
4872
					clearTimeout(timeOutID);
4873
				timeOutID = window.setTimeout("retTimeout()", ', (10 * $timeLimitThreshold), '000);
4874
4875
				getXMLDocument(\'', $upcontext['form_url'], '&xml&filecount=', $upcontext['file_count'], '&substep=\' + lastItem + getData, onItemUpdate);
4876
			}
4877
4878
			// Got an update!
4879
			function onItemUpdate(oXMLDoc)
4880
			{
4881
				var sItemName = "";
4882
				var sDebugName = "";
4883
				var iItemNum = 0;
4884
				var iSubStepProgress = -1;
4885
				var iDebugNum = 0;
4886
				var bIsComplete = 0;
4887
				getData = "";
4888
4889
				// We\'ve got something - so reset the timeout!
4890
				if (timeOutID)
4891
					clearTimeout(timeOutID);
4892
4893
				// Assume no error at this time...
4894
				document.getElementById("error_block").style.display = "none";
4895
4896
				// Are we getting some duff info?
4897
				if (!oXMLDoc.getElementsByTagName("item")[0])
4898
				{
4899
					// Too many errors?
4900
					if (retryCount > 15)
4901
					{
4902
						document.getElementById("error_block").style.display = "";
4903
						setInnerHTML(document.getElementById("error_message"), "Error retrieving information on step: " + (sDebugName == "" ? sLastString : sDebugName));';
4904
4905
	if ($is_debug)
4906
		echo '
4907
						setOuterHTML(document.getElementById(\'debuginfo\'), \'<span style="color: red;">failed<\' + \'/span><span id="debuginfo"><\' + \'/span>\');';
4908
4909
	echo '
4910
					}
4911
					else
4912
					{
4913
						retryCount++;
4914
						getNextItem();
4915
					}
4916
					return false;
4917
				}
4918
4919
				// Never allow loops.
4920
				if (curFile == prevFile)
4921
				{
4922
					retryCount++;
4923
					if (retryCount > 10)
4924
					{
4925
						document.getElementById("error_block").style.display = "";
4926
						setInnerHTML(document.getElementById("error_message"), "Upgrade script appears to be going into a loop - step: " + sDebugName);';
4927
4928
	if ($is_debug)
4929
		echo '
4930
						setOuterHTML(document.getElementById(\'debuginfo\'), \'<span style="color: red;">failed<\' + \'/span><span id="debuginfo"><\' + \'/span>\');';
4931
4932
	echo '
4933
					}
4934
				}
4935
				retryCount = 0;
4936
4937
				for (var i = 0; i < oXMLDoc.getElementsByTagName("item")[0].childNodes.length; i++)
4938
					sItemName += oXMLDoc.getElementsByTagName("item")[0].childNodes[i].nodeValue;
4939
				for (var i = 0; i < oXMLDoc.getElementsByTagName("debug")[0].childNodes.length; i++)
4940
					sDebugName += oXMLDoc.getElementsByTagName("debug")[0].childNodes[i].nodeValue;
4941
				for (var i = 0; i < oXMLDoc.getElementsByTagName("get").length; i++)
4942
				{
4943
					getData += "&" + oXMLDoc.getElementsByTagName("get")[i].getAttribute("key") + "=";
4944
					for (var j = 0; j < oXMLDoc.getElementsByTagName("get")[i].childNodes.length; j++)
4945
					{
4946
						getData += oXMLDoc.getElementsByTagName("get")[i].childNodes[j].nodeValue;
4947
					}
4948
				}
4949
4950
				iItemNum = oXMLDoc.getElementsByTagName("item")[0].getAttribute("num");
4951
				iDebugNum = parseInt(oXMLDoc.getElementsByTagName("debug")[0].getAttribute("num"));
4952
				bIsComplete = parseInt(oXMLDoc.getElementsByTagName("debug")[0].getAttribute("complete"));
4953
				iSubStepProgress = parseFloat(oXMLDoc.getElementsByTagName("debug")[0].getAttribute("percent"));
4954
				sLastString = sDebugName + " (Item: " + iDebugNum + ")";
4955
4956
				curFile = parseInt(oXMLDoc.getElementsByTagName("file")[0].getAttribute("num"));
4957
				debugItems = parseInt(oXMLDoc.getElementsByTagName("file")[0].getAttribute("debug_items"));
4958
				totalItems = parseInt(oXMLDoc.getElementsByTagName("file")[0].getAttribute("items"));
4959
4960
				// If we have an error we haven\'t completed!
4961
				if (oXMLDoc.getElementsByTagName("error")[0] && bIsComplete)
4962
					iDebugNum = lastItem;
4963
4964
				// Do we have the additional progress bar?
4965
				if (iSubStepProgress != -1)
4966
				{
4967
					document.getElementById("substep_bar_div").style.display = "";
4968
					document.getElementById("substep_bar_div2").style.display = "";
4969
					document.getElementById("substep_progress").style.width = iSubStepProgress + "%";
4970
					setInnerHTML(document.getElementById("substep_text"), iSubStepProgress + "%");
4971
					setInnerHTML(document.getElementById("substep_bar_div"), sDebugName.replace(/\./g, "") + ":");
4972
				}
4973
				else
4974
				{
4975
					document.getElementById("substep_bar_div").style.display = "none";
4976
					document.getElementById("substep_bar_div2").style.display = "none";
4977
				}
4978
4979
				// Move onto the next item?
4980
				if (bIsComplete)
4981
					lastItem = iDebugNum;
4982
				else
4983
					lastItem = iDebugNum - 1;
4984
4985
				// Are we finished?
4986
				if (bIsComplete && iDebugNum == -1 && curFile >= ', $upcontext['file_count'], ')
4987
				{';
4988
4989
		if ($is_debug)
4990
			echo '
4991
					document.getElementById(\'debug_section\').style.display = "none";
4992
4993
					var upgradeFinishedTime = parseInt(oXMLDoc.getElementsByTagName("curtime")[0].childNodes[0].nodeValue);
4994
					var diffTime = upgradeFinishedTime - upgradeStartTime;
4995
					var diffHours = Math.floor(diffTime / 3600);
4996
					var diffMinutes = parseInt((diffTime / 60) % 60);
4997
					var diffSeconds = parseInt(diffTime % 60);
4998
4999
					var totalTime = "";
5000
					if (diffHours > 0)
5001
						totalTime = totalTime + diffHours + " hour" + (diffHours > 1 ? "s" : "") + " ";
5002
					if (diffMinutes > 0)
5003
						totalTime = totalTime + diffMinutes + " minute" + (diffMinutes > 1 ? "s" : "") + " ";
5004
					if (diffSeconds > 0)
5005
						totalTime = totalTime + diffSeconds + " second" + (diffSeconds > 1 ? "s" : "");
5006
5007
					setInnerHTML(document.getElementById("upgradeCompleted"), "Completed in " + totalTime);';
5008
5009
		echo '
5010
5011
					document.getElementById(\'commess\').style.display = "";
5012
					document.getElementById(\'contbutt\').disabled = 0;
5013
					document.getElementById(\'database_done\').value = 1;';
5014
5015
		if ($upcontext['file_count'] > 1)
5016
			echo '
5017
					document.getElementById(\'info1\').style.display = "none";';
5018
5019
		echo '
5020
					document.getElementById(\'info2\').style.display = "none";
5021
					updateStepProgress(100, 100, ', $upcontext['step_weight'] * ((100 - $upcontext['step_progress']) / 100), ');
5022
					return true;
5023
				}
5024
				// Was it the last step in the file?
5025
				else if (bIsComplete && iDebugNum == -1)
5026
				{
5027
					lastItem = 0;
5028
					prevFile = curFile;';
5029
5030
		if ($is_debug)
5031
			echo '
5032
					setOuterHTML(document.getElementById(\'debuginfo\'), \'Moving to next script file...done<br><span id="debuginfo"><\' + \'/span>\');';
5033
5034
		echo '
5035
					getNextItem();
5036
					return true;
5037
				}';
5038
5039
		// If debug scroll the screen.
5040
		if ($is_debug)
5041
			echo '
5042
				if (iLastSubStepProgress == -1)
5043
				{
5044
					// Give it consistent dots.
5045
					dots = sDebugName.match(/\./g);
5046
					numDots = dots ? dots.length : 0;
5047
					for (var i = numDots; i < 3; i++)
5048
						sDebugName += ".";
5049
					setOuterHTML(document.getElementById(\'debuginfo\'), sDebugName + \'<span id="debuginfo"><\' + \'/span>\');
5050
				}
5051
				iLastSubStepProgress = iSubStepProgress;
5052
5053
				if (bIsComplete)
5054
					setOuterHTML(document.getElementById(\'debuginfo\'), \'done<br><span id="debuginfo"><\' + \'/span>\');
5055
				else
5056
					setOuterHTML(document.getElementById(\'debuginfo\'), \'...<span id="debuginfo"><\' + \'/span>\');
5057
5058
				if (document.getElementById(\'debug_section\').scrollHeight)
5059
					document.getElementById(\'debug_section\').scrollTop = document.getElementById(\'debug_section\').scrollHeight';
5060
5061
		echo '
5062
				// Update the page.
5063
				setInnerHTML(document.getElementById(\'item_num\'), iItemNum);
5064
				setInnerHTML(document.getElementById(\'cur_item_name\'), sItemName);';
5065
5066
		if ($upcontext['file_count'] > 1)
5067
		{
5068
			echo '
5069
				setInnerHTML(document.getElementById(\'file_done\'), curFile);
5070
				setInnerHTML(document.getElementById(\'item_count\'), totalItems);';
5071
		}
5072
5073
		echo '
5074
				// Is there an error?
5075
				if (oXMLDoc.getElementsByTagName("error")[0])
5076
				{
5077
					var sErrorMsg = "";
5078
					for (var i = 0; i < oXMLDoc.getElementsByTagName("error")[0].childNodes.length; i++)
5079
						sErrorMsg += oXMLDoc.getElementsByTagName("error")[0].childNodes[i].nodeValue;
5080
					document.getElementById("error_block").style.display = "";
5081
					setInnerHTML(document.getElementById("error_message"), sErrorMsg);
5082
					return false;
5083
				}
5084
5085
				// Get the progress bar right.
5086
				barTotal = debugItems * ', $upcontext['file_count'], ';
5087
				barDone = (debugItems * (curFile - 1)) + lastItem;
5088
5089
				updateStepProgress(barDone, barTotal, ', $upcontext['step_weight'] * ((100 - $upcontext['step_progress']) / 100), ');
5090
5091
				// Finally - update the time here as it shows the server is responding!
5092
				curTime = new Date();
5093
				iElapsed = (curTime.getTime() / 1000 - ', $upcontext['started'], ');
5094
				mins = parseInt(iElapsed / 60);
5095
				secs = parseInt(iElapsed - mins * 60);
5096
				setInnerHTML(document.getElementById("mins_elapsed"), mins);
5097
				setInnerHTML(document.getElementById("secs_elapsed"), secs);
5098
5099
				getNextItem();
5100
				return true;
5101
			}
5102
5103
			// What if we timeout?!
5104
			function retTimeout(attemptAgain)
5105
			{
5106
				// Oh noes...
5107
				if (!attemptAgain)
5108
				{
5109
					document.getElementById("error_block").style.display = "";
5110
					setInnerHTML(document.getElementById("error_message"), "Server has not responded for ', ($timeLimitThreshold * 10), ' seconds. It may be worth waiting a little longer or otherwise please click <a href=\"#\" onclick=\"retTimeout(true); return false;\">here<" + "/a> to try this step again");
5111
				}
5112
				else
5113
				{
5114
					document.getElementById("error_block").style.display = "none";
5115
					getNextItem();
5116
				}
5117
			}';
5118
5119
		// Start things off assuming we've not errored.
5120
		if (empty($upcontext['error_message']))
5121
			echo '
5122
			getNextItem();';
5123
5124
		echo '
5125
		</script>';
5126
	}
5127
	return;
5128
}
5129
5130
function template_database_xml()
5131
{
5132
	global $is_debug, $upcontext, $txt;
5133
5134
	echo '
5135
	<file num="', $upcontext['cur_file_num'], '" items="', $upcontext['total_items'], '" debug_items="', $upcontext['debug_items'], '">', $upcontext['cur_file_name'], '</file>
5136
	<item num="', $upcontext['current_item_num'], '">', $upcontext['current_item_name'], '</item>
5137
	<debug num="', $upcontext['current_debug_item_num'], '" percent="', isset($upcontext['substep_progress']) ? $upcontext['substep_progress'] : '-1', '" complete="', empty($upcontext['completed_step']) ? 0 : 1, '">', $upcontext['current_debug_item_name'], '</debug>';
5138
5139
	if (!empty($upcontext['error_message']))
5140
		echo '
5141
	<error>', $upcontext['error_message'], '</error>';
5142
5143
	if (!empty($upcontext['error_string']))
5144
		echo '
5145
	<sql>', $upcontext['error_string'], '</sql>';
5146
5147
	if ($is_debug)
5148
		echo '
5149
	<curtime>', time(), '</curtime>';
5150
}
5151
5152
// Template for the UTF-8 conversion step. Basically a copy of the backup stuff with slight modifications....
5153 View Code Duplication
function template_convert_utf8()
0 ignored issues
show
Duplication introduced by
This function 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...
5154
{
5155
	global $upcontext, $support_js, $is_debug;
5156
5157
	echo '
5158
			<h3>Please wait while your database is converted to UTF-8. For large forums this may take some time!</h3>';
5159
5160
	echo '
5161
			<form action="', $upcontext['form_url'], '" name="upform" id="upform" method="post">
5162
			<input type="hidden" name="utf8_done" id="utf8_done" value="0">
5163
			<strong>Completed <span id="tab_done">', $upcontext['cur_table_num'], '</span> out of ', $upcontext['table_count'], ' tables.</strong>
5164
			<span id="debuginfo"></span>';
5165
5166
	// Done any tables so far?
5167
	if (!empty($upcontext['previous_tables']))
5168
		foreach ($upcontext['previous_tables'] as $table)
5169
			echo '
5170
			<br>Completed Table: &quot;', $table, '&quot;.';
5171
5172
	echo '
5173
			<h3 id="current_tab_div">Current Table: &quot;<span id="current_table">', $upcontext['cur_table_name'], '</span>&quot;</h3>';
5174
5175
	// If we dropped their index, let's let them know
5176
	if ($upcontext['cur_table_num'] == $upcontext['table_count'] && $upcontext['dropping_index'])
5177
		echo '
5178
			<br><span style="display:inline;">Please note that your fulltext index was dropped to facilitate the conversion and will need to be recreated.</span>';
5179
5180
	echo '
5181
			<br><span id="commess" style="font-weight: bold; display: ', $upcontext['cur_table_num'] == $upcontext['table_count'] ? 'inline' : 'none', ';">Conversion Complete! Click Continue to Proceed.</span>';
5182
5183
	// Continue please!
5184
	$upcontext['continue'] = $support_js ? 2 : 1;
5185
5186
	// If javascript allows we want to do this using XML.
5187
	if ($support_js)
5188
	{
5189
		echo '
5190
		<script>
5191
			var lastTable = ', $upcontext['cur_table_num'], ';
5192
			function getNextTables()
5193
			{
5194
				getXMLDocument(\'', $upcontext['form_url'], '&xml&substep=\' + lastTable, onBackupUpdate);
5195
			}
5196
5197
			// Got an update!
5198
			function onBackupUpdate(oXMLDoc)
5199
			{
5200
				var sCurrentTableName = "";
5201
				var iTableNum = 0;
5202
				var sCompletedTableName = getInnerHTML(document.getElementById(\'current_table\'));
5203
				for (var i = 0; i < oXMLDoc.getElementsByTagName("table")[0].childNodes.length; i++)
5204
					sCurrentTableName += oXMLDoc.getElementsByTagName("table")[0].childNodes[i].nodeValue;
5205
				iTableNum = oXMLDoc.getElementsByTagName("table")[0].getAttribute("num");
5206
5207
				// Update the page.
5208
				setInnerHTML(document.getElementById(\'tab_done\'), iTableNum);
5209
				setInnerHTML(document.getElementById(\'current_table\'), sCurrentTableName);
5210
				lastTable = iTableNum;
5211
				updateStepProgress(iTableNum, ', $upcontext['table_count'], ', ', $upcontext['step_weight'] * ((100 - $upcontext['step_progress']) / 100), ');';
5212
5213
		// If debug flood the screen.
5214
		if ($is_debug)
5215
			echo '
5216
				setOuterHTML(document.getElementById(\'debuginfo\'), \'<br>Completed Table: &quot;\' + sCompletedTableName + \'&quot;.<span id="debuginfo"><\' + \'/span>\');';
5217
5218
		echo '
5219
				// Get the next update...
5220
				if (iTableNum == ', $upcontext['table_count'], ')
5221
				{
5222
					document.getElementById(\'commess\').style.display = "";
5223
					document.getElementById(\'current_tab_div\').style.display = "none";
5224
					document.getElementById(\'contbutt\').disabled = 0;
5225
					document.getElementById(\'utf8_done\').value = 1;
5226
				}
5227
				else
5228
					getNextTables();
5229
			}
5230
			getNextTables();
5231
		</script>';
5232
	}
5233
}
5234
5235
function template_utf8_xml()
5236
{
5237
	global $upcontext;
5238
5239
	echo '
5240
	<table num="', $upcontext['cur_table_num'], '">', $upcontext['cur_table_name'], '</table>';
5241
}
5242
5243
function template_clean_mods()
5244
{
5245
	global $upcontext;
5246
5247
	$upcontext['chmod_in_form'] = true;
5248
5249
	echo '
5250
	<h3>SMF has detected some packages which were installed but not fully removed prior to upgrade. We recommend you remove the following mods and reinstall upon completion of the upgrade.</h3>
5251
	<form action="', $upcontext['form_url'], '&amp;ssi=1" name="upform" id="upform" method="post">';
5252
5253
	// In case it's required.
5254
	template_chmod();
5255
5256
	echo '
5257
		<table width="90%" align="center" style="background-color: black;">
5258
			<tr style="background-color: #eeeeee;">
5259
				<td width="40%"><strong>Modification Name</strong></td>
5260
				<td width="10%" align="center"><strong>Version</strong></td>
5261
				<td width="15%"><strong>Files Affected</strong></td>
5262
				<td width="20%"><strong>Status</strong></td>
5263
				<td width="5%" align="center"><strong>Fix?</strong></td>
5264
			</tr>';
5265
5266
	foreach ($upcontext['packages'] as $package)
5267
	{
5268
		echo '
5269
			<tr style="background-color: #cccccc;">
5270
				<td width="40%">', $package['name'], '</td>
5271
				<td width="10%">', $package['version'], '</td>
5272
				<td width="15%">', $package['file_count'], ' <span class="smalltext">[<a href="#" onclick="alert(\'The following files are affected by this modification:\\n\\n', strtr(implode('<br>', $package['files']), array('\\' => '\\\\', '<br>' => '\\n')), '\'); return false;">details</a>]</td>
5273
				<td width="20%"><span style="font-weight: bold; color: ', $package['color'], '">', $package['status'], '</span></td>
5274
				<td width="5%" align="center">
5275
					<input type="hidden" name="remove[', $package['id'], ']" value="0">
5276
					<input type="checkbox" name="remove[', $package['id'], ']"', $package['color'] == 'green' ? ' disabled' : '', ' class="input_check">
5277
				</td>
5278
			</tr>';
5279
	}
5280
	echo '
5281
		</table>
5282
		<input type="hidden" name="cleandone" value="1">';
5283
5284
	// Files to make writable?
5285 View Code Duplication
	if (!empty($upcontext['writable_files']))
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...
5286
		echo '
5287
		<input type="hidden" name="writable_files" value="', base64_encode(safe_serialize($upcontext['writable_files'])), '">';
5288
5289
	// We'll want a continue button...
5290
	if (empty($upcontext['chmod']['files']))
5291
		$upcontext['continue'] = 1;
5292
}
5293
5294
// Finished with the mods - let them know what we've done.
5295
function template_cleanup_done()
5296
{
5297
	global $upcontext;
5298
5299
	echo '
5300
	<h3>SMF has attempted to fix and reinstall mods as required. We recommend you visit the package manager upon completing upgrade to check the status of your modifications.</h3>
5301
	<form action="', $upcontext['form_url'], '&amp;ssi=1" name="upform" id="upform" method="post">
5302
		<table width="90%" align="center" style="background-color: black;">
5303
			<tr style="background-color: #eeeeee;">
5304
				<td width="100%"><strong>Actions Completed:</strong></td>
5305
			</tr>';
5306
5307
	foreach ($upcontext['packages'] as $package)
5308
	{
5309
		echo '
5310
			<tr style="background-color: #cccccc;">
5311
				<td>', $package['name'], '... <span style="font-weight: bold; color: ', $package['color'], ';">', $package['result'], '</span></td>
5312
			</tr>';
5313
	}
5314
	echo '
5315
		</table>
5316
		<input type="hidden" name="cleandone2" value="1">';
5317
5318
	// We'll want a continue button...
5319
	$upcontext['continue'] = 1;
5320
}
5321
5322
// Do they want to upgrade their templates?
5323
function template_upgrade_templates()
5324
{
5325
	global $upcontext;
5326
5327
	echo '
5328
	<h3>There have been numerous language and template changes since the previous version of SMF. On this step the upgrader can attempt to automatically make these changes in your templates to save you from doing so manually.</h3>
5329
	<form action="', $upcontext['form_url'], '&amp;ssi=1', $upcontext['is_test'] ? '' : ';forreal=1', '" name="upform" id="upform" method="post">';
5330
5331
	// Any files need to be writable?
5332
	$upcontext['chmod_in_form'] = true;
5333
	template_chmod();
5334
5335
	// Language/Template files need an update?
5336
	if ($upcontext['temp_progress'] == 0 && !$upcontext['is_test'] && (!empty($upcontext['languages']) || !empty($upcontext['themes'])))
5337
	{
5338
		echo '
5339
		The following template files will be updated to ensure they are compatible with this version of SMF. Note that this can only fix a limited number of compatibility issues and in general you should seek out the latest version of these themes/language files.
5340
		<table width="90%" align="center" style="background-color: black;">
5341
			<tr style="background-color: #eeeeee;">
5342
				<td width="80%"><strong>Area</strong></td>
5343
				<td width="20%" align="center"><strong>Changes Required</strong></td>
5344
			</tr>';
5345
5346 View Code Duplication
		foreach ($upcontext['languages'] as $language)
0 ignored issues
show
Bug introduced by
The expression $upcontext['languages'] of type boolean is not traversable.
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...
5347
		{
5348
			echo '
5349
				<tr style="background-color: #cccccc;">
5350
					<td width="80%">
5351
						&quot;', $language['name'], '&quot; Language Pack
5352
						<div class="smalltext">(';
5353
5354
			foreach ($language['files'] as $k => $file)
5355
				echo $file['name'], $k + 1 != count($language['files']) ? ', ' : ')';
5356
5357
			echo '
5358
						</div>
5359
					</td>
5360
					<td width="20%" align="center">', $language['edit_count'] == 0 ? 1 : $language['edit_count'], '</td>
5361
				</tr>';
5362
		}
5363
5364 View Code Duplication
		foreach ($upcontext['themes'] as $theme)
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...
5365
		{
5366
			echo '
5367
				<tr style="background-color: #CCCCCC;">
5368
					<td width="80%">
5369
						&quot;', $theme['name'], '&quot; Theme
5370
						<div class="smalltext">(';
5371
5372
			foreach ($theme['files'] as $k => $file)
5373
				echo $file['name'], $k + 1 != count($theme['files']) ? ', ' : ')';
5374
5375
			echo '
5376
						</div>
5377
					</td>
5378
					<td width="20%" align="center">', $theme['edit_count'] == 0 ? 1 : $theme['edit_count'], '</td>
5379
				</tr>';
5380
		}
5381
5382
		echo '
5383
		</table>';
5384
	}
5385
	else
5386
	{
5387
		$langFiles = 0;
5388
		$themeFiles = 0;
5389
		if (!empty($upcontext['languages']))
5390
			foreach ($upcontext['languages'] as $lang)
0 ignored issues
show
Bug introduced by
The expression $upcontext['languages'] of type boolean is not traversable.
Loading history...
5391
				$langFiles += count($lang['files']);
5392
		if (!empty($upcontext['themes']))
5393
			foreach ($upcontext['themes'] as $theme)
0 ignored issues
show
Bug introduced by
The expression $upcontext['themes'] of type boolean is not traversable.
Loading history...
5394
				$themeFiles += count($theme['files']);
5395
		echo sprintf('Found <strong>%d</strong> language files and <strong>%d</strong> templates requiring an update so far.', $langFiles, $themeFiles) . '<br>';
5396
5397
		// What we're currently doing?
5398
		if (!empty($upcontext['current_message']))
5399
			echo '
5400
				', $upcontext['current_message'];
5401
	}
5402
5403
	echo '
5404
		<input type="hidden" name="uptempdone" value="1">';
5405
5406 View Code Duplication
	if (!empty($upcontext['languages']))
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...
5407
		echo '
5408
		<input type="hidden" name="languages" value="', base64_encode(safe_serialize($upcontext['languages'])), '">';
5409 View Code Duplication
	if (!empty($upcontext['themes']))
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...
5410
		echo '
5411
		<input type="hidden" name="themes" value="', base64_encode(safe_serialize($upcontext['themes'])), '">';
5412 View Code Duplication
	if (!empty($upcontext['writable_files']))
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...
5413
		echo '
5414
		<input type="hidden" name="writable_files" value="', base64_encode(safe_serialize($upcontext['writable_files'])), '">';
5415
5416
	// Offer them the option to upgrade from YaBB SE?
5417
	if (!empty($upcontext['can_upgrade_yabbse']))
5418
		echo '
5419
		<br><label for="conv"><input type="checkbox" name="conv" id="conv" value="1" class="input_check"> Convert the existing YaBB SE template and set it as default.</label><br>';
5420
5421
	// We'll want a continue button... assuming chmod is OK (Otherwise let them use connect!)
5422
	if (empty($upcontext['chmod']['files']) || $upcontext['is_test'])
5423
		$upcontext['continue'] = 1;
5424
}
5425
5426
// Template for the database backup tool/
5427 View Code Duplication
function template_serialize_json()
0 ignored issues
show
Duplication introduced by
This function 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...
5428
{
5429
	global $upcontext, $support_js, $is_debug;
5430
5431
	echo '
5432
			<h3>Converting data from serialize to JSON...</h3>';
5433
5434
	echo '
5435
			<form action="', $upcontext['form_url'], '" name="upform" id="upform" method="post">
5436
			<input type="hidden" name="json_done" id="json_done" value="0">
5437
			<strong>Completed <span id="tab_done">', $upcontext['cur_table_num'], '</span> out of ', $upcontext['table_count'], ' tables.</strong>
5438
			<span id="debuginfo"></span>';
5439
5440
	// Dont any tables so far?
5441
	if (!empty($upcontext['previous_tables']))
5442
		foreach ($upcontext['previous_tables'] as $table)
5443
			echo '
5444
			<br>Completed Table: &quot;', $table, '&quot;.';
5445
5446
	echo '
5447
			<h3 id="current_tab_div">Current Table: &quot;<span id="current_table">', $upcontext['cur_table_name'], '</span>&quot;</h3>
5448
			<br><span id="commess" style="font-weight: bold; display: ', $upcontext['cur_table_num'] == $upcontext['table_count'] ? 'inline' : 'none', ';">Convert to JSON Complete! Click Continue to Proceed.</span>';
5449
5450
	// Try to make sure substep was reset.
5451
	if ($upcontext['cur_table_num'] == $upcontext['table_count'])
5452
		echo '
5453
			<input type="hidden" name="substep" id="substep" value="0">';
5454
5455
	// Continue please!
5456
	$upcontext['continue'] = $support_js ? 2 : 1;
5457
5458
	// If javascript allows we want to do this using XML.
5459
	if ($support_js)
5460
	{
5461
		echo '
5462
		<script>
5463
			var lastTable = ', $upcontext['cur_table_num'], ';
5464
			function getNextTables()
5465
			{
5466
				getXMLDocument(\'', $upcontext['form_url'], '&xml&substep=\' + lastTable, onBackupUpdate);
5467
			}
5468
5469
			// Got an update!
5470
			function onBackupUpdate(oXMLDoc)
5471
			{
5472
				var sCurrentTableName = "";
5473
				var iTableNum = 0;
5474
				var sCompletedTableName = getInnerHTML(document.getElementById(\'current_table\'));
5475
				for (var i = 0; i < oXMLDoc.getElementsByTagName("table")[0].childNodes.length; i++)
5476
					sCurrentTableName += oXMLDoc.getElementsByTagName("table")[0].childNodes[i].nodeValue;
5477
				iTableNum = oXMLDoc.getElementsByTagName("table")[0].getAttribute("num");
5478
5479
				// Update the page.
5480
				setInnerHTML(document.getElementById(\'tab_done\'), iTableNum);
5481
				setInnerHTML(document.getElementById(\'current_table\'), sCurrentTableName);
5482
				lastTable = iTableNum;
5483
				updateStepProgress(iTableNum, ', $upcontext['table_count'], ', ', $upcontext['step_weight'] * ((100 - $upcontext['step_progress']) / 100), ');';
5484
5485
		// If debug flood the screen.
5486
		if ($is_debug)
5487
			echo '
5488
				setOuterHTML(document.getElementById(\'debuginfo\'), \'<br>Completed Table: &quot;\' + sCompletedTableName + \'&quot;.<span id="debuginfo"><\' + \'/span>\');';
5489
5490
		echo '
5491
				// Get the next update...
5492
				if (iTableNum == ', $upcontext['table_count'], ')
5493
				{
5494
					document.getElementById(\'commess\').style.display = "";
5495
					document.getElementById(\'current_tab_div\').style.display = "none";
5496
					document.getElementById(\'contbutt\').disabled = 0;
5497
					document.getElementById(\'json_done\').value = 1;
5498
				}
5499
				else
5500
					getNextTables();
5501
			}
5502
			getNextTables();
5503
		</script>';
5504
	}
5505
}
5506
5507
function template_serialize_json_xml()
5508
{
5509
	global $upcontext;
5510
5511
	echo '
5512
	<table num="', $upcontext['cur_table_num'], '">', $upcontext['cur_table_name'], '</table>';
5513
}
5514
5515
function template_upgrade_complete()
5516
{
5517
	global $upcontext, $upgradeurl, $settings, $boardurl, $is_debug;
5518
5519
	echo '
5520
	<h3>That wasn\'t so hard, was it?  Now you are ready to use <a href="', $boardurl, '/index.php">your installation of SMF</a>.  Hope you like it!</h3>
5521
	<form action="', $boardurl, '/index.php">';
5522
5523
	if (!empty($upcontext['can_delete_script']))
5524
		echo '
5525
			<label for="delete_self"><input type="checkbox" id="delete_self" onclick="doTheDelete(this);" class="input_check"> Delete upgrade.php and its data files now</label> <em>(doesn\'t work on all servers).</em>
5526
			<script>
5527
				function doTheDelete(theCheck)
5528
				{
5529
					var theImage = document.getElementById ? document.getElementById("delete_upgrader") : document.all.delete_upgrader;
5530
5531
					theImage.src = "', $upgradeurl, '?delete=1&ts_" + (new Date().getTime());
5532
					theCheck.disabled = true;
5533
				}
5534
			</script>
5535
			<img src="', $settings['default_theme_url'], '/images/blank.png" alt="" id="delete_upgrader"><br>';
5536
5537
	$active = time() - $upcontext['started'];
5538
	$hours = floor($active / 3600);
5539
	$minutes = intval(($active / 60) % 60);
5540
	$seconds = intval($active % 60);
5541
5542
	if ($is_debug)
5543
	{
5544
		$totalTime = '';
5545
		if ($hours > 0)
5546
			$totalTime .= $hours . ' hour' . ($hours > 1 ? 's':'') . ' ';
5547
		if ($minutes > 0)
5548
			$totalTime .= $minutes . ' minute' . ($minutes > 1 ? 's':'') . ' ';
5549
		if ($seconds > 0)
5550
			$totalTime .= $seconds . ' second' . ($seconds > 1 ? 's':'') . ' ';
5551
	}
5552
5553
	if ($is_debug && !empty($totalTime))
5554
		echo '<br> Upgrade completed in ', $totalTime, '<br><br>';
5555
5556
	echo '<br>
5557
			If you had any problems with this upgrade, or have any problems using SMF, please don\'t hesitate to <a href="http://www.simplemachines.org/community/index.php">look to us for assistance</a>.<br>
5558
			<br>
5559
			Best of luck,<br>
5560
			Simple Machines';
5561
}
5562
5563
/**
5564
 * Convert MySQL (var)char ip col to binary
5565
 * newCol needs to be a varbinary(16) null able field
5566
 * return true or false
5567
 */
5568
function MySQLConvertOldIp($targetTable, $oldCol, $newCol, $limit = 50000, $setSize = 100)
5569
{
5570
	global $smcFunc, $step_progress;
5571
5572
	$step_progress['name'] = 'Converting ips';
5573
	$step_progress['current'] = $_GET['a'];
5574
5575
	// Skip this if we don't have the column
5576
	$request = $smcFunc['db_query']('', '
5577
		SHOW FIELDS
5578
		FROM {db_prefix}{raw:table}
5579
		WHERE Field = {string:name}',
5580
		array(
5581
			'table' => $targetTable,
5582
			'name' => $oldCol,
5583
	));
5584
	if ($smcFunc['db_num_rows']($request) !== 1)
5585
	{
5586
		$smcFunc['db_free_result']($request);
5587
		return;
5588
	}
5589
	$smcFunc['db_free_result']($request);
5590
5591
	//mysql default max length is 1mb http://dev.mysql.com/doc/refman/5.1/en/packet-too-large.html
5592
	$arIp = array();
5593
5594
	$is_done = false;
5595
	while (!$is_done)
5596
	{
5597
		nextSubStep($substep);
0 ignored issues
show
Bug introduced by
The variable $substep 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...
5598
5599
		$request = $smcFunc['db_query']('', '
5600
			SELECT DISTINCT {raw:old_col}
5601
			FROM {db_prefix}{raw:table_name}
5602
			WHERE {raw:new_col} IS NULL
5603
			LIMIT {int:limit}',
5604
			array(
5605
				'old_col' => $oldCol,
5606
				'new_col' => $newCol,
5607
				'table_name' => $targetTable,
5608
				'empty' => '',
5609
				'limit' => $limit,
5610
		));
5611
		while ($row = $smcFunc['db_fetch_assoc']($request))
5612
			$arIp[] = $row[$oldCol];
5613
		$smcFunc['db_free_result']($request);
5614
5615
		// Special case, null ip could keep us in a loop.
5616
		if (is_null($arIp[0]))
5617
			unset($arIp[0]);
5618
5619
		if (empty($arIp))
5620
			$is_done = true;
5621
5622
		$updates = array();
5623
		$cases = array();
5624
		for ($i = 0; $i < count($arIp); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
5625
		{
5626
			$arIp[$i] = trim($arIp[$i]);
5627
5628
			if (empty($arIp[$i]))
5629
				continue;
5630
5631
			$updates['ip' . $i] = trim($arIp[$i]);
5632
			$cases[trim($arIp[$i])] = 'WHEN ' . $oldCol . ' = {string:ip' . $i . '} THEN {inet:ip' . $i . '}';
5633
5634
			if ($setSize > 0 && $i % $setSize === 0)
5635
			{
5636
				if (count($updates) == 1)
5637
					continue;
5638
5639
				$updates['whereSet'] = array_values($updates);
5640
				$smcFunc['db_query']('', '
5641
					UPDATE {db_prefix}' . $targetTable . '
5642
					SET ' . $newCol . ' = CASE ' .
5643
					implode('
5644
						', $cases) . '
5645
						ELSE NULL
5646
					END
5647
					WHERE ' . $oldCol . ' IN ({array_string:whereSet})',
5648
					$updates
5649
				);
5650
5651
				$updates = array();
5652
				$cases = array();
5653
			}
5654
		}
5655
5656
		// Incase some extras made it through.
5657
		if (!empty($updates))
5658
		{
5659
			if (count($updates) == 1)
5660
			{
5661
				foreach ($updates as $key => $ip)
5662
				{
5663
					$request = $smcFunc['db_query']('', '
0 ignored issues
show
Unused Code introduced by
$request 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...
5664
						UPDATE {db_prefix}' . $targetTable . '
5665
						SET ' . $newCol . ' = {inet:ip}
5666
						WHERE ' . $oldCol . ' = {string:ip}',
5667
						array(
5668
							'ip' => $ip
5669
					));
5670
				}
5671
			}
5672
			else
5673
			{
5674
				$updates['whereSet'] = array_values($updates);
5675
				$request = $smcFunc['db_query']('', '
0 ignored issues
show
Unused Code introduced by
$request 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...
5676
					UPDATE {db_prefix}' . $targetTable . '
5677
					SET ' . $newCol . ' = CASE ' .
5678
					implode('
5679
						', $cases) . '
5680
						ELSE NULL
5681
					END
5682
					WHERE ' . $oldCol . ' IN ({array_string:whereSet})',
5683
					$updates
5684
				);
5685
			}
5686
		}
5687
		else
5688
			$is_done = true;
5689
5690
		$_GET['a'] += $limit;
5691
		$step_progress['current'] = $_GET['a'];
5692
	}
5693
5694
	unset($_GET['a']);
5695
}
5696
5697
?>
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...
5698