PageRenderTime 12ms CodeModel.GetById 5ms app.highlight 73ms RepoModel.GetById 1ms app.codeStats 1ms

/other/upgrade.php

https://github.com/smf-portal/SMF2.1
PHP | 4523 lines | 3515 code | 601 blank | 407 comment | 730 complexity | 3fea4611b32c8325cd60afa9439758d6 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2
   3/**
   4 * Simple Machines Forum (SMF)
   5 *
   6 * @package SMF
   7 * @author Simple Machines http://www.simplemachines.org
   8 * @copyright 2012 Simple Machines
   9 * @license http://www.simplemachines.org/about/smf/license.php BSD
  10 *
  11 * @version 2.1 Alpha 1
  12 */
  13
  14// Version information...
  15define('SMF_VERSION', '2.1 Alpha 1');
  16define('SMF_LANG_VERSION', '2.1');
  17
  18$GLOBALS['required_php_version'] = '5.1.0';
  19$GLOBALS['required_mysql_version'] = '4.0.18';
  20
  21$databases = array(
  22	'mysql' => array(
  23		'name' => 'MySQL',
  24		'version' => '4.0.18',
  25		'version_check' => 'return min(mysql_get_server_info(), mysql_get_client_info());',
  26		'utf8_support' => true,
  27		'utf8_version' => '4.1.0',
  28		'utf8_version_check' => 'return mysql_get_server_info();',
  29		'alter_support' => true,
  30	),
  31	'postgresql' => array(
  32		'name' => 'PostgreSQL',
  33		'version' => '8.0',
  34		'version_check' => '$version = pg_version(); return $version[\'client\'];',
  35		'always_has_db' => true,
  36	),
  37	'sqlite' => array(
  38		'name' => 'SQLite',
  39		'version' => '1',
  40		'version_check' => 'return 1;',
  41		'always_has_db' => true,
  42	),
  43);
  44
  45// General options for the script.
  46$timeLimitThreshold = 3;
  47$upgrade_path = dirname(__FILE__);
  48$upgradeurl = $_SERVER['PHP_SELF'];
  49// Where the SMF images etc are kept.
  50$smfsite = 'http://www.simplemachines.org/smf';
  51// Disable the need for admins to login?
  52$disable_security = false;
  53// How long, in seconds, must admin be inactive to allow someone else to run?
  54$upcontext['inactive_timeout'] = 10;
  55
  56// All the steps in detail.
  57// Number,Name,Function,Progress Weight.
  58$upcontext['steps'] = array(
  59	0 => array(1, 'Login', 'WelcomeLogin', 2),
  60	1 => array(2, 'Upgrade Options', 'UpgradeOptions', 2),
  61	2 => array(3, 'Backup', 'BackupDatabase', 10),
  62	3 => array(4, 'Database Changes', 'DatabaseChanges', 70),
  63	// This is removed as it doesn't really work right at the moment.
  64	//4 => array(5, 'Cleanup Mods', 'CleanupMods', 10),
  65	4 => array(5, 'Delete Upgrade', 'DeleteUpgrade', 1),
  66);
  67// Just to remember which one has files in it.
  68$upcontext['database_step'] = 3;
  69@set_time_limit(600);
  70if (!ini_get('safe_mode'))
  71{
  72	ini_set('mysql.connect_timeout', -1); 
  73	ini_set('default_socket_timeout', 900);
  74}
  75// Clean the upgrade path if this is from the client.
  76if (!empty($_SERVER['argv']) && php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']))
  77	for ($i = 1; $i < $_SERVER['argc']; $i++)
  78	{
  79		if (preg_match('~^--path=(.+)$~', $_SERVER['argv'][$i], $match) != 0)
  80			$upgrade_path = substr($match[1], -1) == '/' ? substr($match[1], 0, -1) : $match[1];
  81	}
  82
  83// Are we from the client?
  84if (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']))
  85{
  86	$command_line = true;
  87	$disable_security = 1;
  88}
  89else
  90	$command_line = false;
  91
  92// Load this now just because we can.
  93require_once($upgrade_path . '/Settings.php');
  94
  95// Are we logged in?
  96if (isset($upgradeData))
  97{
  98	$upcontext['user'] = unserialize(base64_decode($upgradeData));
  99
 100	// Check for sensible values.
 101	if (empty($upcontext['user']['started']) || $upcontext['user']['started'] < time() - 86400)
 102		$upcontext['user']['started'] = time();
 103	if (empty($upcontext['user']['updated']) || $upcontext['user']['updated'] < time() - 86400)
 104		$upcontext['user']['updated'] = 0;
 105
 106	$upcontext['started'] = $upcontext['user']['started'];
 107	$upcontext['updated'] = $upcontext['user']['updated'];
 108}
 109
 110// Nothing sensible?
 111if (empty($upcontext['updated']))
 112{
 113	$upcontext['started'] = time();
 114	$upcontext['updated'] = 0;
 115	$upcontext['user'] = array(
 116		'id' => 0,
 117		'name' => 'Guest',
 118		'pass' => 0,
 119		'started' => $upcontext['started'],
 120		'updated' => $upcontext['updated'],
 121	);
 122}
 123
 124// Load up some essential data...
 125loadEssentialData();
 126
 127// Are we going to be mimic'ing SSI at this point?
 128if (isset($_GET['ssi']))
 129{
 130	require_once($sourcedir . '/Subs.php');
 131	require_once($sourcedir . '/Errors.php');
 132	require_once($sourcedir . '/Logging.php');
 133	require_once($sourcedir . '/Load.php');
 134	require_once($sourcedir . '/Security.php');
 135	require_once($sourcedir . '/Subs-Package.php');
 136
 137	loadUserSettings();
 138	loadPermissions();
 139}
 140
 141// All the non-SSI stuff.
 142if (!function_exists('ip2range'))
 143	require_once($sourcedir . '/Subs.php');
 144
 145if (!function_exists('un_htmlspecialchars'))
 146{
 147	function un_htmlspecialchars($string)
 148	{
 149		return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES)) + array('&#039;' => '\'', '&nbsp;' => ' '));
 150	}
 151}
 152
 153if (!function_exists('text2words'))
 154{
 155	function text2words($text)
 156	{
 157		global $smcFunc;
 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
 180if (!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		while ($file = readdir($dh))
 194		{
 195			if ($file != '.' && $file != '..' && $file != 'index.php' && $file != '.htaccess' && (!$type || substr($file, 0, strlen($type)) == $type))
 196				@unlink($cachedir . '/' . $file);
 197		}
 198		closedir($dh);
 199
 200		// Invalidate cache, to be sure!
 201		// ... as long as Load.php can be modified, anyway.
 202		@touch($sourcedir . '/' . 'Load.php');
 203		clearstatcache();
 204	}
 205}
 206
 207// MD5 Encryption.
 208if (!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// http://www.faqs.org/rfcs/rfc959.html
 224if (!class_exists('ftp_connection'))
 225{
 226	class ftp_connection
 227	{
 228		var $connection = 'no_connection', $error = false, $last_message, $pasv = array();
 229
 230		// Create a new FTP connection...
 231		function ftp_connection($ftp_server, $ftp_port = 21, $ftp_user = 'anonymous', $ftp_pass = 'ftpclient@simplemachines.org')
 232		{
 233			if ($ftp_server !== null)
 234				$this->connect($ftp_server, $ftp_port, $ftp_user, $ftp_pass);
 235		}
 236
 237		function connect($ftp_server, $ftp_port = 21, $ftp_user = 'anonymous', $ftp_pass = 'ftpclient@simplemachines.org')
 238		{
 239			if (substr($ftp_server, 0, 6) == 'ftp://')
 240				$ftp_server = substr($ftp_server, 6);
 241			elseif (substr($ftp_server, 0, 7) == 'ftps://')
 242				$ftp_server = 'ssl://' . substr($ftp_server, 7);
 243			if (substr($ftp_server, 0, 7) == 'http://')
 244				$ftp_server = substr($ftp_server, 7);
 245			$ftp_server = strtr($ftp_server, array('/' => '', ':' => '', '@' => ''));
 246
 247			// Connect to the FTP server.
 248			$this->connection = @fsockopen($ftp_server, $ftp_port, $err, $err, 5);
 249			if (!$this->connection)
 250			{
 251				$this->error = 'bad_server';
 252				return;
 253			}
 254
 255			// Get the welcome message...
 256			if (!$this->check_response(220))
 257			{
 258				$this->error = 'bad_response';
 259				return;
 260			}
 261
 262			// Send the username, it should ask for a password.
 263			fwrite($this->connection, 'USER ' . $ftp_user . "\r\n");
 264			if (!$this->check_response(331))
 265			{
 266				$this->error = 'bad_username';
 267				return;
 268			}
 269
 270			// Now send the password... and hope it goes okay.
 271			fwrite($this->connection, 'PASS ' . $ftp_pass . "\r\n");
 272			if (!$this->check_response(230))
 273			{
 274				$this->error = 'bad_password';
 275				return;
 276			}
 277		}
 278
 279		function chdir($ftp_path)
 280		{
 281			if (!is_resource($this->connection))
 282				return false;
 283
 284			// No slash on the end, please...
 285			if (substr($ftp_path, -1) == '/' && $ftp_path !== '/')
 286				$ftp_path = substr($ftp_path, 0, -1);
 287
 288			fwrite($this->connection, 'CWD ' . $ftp_path . "\r\n");
 289			if (!$this->check_response(250))
 290			{
 291				$this->error = 'bad_path';
 292				return false;
 293			}
 294
 295			return true;
 296		}
 297
 298		function chmod($ftp_file, $chmod)
 299		{
 300			if (!is_resource($this->connection))
 301				return false;
 302
 303			// Convert the chmod value from octal (0777) to text ("777").
 304			fwrite($this->connection, 'SITE CHMOD ' . decoct($chmod) . ' ' . $ftp_file . "\r\n");
 305			if (!$this->check_response(200))
 306			{
 307				$this->error = 'bad_file';
 308				return false;
 309			}
 310
 311			return true;
 312		}
 313
 314		function unlink($ftp_file)
 315		{
 316			// We are actually connected, right?
 317			if (!is_resource($this->connection))
 318				return false;
 319
 320			// Delete file X.
 321			fwrite($this->connection, 'DELE ' . $ftp_file . "\r\n");
 322			if (!$this->check_response(250))
 323			{
 324				fwrite($this->connection, 'RMD ' . $ftp_file . "\r\n");
 325
 326				// Still no love?
 327				if (!$this->check_response(250))
 328				{
 329					$this->error = 'bad_file';
 330					return false;
 331				}
 332			}
 333
 334			return true;
 335		}
 336
 337		function check_response($desired)
 338		{
 339			// Wait for a response that isn't continued with -, but don't wait too long.
 340			$time = time();
 341			do
 342				$this->last_message = fgets($this->connection, 1024);
 343			while (substr($this->last_message, 3, 1) != ' ' && time() - $time < 5);
 344
 345			// Was the desired response returned?
 346			return is_array($desired) ? in_array(substr($this->last_message, 0, 3), $desired) : substr($this->last_message, 0, 3) == $desired;
 347		}
 348
 349		function passive()
 350		{
 351			// We can't create a passive data connection without a primary one first being there.
 352			if (!is_resource($this->connection))
 353				return false;
 354
 355			// Request a passive connection - this means, we'll talk to you, you don't talk to us.
 356			@fwrite($this->connection, 'PASV' . "\r\n");
 357			$time = time();
 358			do
 359				$response = fgets($this->connection, 1024);
 360			while (substr($response, 3, 1) != ' ' && time() - $time < 5);
 361
 362			// If it's not 227, we weren't given an IP and port, which means it failed.
 363			if (substr($response, 0, 4) != '227 ')
 364			{
 365				$this->error = 'bad_response';
 366				return false;
 367			}
 368
 369			// Snatch the IP and port information, or die horribly trying...
 370			if (preg_match('~\((\d+),\s*(\d+),\s*(\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))\)~', $response, $match) == 0)
 371			{
 372				$this->error = 'bad_response';
 373				return false;
 374			}
 375
 376			// This is pretty simple - store it for later use ;).
 377			$this->pasv = array('ip' => $match[1] . '.' . $match[2] . '.' . $match[3] . '.' . $match[4], 'port' => $match[5] * 256 + $match[6]);
 378
 379			return true;
 380		}
 381
 382		function create_file($ftp_file)
 383		{
 384			// First, we have to be connected... very important.
 385			if (!is_resource($this->connection))
 386				return false;
 387
 388			// I'd like one passive mode, please!
 389			if (!$this->passive())
 390				return false;
 391
 392			// Seems logical enough, so far...
 393			fwrite($this->connection, 'STOR ' . $ftp_file . "\r\n");
 394
 395			// Okay, now we connect to the data port.  If it doesn't work out, it's probably "file already exists", etc.
 396			$fp = @fsockopen($this->pasv['ip'], $this->pasv['port'], $err, $err, 5);
 397			if (!$fp || !$this->check_response(150))
 398			{
 399				$this->error = 'bad_file';
 400				@fclose($fp);
 401				return false;
 402			}
 403
 404			// This may look strange, but we're just closing it to indicate a zero-byte upload.
 405			fclose($fp);
 406			if (!$this->check_response(226))
 407			{
 408				$this->error = 'bad_response';
 409				return false;
 410			}
 411
 412			return true;
 413		}
 414
 415		function list_dir($ftp_path = '', $search = false)
 416		{
 417			// Are we even connected...?
 418			if (!is_resource($this->connection))
 419				return false;
 420
 421			// Passive... non-agressive...
 422			if (!$this->passive())
 423				return false;
 424
 425			// Get the listing!
 426			fwrite($this->connection, 'LIST -1' . ($search ? 'R' : '') . ($ftp_path == '' ? '' : ' ' . $ftp_path) . "\r\n");
 427
 428			// Connect, assuming we've got a connection.
 429			$fp = @fsockopen($this->pasv['ip'], $this->pasv['port'], $err, $err, 5);
 430			if (!$fp || !$this->check_response(array(150, 125)))
 431			{
 432				$this->error = 'bad_response';
 433				@fclose($fp);
 434				return false;
 435			}
 436
 437			// Read in the file listing.
 438			$data = '';
 439			while (!feof($fp))
 440				$data .= fread($fp, 4096);
 441			fclose($fp);
 442
 443			// Everything go okay?
 444			if (!$this->check_response(226))
 445			{
 446				$this->error = 'bad_response';
 447				return false;
 448			}
 449
 450			return $data;
 451		}
 452
 453		function locate($file, $listing = null)
 454		{
 455			if ($listing === null)
 456				$listing = $this->list_dir('', true);
 457			$listing = explode("\n", $listing);
 458
 459			@fwrite($this->connection, 'PWD' . "\r\n");
 460			$time = time();
 461			do
 462				$response = fgets($this->connection, 1024);
 463			while (substr($response, 3, 1) != ' ' && time() - $time < 5);
 464
 465			// Check for 257!
 466			if (preg_match('~^257 "(.+?)" ~', $response, $match) != 0)
 467				$current_dir = strtr($match[1], array('""' => '"'));
 468			else
 469				$current_dir = '';
 470
 471			for ($i = 0, $n = count($listing); $i < $n; $i++)
 472			{
 473				if (trim($listing[$i]) == '' && isset($listing[$i + 1]))
 474				{
 475					$current_dir = substr(trim($listing[++$i]), 0, -1);
 476					$i++;
 477				}
 478
 479				// Okay, this file's name is:
 480				$listing[$i] = $current_dir . '/' . trim(strlen($listing[$i]) > 30 ? strrchr($listing[$i], ' ') : $listing[$i]);
 481
 482				if (substr($file, 0, 1) == '*' && substr($listing[$i], -(strlen($file) - 1)) == substr($file, 1))
 483					return $listing[$i];
 484				if (substr($file, -1) == '*' && substr($listing[$i], 0, strlen($file) - 1) == substr($file, 0, -1))
 485					return $listing[$i];
 486				if (basename($listing[$i]) == $file || $listing[$i] == $file)
 487					return $listing[$i];
 488			}
 489
 490			return false;
 491		}
 492
 493		function create_dir($ftp_dir)
 494		{
 495			// We must be connected to the server to do something.
 496			if (!is_resource($this->connection))
 497				return false;
 498
 499			// Make this new beautiful directory!
 500			fwrite($this->connection, 'MKD ' . $ftp_dir . "\r\n");
 501			if (!$this->check_response(257))
 502			{
 503				$this->error = 'bad_file';
 504				return false;
 505			}
 506
 507			return true;
 508		}
 509
 510		function detect_path($filesystem_path, $lookup_file = null)
 511		{
 512			$username = '';
 513
 514			if (isset($_SERVER['DOCUMENT_ROOT']))
 515			{
 516				if (preg_match('~^/home[2]?/([^/]+?)/public_html~', $_SERVER['DOCUMENT_ROOT'], $match))
 517				{
 518					$username = $match[1];
 519
 520					$path = strtr($_SERVER['DOCUMENT_ROOT'], array('/home/' . $match[1] . '/' => '', '/home2/' . $match[1] . '/' => ''));
 521
 522					if (substr($path, -1) == '/')
 523						$path = substr($path, 0, -1);
 524
 525					if (strlen(dirname($_SERVER['PHP_SELF'])) > 1)
 526						$path .= dirname($_SERVER['PHP_SELF']);
 527				}
 528				elseif (substr($filesystem_path, 0, 9) == '/var/www/')
 529					$path = substr($filesystem_path, 8);
 530				else
 531					$path = strtr(strtr($filesystem_path, array('\\' => '/')), array($_SERVER['DOCUMENT_ROOT'] => ''));
 532			}
 533			else
 534				$path = '';
 535
 536			if (is_resource($this->connection) && $this->list_dir($path) == '')
 537			{
 538				$data = $this->list_dir('', true);
 539
 540				if ($lookup_file === null)
 541					$lookup_file = $_SERVER['PHP_SELF'];
 542
 543				$found_path = dirname($this->locate('*' . basename(dirname($lookup_file)) . '/' . basename($lookup_file), $data));
 544				if ($found_path == false)
 545					$found_path = dirname($this->locate(basename($lookup_file)));
 546				if ($found_path != false)
 547					$path = $found_path;
 548			}
 549			elseif (is_resource($this->connection))
 550				$found_path = true;
 551
 552			return array($username, $path, isset($found_path));
 553		}
 554
 555		function close()
 556		{
 557			// Goodbye!
 558			fwrite($this->connection, 'QUIT' . "\r\n");
 559			fclose($this->connection);
 560
 561			return true;
 562		}
 563	}
 564}
 565
 566// Have we got tracking data - if so use it (It will be clean!)
 567if (isset($_GET['data']))
 568{
 569	$upcontext['upgrade_status'] = unserialize(base64_decode($_GET['data']));
 570	$upcontext['current_step'] = $upcontext['upgrade_status']['curstep'];
 571	$upcontext['language'] = $upcontext['upgrade_status']['lang'];
 572	$upcontext['rid'] = $upcontext['upgrade_status']['rid'];
 573	$is_debug = $upcontext['upgrade_status']['debug'];
 574	$support_js = $upcontext['upgrade_status']['js'];
 575
 576	// Load the language.
 577	if (file_exists($boarddir . '/Themes/default/languages/Install.' . $upcontext['language'] . '.php'))
 578		require_once($boarddir . '/Themes/default/languages/Install.' . $upcontext['language'] . '.php');
 579}
 580// Set the defaults.
 581else
 582{
 583	$upcontext['current_step'] = 0;
 584	$upcontext['rid'] = mt_rand(0, 5000);
 585	$upcontext['upgrade_status'] = array(
 586		'curstep' => 0,
 587		'lang' => isset($_GET['lang']) ? $_GET['lang'] : basename($language, '.lng'),
 588		'rid' => $upcontext['rid'],
 589		'pass' => 0,
 590		'debug' => 0,
 591		'js' => 0,
 592	);
 593	$upcontext['language'] = $upcontext['upgrade_status']['lang'];
 594}
 595
 596// Don't do security check if on Yabbse
 597if (!isset($modSettings['smfVersion']))
 598	$disable_security = true;
 599
 600// If this isn't the first stage see whether they are logging in and resuming.
 601if ($upcontext['current_step'] != 0 || !empty($upcontext['user']['step']))
 602	checkLogin();
 603
 604// This only exists if we're on SMF ;)
 605if (isset($modSettings['smfVersion']))
 606{
 607	$request = $smcFunc['db_query']('', '
 608		SELECT variable, value
 609		FROM {db_prefix}themes
 610		WHERE id_theme = {int:id_theme}
 611			AND variable IN ({string:theme_url}, {string:theme_dir}, {string:images_url})',
 612		array(
 613			'id_theme' => 1,
 614			'theme_url' => 'theme_url',
 615			'theme_dir' => 'theme_dir',
 616			'images_url' => 'images_url',
 617			'db_error_skip' => true,
 618		)
 619	);
 620	while ($row = $smcFunc['db_fetch_assoc']($request))
 621		$modSettings[$row['variable']] = $row['value'];
 622	$smcFunc['db_free_result']($request);
 623}
 624
 625if (!isset($modSettings['theme_url']))
 626{
 627	$modSettings['theme_dir'] = $boarddir . '/Themes/default';
 628	$modSettings['theme_url'] = 'Themes/default';
 629	$modSettings['images_url'] = 'Themes/default/images';
 630}
 631if (!isset($settings['default_theme_url']))
 632	$settings['default_theme_url'] = $modSettings['theme_url'];
 633if (!isset($settings['default_theme_dir']))
 634	$settings['default_theme_dir'] = $modSettings['theme_dir'];
 635
 636$upcontext['is_large_forum'] = (empty($modSettings['smfVersion']) || $modSettings['smfVersion'] <= '1.1 RC1') && !empty($modSettings['totalMessages']) && $modSettings['totalMessages'] > 75000;
 637// Default title...
 638$upcontext['page_title'] = isset($modSettings['smfVersion']) ? 'Updating Your SMF Install!' : 'Upgrading from YaBB SE!';
 639
 640$upcontext['right_to_left'] = isset($txt['lang_rtl']) ? $txt['lang_rtl'] : false;
 641
 642if ($command_line)
 643	cmdStep0();
 644
 645// Don't error if we're using xml.
 646if (isset($_GET['xml']))
 647	$upcontext['return_error'] = true;
 648
 649// Loop through all the steps doing each one as required.
 650$upcontext['overall_percent'] = 0;
 651foreach ($upcontext['steps'] as $num => $step)
 652{
 653	if ($num >= $upcontext['current_step'])
 654	{
 655		// The current weight of this step in terms of overall progress.
 656		$upcontext['step_weight'] = $step[3];
 657		// Make sure we reset the skip button.
 658		$upcontext['skip'] = false;
 659
 660		// We cannot proceed if we're not logged in.
 661		if ($num != 0 && !$disable_security && $upcontext['user']['pass'] != $upcontext['upgrade_status']['pass'])
 662		{
 663			$upcontext['steps'][0][2]();
 664			break;
 665		}
 666
 667		// Call the step and if it returns false that means pause!
 668		if (function_exists($step[2]) && $step[2]() === false)
 669			break;
 670		elseif (function_exists($step[2]))
 671			$upcontext['current_step']++;
 672	}
 673	$upcontext['overall_percent'] += $step[3];
 674}
 675
 676upgradeExit();
 677
 678// Exit the upgrade script.
 679function upgradeExit($fallThrough = false)
 680{
 681	global $upcontext, $upgradeurl, $boarddir, $command_line;
 682
 683	// Save where we are...
 684	if (!empty($upcontext['current_step']) && !empty($upcontext['user']['id']))
 685	{
 686		$upcontext['user']['step'] = $upcontext['current_step'];
 687		$upcontext['user']['substep'] = $_GET['substep'];
 688		$upcontext['user']['updated'] = time();
 689		$upgradeData = base64_encode(serialize($upcontext['user']));
 690		copy($boarddir . '/Settings.php', $boarddir . '/Settings_bak.php');
 691		changeSettings(array('upgradeData' => '"' . $upgradeData . '"'));
 692		updateLastError();
 693	}
 694
 695	// Handle the progress of the step, if any.
 696	if (!empty($upcontext['step_progress']) && isset($upcontext['steps'][$upcontext['current_step']]))
 697	{
 698		$upcontext['step_progress'] = round($upcontext['step_progress'], 1);
 699		$upcontext['overall_percent'] += $upcontext['step_progress'] * ($upcontext['steps'][$upcontext['current_step']][3] / 100);
 700	}
 701	$upcontext['overall_percent'] = (int) $upcontext['overall_percent'];
 702
 703	// We usually dump our templates out.
 704	if (!$fallThrough)
 705	{
 706		// This should not happen my dear... HELP ME DEVELOPERS!!
 707		if (!empty($command_line))
 708		{
 709			if (function_exists('debug_print_backtrace'))
 710				debug_print_backtrace();
 711
 712			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.';
 713			flush();
 714			die();
 715		}
 716
 717		if (!isset($_GET['xml']))
 718			template_upgrade_above();
 719		else
 720		{
 721			header('Content-Type: text/xml; charset=ISO-8859-1');
 722			// Sadly we need to retain the $_GET data thanks to the old upgrade scripts.
 723			$upcontext['get_data'] = array();
 724			foreach ($_GET as $k => $v)
 725			{
 726				if (substr($k, 0, 3) != 'amp' && !in_array($k, array('xml', 'substep', 'lang', 'data', 'step', 'filecount')))
 727				{
 728					$upcontext['get_data'][$k] = $v;
 729				}
 730			}
 731			template_xml_above();
 732		}
 733
 734		// Call the template.
 735		if (isset($upcontext['sub_template']))
 736		{
 737			$upcontext['upgrade_status']['curstep'] = $upcontext['current_step'];
 738			$upcontext['form_url'] = $upgradeurl . '?step=' . $upcontext['current_step'] . '&amp;substep=' . $_GET['substep'] . '&amp;data=' . base64_encode(serialize($upcontext['upgrade_status']));
 739
 740			// Custom stuff to pass back?
 741			if (!empty($upcontext['query_string']))
 742				$upcontext['form_url'] .= $upcontext['query_string'];
 743
 744			call_user_func('template_' . $upcontext['sub_template']);
 745		}
 746
 747		// Was there an error?
 748		if (!empty($upcontext['forced_error_message']))
 749			echo $upcontext['forced_error_message'];
 750
 751		// Show the footer.
 752		if (!isset($_GET['xml']))
 753			template_upgrade_below();
 754		else
 755			template_xml_below();
 756	}
 757
 758	// Bang - gone!
 759	die();
 760}
 761
 762// Used to direct the user to another location.
 763function redirectLocation($location, $addForm = true)
 764{
 765	global $upgradeurl, $upcontext, $command_line;
 766
 767	// Command line users can't be redirected.
 768	if ($command_line)
 769		upgradeExit(true);
 770
 771	// Are we providing the core info?
 772	if ($addForm)
 773	{
 774		$upcontext['upgrade_status']['curstep'] = $upcontext['current_step'];
 775		$location = $upgradeurl . '?step=' . $upcontext['current_step'] . '&substep=' . $_GET['substep'] . '&data=' . base64_encode(serialize($upcontext['upgrade_status'])) . $location;
 776	}
 777
 778	while (@ob_end_clean());
 779	header('Location: ' . strtr($location, array('&amp;' => '&')));
 780
 781	// Exit - saving status as we go.
 782	upgradeExit(true);
 783}
 784
 785// Load all essential data and connect to the DB as this is pre SSI.php
 786function loadEssentialData()
 787{
 788	global $db_server, $db_user, $db_passwd, $db_name, $db_connection, $db_prefix, $db_character_set, $db_type;
 789	global $modSettings, $sourcedir, $smcFunc, $upcontext;
 790
 791	// Do the non-SSI stuff...
 792	@set_magic_quotes_runtime(0);
 793	error_reporting(E_ALL);
 794	define('SMF', 1);
 795
 796	// Start the session.
 797	if (@ini_get('session.save_handler') == 'user')
 798		@ini_set('session.save_handler', 'files');
 799	@session_start();
 800
 801	if (empty($smcFunc))
 802		$smcFunc = array();
 803
 804	// Check we don't need some compatibility.
 805	if (@version_compare(PHP_VERSION, '5.1', '<='))
 806		require_once($sourcedir . '/Subs-Compat.php');
 807
 808	// Initialize everything...
 809	initialize_inputs();
 810
 811	// Get the database going!
 812	if (empty($db_type))
 813		$db_type = 'mysql';
 814	if (file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php'))
 815	{
 816		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
 817
 818		// Make the connection...
 819		$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('non_fatal' => true));
 820
 821		// Oh dear god!!
 822		if ($db_connection === null)
 823			die('Unable to connect to database - please check username and password are correct in Settings.php');
 824
 825		if ($db_type == 'mysql' && isset($db_character_set) && preg_match('~^\w+$~', $db_character_set) === 1)
 826			$smcFunc['db_query']('', '
 827			SET NAMES ' . $db_character_set,
 828			array(
 829				'db_error_skip' => true,
 830			)
 831		);
 832
 833		// Load the modSettings data...
 834		$request = $smcFunc['db_query']('', '
 835			SELECT variable, value
 836			FROM {db_prefix}settings',
 837			array(
 838				'db_error_skip' => true,
 839			)
 840		);
 841		$modSettings = array();
 842		while ($row = $smcFunc['db_fetch_assoc']($request))
 843			$modSettings[$row['variable']] = $row['value'];
 844		$smcFunc['db_free_result']($request);
 845	}
 846	else
 847	{
 848		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.');
 849	}
 850
 851	// If they don't have the file, they're going to get a warning anyway so we won't need to clean request vars.
 852	if (file_exists($sourcedir . '/QueryString.php'))
 853	{
 854		require_once($sourcedir . '/QueryString.php');
 855		cleanRequest();
 856	}
 857
 858	if (!isset($_GET['substep']))
 859		$_GET['substep'] = 0;
 860}
 861
 862function initialize_inputs()
 863{
 864	global $sourcedir, $start_time, $upcontext, $db_type;
 865
 866	$start_time = time();
 867
 868	umask(0);
 869
 870	// Fun.  Low PHP version...
 871	if (!isset($_GET))
 872	{
 873		$GLOBALS['_GET']['step'] = 0;
 874		return;
 875	}
 876
 877	ob_start();
 878
 879	// Better to upgrade cleanly and fall apart than to screw everything up if things take too long.
 880	ignore_user_abort(true);
 881
 882	// This is really quite simple; if ?delete is on the URL, delete the upgrader...
 883	if (isset($_GET['delete']))
 884	{
 885		@unlink(__FILE__);
 886
 887		// And the extra little files ;).
 888		@unlink(dirname(__FILE__) . '/upgrade_1-0.sql');
 889		@unlink(dirname(__FILE__) . '/upgrade_1-1.sql');
 890		@unlink(dirname(__FILE__) . '/upgrade_2-0_' . $db_type . '.sql');
 891		@unlink(dirname(__FILE__) . '/upgrade_2-1_' . $db_type . '.sql');
 892		@unlink(dirname(__FILE__) . '/webinstall.php');
 893
 894		$dh = opendir(dirname(__FILE__));
 895		while ($file = readdir($dh))
 896		{
 897			if (preg_match('~upgrade_\d-\d_([A-Za-z])+\.sql~i', $file, $matches) && isset($matches[1]))
 898				@unlink(dirname(__FILE__) . '/' . $file);
 899		}
 900		closedir($dh);
 901
 902		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');
 903		exit;
 904	}
 905
 906	// Are we calling the backup css file?
 907	if (isset($_GET['infile_css']))
 908	{
 909		header('Content-Type: text/css');
 910		template_css();
 911		exit;
 912	}
 913
 914	// Anybody home?
 915	if (!isset($_GET['xml']))
 916	{
 917		$upcontext['remote_files_available'] = false;
 918		$test = @fsockopen('www.simplemachines.org', 80, $errno, $errstr, 1);
 919		if ($test)
 920			$upcontext['remote_files_available'] = true;
 921		@fclose($test);
 922	}
 923
 924	// Something is causing this to happen, and it's annoying.  Stop it.
 925	$temp = 'upgrade_php?step';
 926	while (strlen($temp) > 4)
 927	{
 928		if (isset($_GET[$temp]))
 929			unset($_GET[$temp]);
 930		$temp = substr($temp, 1);
 931	}
 932
 933	// Force a step, defaulting to 0.
 934	$_GET['step'] = (int) @$_GET['step'];
 935	$_GET['substep'] = (int) @$_GET['substep'];
 936}
 937
 938// Step 0 - Let's welcome them in and ask them to login!
 939function WelcomeLogin()
 940{
 941	global $boarddir, $sourcedir, $db_prefix, $language, $modSettings, $cachedir, $upgradeurl, $upcontext, $disable_security;
 942	global $smcFunc, $db_type, $databases, $txt;
 943
 944	$upcontext['sub_template'] = 'welcome_message';
 945
 946	// Check for some key files - one template, one language, and a new and an old source file.
 947	$check = @file_exists($boarddir . '/Themes/default/index.template.php')
 948		&& @file_exists($sourcedir . '/QueryString.php')
 949		&& @file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php')
 950		&& @file_exists(dirname(__FILE__) . '/upgrade_2-1_' . $db_type . '.sql');
 951
 952	// Need legacy scripts?
 953	if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < 2.1)
 954		$check &= @file_exists(dirname(__FILE__) . '/upgrade_2-0_' . $db_type . '.sql');
 955	if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < 2.0)
 956		$check &= @file_exists(dirname(__FILE__) . '/upgrade_1-1.sql');
 957	if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < 1.1)
 958		$check &= @file_exists(dirname(__FILE__) . '/upgrade_1-0.sql');
 959
 960	if (!$check)
 961		// 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.
 962		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.');
 963
 964	// Do they meet the install requirements?
 965	if (!php_version_check())
 966		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.');
 967
 968	if (!db_version_check())
 969		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.');
 970
 971	// Do they have ALTER privileges?
 972	if (!empty($databases[$db_type]['alter_support']) && $smcFunc['db_query']('alter_boards', 'ALTER TABLE {db_prefix}boards ORDER BY id_board', array()) === false)
 973		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.');
 974
 975	// Do a quick version spot check.
 976	$temp = substr(@implode('', @file($boarddir . '/index.php')), 0, 4096);
 977	preg_match('~\*\s@version\s+(.+)[\s]{2}~i', $temp, $match);
 978	if (empty($match[1]) || $match[1] != SMF_VERSION)
 979		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.');
 980
 981	// What absolutely needs to be writable?
 982	$writable_files = array(
 983		$boarddir . '/Settings.php',
 984		$boarddir . '/Settings_bak.php',
 985	);
 986
 987	require_once($sourcedir . '/Security.php');
 988	createToken('login');
 989
 990	// Check the cache directory.
 991	$cachedir_temp = empty($cachedir) ? $boarddir . '/cache' : $cachedir;
 992	if (!file_exists($cachedir_temp))
 993		@mkdir($cachedir_temp);
 994	if (!file_exists($cachedir_temp))
 995		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.');
 996
 997	if (!file_exists($boarddir . '/Themes/default/languages/index.' . $upcontext['language'] . '.php') && !isset($modSettings['smfVersion']) && !isset($_GET['lang']))
 998		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>.');
 999	elseif (!isset($_GET['skiplang']))
1000	{
1001		$temp = substr(@implode('', @file($boarddir . '/Themes/default/languages/index.' . $upcontext['language'] . '.php')), 0, 4096);
1002		preg_match('~(?://|/\*)\s*Version:\s+(.+?);\s*index(?:[\s]{2}|\*/)~i', $temp, $match);
1003
1004		if (empty($match[1]) || $match[1] != SMF_LANG_VERSION)
1005			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>]');
1006	}
1007
1008	// This needs to exist!
1009	if (!file_exists($boarddir . '/Themes/default/languages/Install.' . $upcontext['language'] . '.php'))
1010		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>]');
1011	else
1012		require_once($boarddir . '/Themes/default/languages/Install.' . $upcontext['language'] . '.php');
1013
1014	if (!makeFilesWritable($writable_files))
1015		return false;
1016
1017	// Check agreement.txt. (it may not exist, in which case $boarddir must be writable.)
1018	if (isset($modSettings['agreement']) && (!is_writable($boarddir) || file_exists($boarddir . '/agreement.txt')) && !is_writable($boarddir . '/agreement.txt'))
1019		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.');
1020
1021	// Upgrade the agreement.
1022	elseif (isset($modSettings['agreement']))
1023	{
1024		$fp = fopen($boarddir . '/agreement.txt', 'w');
1025		fwrite($fp, $modSettings['agreement']);
1026		fclose($fp);
1027	}
1028
1029	// We're going to check that their board dir setting is right incase they've been moving stuff around.
1030	if (strtr($boarddir, array('/' => '', '\\' => '')) != strtr(dirname(__FILE__), array('/' => '', '\\' => '')))
1031		$upcontext['warning'] = '
1032			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 />
1033			<ul>
1034				<li>Board Directory: ' . $boarddir . '</li>
1035				<li>Source Directory: ' . $boarddir . '</li>
1036				<li>Cache Directory: ' . $cachedir_temp . '</li>
1037			</ul>
1038			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.';
1039
1040	// Either we're logged in or we're going to present the login.
1041	if (checkLogin())
1042		return true;
1043
1044	return false;
1045}
1046
1047// Step 0.5: Does the login work?
1048function checkLogin()
1049{
1050	global $boarddir, $sourcedir, $db_prefix, $language, $modSettings, $cachedir, $upgradeurl, $upcontext, $disable_security;
1051	global $smcFunc, $db_type, $databases, $support_js, $txt;
1052
1053	// Are we trying to login?
1054	if (isset($_POST['contbutt']) && (!empty($_POST['user']) || $disable_security))
1055	{
1056		// If we've disabled security pick a suitable name!
1057		if (empty($_POST['user']))
1058			$_POST['user'] = 'Administrator';
1059
1060		// Before 2.0 these column names were different!
1061		$oldDB = false;
1062		if (empty($db_type) || $db_type == 'mysql')
1063		{
1064			$request = $smcFunc['db_query']('', '
1065				SHOW COLUMNS
1066				FROM {db_prefix}members
1067				LIKE {string:member_name}',
1068				array(
1069					'member_name' => 'memberName',
1070					'db_error_skip' => true,
1071				)
1072			);
1073			if ($smcFunc['db_num_rows']($request) != 0)
1074				$oldDB = true;
1075			$smcFunc['db_free_result']($request);
1076		}
1077
1078		// Get what we believe to be their details.
1079		if (!$disable_security)
1080		{
1081			if ($oldDB)
1082				$request = $smcFunc['db_query']('', '
1083					SELECT id_member, memberName AS member_name, passwd, id_group,
1084					additionalGroups AS additional_groups, lngfile
1085					FROM {db_prefix}members
1086					WHERE memberName = {string:member_name}',
1087					array(
1088						'member_name' => $_POST['user'],
1089						'db_error_skip' => true,
1090					)
1091				);
1092			else
1093				$request = $smcFunc['db_query']('', '
1094					SELECT id_member, member_name, passwd, id_group, additional_groups, lngfile
1095					FROM {db_prefix}members
1096					WHERE member_name = {string:member_name}',
1097					array(
1098						'member_name' => $_POST['user'],
1099						'db_error_skip' => true,
1100					)
1101				);
1102			if ($smcFunc['db_num_rows']($request) != 0)
1103			{
1104				list ($id_member, $name, $password, $id_group, $addGroups, $user_language) = $smcFunc['db_fetch_row']($request);
1105
1106				$groups = explode(',', $addGroups);
1107				$groups[] = $id_group;
1108
1109				foreach ($groups as $k => $v)
1110					$groups[$k] = (int) $v;
1111
1112				// Figure out the password using SMF's encryption - if what they typed is right.
1113				if (isset($_REQUEST['hash_passwrd']) && strlen($_REQUEST['hash_passwrd']) == 40)
1114				{
1115					// Challenge passed.
1116					if ($_REQUEST['hash_passwrd'] == sha1($password . $upcontext['rid']))
1117						$sha_passwd = $password;
1118				}
1119				else
1120					$sha_passwd = sha1(strtolower($name) . un_htmlspecialchars($_REQUEST['passwrd']));
1121			}
1122			else
1123				$upcontext['username_incorrect'] = true;
1124			$smcFunc['db_free_result']($request);
1125		}
1126		$upcontext['username'] = $_POST['user'];
1127
1128		// Track whether javascript works!
1129		if (!empty($_POST['js_works']))
1130		{
1131			$upcontext['upgrade_status']['js'] = 1;
1132			$support_js = 1;
1133		}
1134		else
1135			$support_js = 0;
1136
1137		// Note down the version we are coming from.
1138		if (!empty($modSettings['smfVersion']) && empty($upcontext['user']['version']))
1139			$upcontext['user']['version'] = $modSettings['smfVersion'];
1140
1141		// Didn't get anywhere?
1142		if ((empty($sha_passwd) || $password != $sha_passwd) && empty($upcontext['username_incorrect']) && !$disable_security)
1143		{
1144			// MD5?
1145			$md5pass = md5_hmac($_REQUEST['passwrd'], strtolower($_POST['user']));
1146			if ($md5pass != $password)
1147			{
1148				$upcontext['password_failed'] = true;
1149				// Disable the hashing this time.
1150				$upcontext['disable_login_hashing'] = true;
1151			}
1152		}
1153
1154		if ((empty($upcontext['password_failed']) && !empty($name)) || $disable_security)
1155		{
1156			// Set the password.
1157			if (!$disable_security)
1158			{
1159				// Do we actually have permission?
1160				if (!in_array(1, $groups))
1161				{
1162					$request = $smcFunc['db_query']('', '
1163						SELECT permission
1164						FROM {db_prefix}permissions
1165						WHERE id_group IN ({array_int:groups})
1166							AND permission = {string:admin_forum}',
1167						array(
1168							'groups' => $groups,
1169							'admin_forum' => 'admin_forum',
1170							'db_error_skip' => true,
1171						)
1172					);
1173					if ($smcFunc['db_num_rows']($request) == 0)
1174						return throw_error('You need to be an admin to perform an upgrade!');
1175					$smcFunc['db_free_result']($request);
1176				}
1177
1178				$upcontext['user']['id'] = $id_member;
1179				$upcontext['user']['name'] = $name;
1180			}
1181			else
1182			{
1183				$upcontext['user']['id'] = 1;
1184				$upcontext['user']['name'] = 'Administrator';
1185			}
1186			$upcontext['user']['pass'] = mt_rand(0,60000);
1187			// This basically is used to match the GET variables to Settings.php.
1188			$upcontext['upgrade_status']['pass'] = $upcontext['user']['pass'];
1189
1190			// Set the language to that of the user?
1191			if (isset($user_language) && $user_language != $upcontext['language'] && file_exists($boarddir . '/Themes/default/languages/index.' . basename($user_language, '.lng') . '.php'))
1192			{
1193				$user_language = basename($user_language, '.lng');
1194				$temp = substr(@implode('', @file($boarddir . '/Themes/default/languages/index.' . $user_language . '.php')), 0, 4096);
1195				preg_match('~(?://|/\*)\s*Version:\s+(.+?);\s*index(?:[\s]{2}|\*/)~i', $temp, $match);
1196
1197				if (empty($match[1]) || $match[1] != SMF_LANG_VERSION)
1198					$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'] . '.';
1199				elseif (!file_exists($boarddir . '/Themes/default/languages/Install.' . basename($user_language, '.lng') . '.php'))
1200					$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'] . '.';
1201				else
1202				{
1203					// Set this as the new language.
1204					$upcontext['language'] = $user_language;
1205					$upcontext['upgrade_status']['lang'] = $upcontext['language'];
1206
1207					// Include the file.
1208					require_once($boarddir . '/Themes/default/languages/Install.' . $user_language . '.php');
1209				}
1210			}
1211
1212			// If we're resuming set the step and substep to be correct.
1213			if (isset($_POST['cont']))
1214			{
1215				$upcontext['current_step'] = $upcontext['user']['step'];
1216				$_GET['substep'] = $upcontext['user']['substep'];
1217			}
1218
1219			return true;
1220		}
1221	}
1222
1223	return false;
1224}
1225
1226// Step 1: Do the maintenance and backup.
1227function UpgradeOptions()
1228{
1229	global $db_prefix, $command_line, $modSettings, $is_debug, $smcFunc;
1230	global $boarddir, $boardurl, $sourcedir, $maintenance, $mmessage, $cachedir, $upcontext, $db_type;
1231
1232	$upcontext['sub_template'] = 'upgrade_options';
1233	$upcontext['page_title'] = 'Upgrade Options';
1234
1235	// If we've not submitted then we're done.
1236	if (empty($_POST['upcont']))
1237		return false;
1238
1239	// Firstly, if they're enabling SM stat collection just do it.
1240	if (!empty($_POST['stats']) && substr($boardurl, 0, 16) != 'http://localhost' && empty($modSettings['allow_sm_stats']))
1241	{
1242		// Attempt to register the site etc.
1243		$fp = @fsockopen('www.simplemachines.org', 80, $errno, $errstr);
1244		if ($fp)
1245		{
1246			$out = 'GET /smf/stats/register_stats.php?site=' . base64_encode($boardurl) . ' HTTP/1.1' . "\r\n";
1247			$out .= 'Host: www.simplemachines.org' . "\r\n";
1248			$out .= 'Connection: Close' . "\r\n\r\n";
1249			fwrite($fp, $out);
1250
1251			$return_data = '';
1252			while (!feof($fp))
1253				$return_data .= fgets($fp, 128);
1254
1255			fclose($fp);
1256
1257			// Get the unique site ID.
1258			preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1259
1260			if (!empty($ID[1]))
1261				$smcFunc['db_insert']('replace',
1262					$db_prefix . 'settings',
1263					array('variable' => 'string', 'value' => 'string'),
1264					array('allow_sm_stats', $ID[1]),
1265					array('variable')
1266				);
1267		}
1268	}
1269	else
1270		$smcFunc['db_query']('', '
1271			DELETE FROM {db_prefix}settings
1272			WHERE variable = {string:allow_sm_stats}',
1273			array(
1274				'allow_sm_stats' => 'allow_sm_stats',
1275				'db_error_skip' => true,
1276			)
1277		);
1278
1279	// Emptying the error log?
1280	if (!empty($_POST['empty_error']))
1281		$smcFunc['db_query']('truncate_table', '
1282			TRUNCATE {db_prefix}log_errors',
1283			array(
1284			)
1285		);
1286
1287	$changes = array();
1288
1289	// If we're overriding the language follow it through.
1290	if (isset($_GET['lang']) && file_exists($boarddir . '/Themes/default/languages/index.' . $_GET['lang'] . '.php'))
1291		$changes['language'] = '\'' . $_GET['lang'] . '\'';
1292
1293	if (!empty($_POST['maint']))
1294	{
1295		$changes['maintenance'] = '2';
1296		// Remember what it was...
1297		$upcontext['user']['main'] = $maintenance;
1298
1299		if (!empty($_POST['maintitle']))
1300		{
1301			$changes['mtitle'] = '\'' . addslashes($_POST['maintitle']) . '\'';
1302			$changes['mmessage'] = '\'' . addslashes($_POST['mainmessage']) . '\'';
1303		}
1304		else
1305		{
1306			$changes['mtitle'] = '\'Upgrading the forum...\'';
1307			$changes['mmessage'] = '\'Don\\\'t worry, we will be back shortly with an updated forum.  It will only be a minute ;).\'';
1308		}
1309	}
1310
1311	if ($command_line)
1312		echo ' * Updating Settings.php...';
1313
1314	// Backup the current one first.
1315	copy($boarddir . '/Settings.php', $boarddir . '/Settings_bak.php');
1316
1317	// Fix some old paths.
1318	if (substr($boarddir, 0, 1) == '.')
1319		$changes['boarddir'] = '\'' . fixRelativePath($boarddir) . '\'';
1320
1321	if (substr($sourcedir, 0, 1) == '.')
1322		$changes['sourcedir'] = '\'' . fixRelativePath($sourcedir) . '\'';
1323
1324	if (empty($cachedir) || substr($cachedir, 0, 1) == '.')
1325		$changes['cachedir'] = '\'' . fixRelativePath($boarddir) . '/cache\'';
1326
1327	// Not had the database type added before?
1328	if (empty($db_type))
1329		$changes['db_type'] = 'mysql';
1330
1331	// @todo Maybe change the cookie name if going to 1.1, too?
1332
1333	// Update Settings.php with the new settings.
1334	changeSettings($changes);
1335
1336	if ($command_line)
1337		echo ' Successful.' . "\n";
1338
1339	// Are we doing debug?
1340	if (isset($_POST['debug']))
1341	{
1342		$upcontext['upgrade_status']['debug'] = true;
1343		$is_debug = true;
1344	}
1345
1346	// If we're not backing up then jump one.
1347	if (empty($_POST['backup']))
1348		$upcontext['current_step']++;
1349
1350	// If we've got here then let's proceed to the next step!
1351	return true;
1352}
1353
1354// Backup the database - why not...
1355function BackupDatabase()
1356{
1357	global $upcontext, $db_prefix, $command_line, $is_debug, $support_js, $file_steps, $smcFunc;
1358
1359	$upcontext['sub_template'] = isset($_GET['xml']) ? 'backup_xml' : 'backup_database';
1360	$upcontext['page_title'] = 'Backup Database';
1361
1362	// Done it already - js wise?
1363	if (!empty($_POST['backup_done']))
1364		return true;
1365
1366	// Some useful stuff here.
1367	db_extend();
1368
1369	// Get all the table names.
1370	$filter = str_replace('_', '\_', preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) != 0 ? $match[2] : $db_prefix) . '%';
1371	$db = preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) != 0 ? strtr($match[1], array('`' => '')) : false;
1372	$tables = $smcFunc['db_list_tables']($db, $filter);
1373
1374	$table_names = array();
1375	foreach ($tables as $table)
1376		if (substr($table, 0, 7) !== 'backup_')
1377			$table_names[] = $table;
1378
1379	$upcontext['table_count'] = count($table_names);
1380	$upcontext['cur_table_num'] = $_GET['substep'];
1381	$upcontext['cur_table_name'] = str_replace($db_prefix, '', isset($table_names[$_GET['substep']]) ? $table_names[$_GET['substep']] : $table_names[0]);
1382	$upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100);
1383	// For non-java auto submit...
1384	$file_steps = $upcontext['table_count'];
1385
1386	// What ones have we already done?
1387	foreach ($table_names as $id => $table)
1388		if ($id < $_GET['substep'])
1389			$upcontext['previous_tables'][] = $table;
1390
1391	if ($command_line)
1392		echo 'Backing Up Tables.';
1393
1394	// If we don't support javascript we backup here.
1395	if (!$support_js || isset($_GET['xml']))
1396	{
1397		// Backup each table!
1398		for ($substep = $_GET['substep'], $n = count($table_names); $substep < $n; $substep++)
1399		{
1400			$upcontext['cur_table_name'] = str_replace($db_prefix, '', (isset($table_names[$substep + 1]) ? $table_names[$substep + 1] : $table_names[$substep]));
1401			$upcontext['cur_table_num'] = $substep + 1;
1402
1403			$upcontext['step_progress'] = (int) (($upcontext['cur_table_num'] / $upcontext['table_count']) * 100);
1404
1405			// Do we need to pause?
1406			nextSubstep($substep);
1407
1408			backupTable($table_names[$substep]);
1409
1410			// If this is XML to keep it nice for the user do one table at a time anyway!
1411			if (isset($_GET['xml']))
1412				return upgradeExit();
1413		}
1414
1415		if ($is_debug && $command_line)
1416		{
1417			echo "\n" . ' Successful.\'' . "\n";
1418			flush();
1419		}
1420		$upcontext['step_progress'] = 100;
1421
1422		$_GET['substep'] = 0;
1423		// Make sure we move on!
1424		return true;
1425	}
1426
1427	// Either way next place to post will be database changes!
1428	$_GET['substep'] = 0;
1429	return false;
1430}
1431
1432// Backup one table...
1433function backupTable($table)
1434{
1435	global $is_debug, $command_line, $db_prefix, $smcFunc;
1436
1437	if ($is_debug && $command_line)
1438	{
1439		echo "\n" . ' +++ Backing up \"' . str_replace($db_prefix, '', $table) . '"...';
1440		flush();
1441	}
1442
1443	$smcFunc['db_backup_table']($table, 'backup_' . $table);
1444
1445	if ($is_debug && $command_line)
1446		echo ' done.';
1447}
1448
1449// Step 2: Everything.
1450function DatabaseChanges()
1451{
1452	global $db_prefix, $modSettings, $command_line, $smcFunc;
1453	global $language, $boardurl, $sourcedir, $boarddir, $upcontext, $support_js, $db_type;
1454
1455	// Have we just completed this?
1456	if (!empty($_POST['database_done']))
1457		return true;
1458
1459	$upcontext['sub_template'] = isset($_GET['xml']) ? 'database_xml' : 'database_changes';
1460	$upcontext['page_title'] = 'Database Changes';
1461
1462	// All possible files.
1463	// Name, <version, insert_on_complete
1464	$files = array(
1465		array('upgrade_1-0.sql', '1.1', '1.1 RC0'),
1466		array('upgrade_1-1.sql', '2.0', '2.0 a'),
1467		array('upgrade_2-0_' . $db_type . '.sql', '2.1', '2.1 dev0'),
1468		array('upgrade_2-1_' . $db_type . '.sql', '3.0', SMF_VERSION),
1469	);
1470
1471	// How many files are there in total?
1472	if (isset($_GET['filecount']))
1473		$upcontext['file_count'] = (int) $_GET['filecount'];
1474	else
1475	{
1476		$upcontext['file_count'] = 0;
1477		foreach ($files as $file)
1478		{
1479			if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < $file[1])
1480				$upcontext['file_count']++;
1481		}
1482	}
1483
1484	// Do each file!
1485	$did_not_do = count($files) - $upcontext['file_count'];
1486	$upcontext['step_progress'] = 0;
1487	$upcontext['cur_file_num'] = 0;
1488	foreach ($files as $file)
1489	{
1490		if ($did_not_do)
1491			$did_not_do--;
1492		else
1493		{
1494			$upcontext['cur_file_num']++;
1495			$upcontext['cur_file_name'] = $file[0];
1496			// Do we actually need to do this still?
1497			if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] < $file[1])
1498			{
1499				$nextFile = parse_sql(dirname(__FILE__) . '/' . $file[0]);
1500				if ($nextFile)
1501				{
1502					// Only update the version of this if complete.
1503					$smcFunc['db_insert']('replace',
1504						$db_prefix . 'settings',
1505						array('variable' => 'string', 'value' => 'string'),
1506						array('smfVersion', $file[2]),
1507						array('variable')
1508					);
1509
1510					$modSettings['smfVersion'] = $file[2];
1511				}
1512
1513				// If this is XML we only do this stuff once.
1514				if (isset($_GET['xml']))
1515				{
1516					// Flag to move on to the next.
1517					$upcontext['completed_step'] = true;
1518					// Did we complete the whole file?
1519					if ($nextFile)
1520						$upcontext['current_debug_item_num'] = -1;
1521					return upgradeExit();
1522				}
1523				elseif ($support_js)
1524					break;
1525			}
1526			// Set the progress bar to be right as if we had - even if we hadn't...
1527			$upcontext['step_progress'] = ($upcontext['cur_file_num'] / $upcontext['file_count']) * 100;
1528		}
1529	}
1530
1531	$_GET['substep'] = 0;
1532	// So the template knows we're done.
1533	if (!$support_js)
1534	{
1535		$upcontext['changes_complete'] = true;
1536
1537		// If this is the command line we can't do any more.
1538		if ($command_line)
1539			return DeleteUpgrade();
1540
1541		return true;
1542	}
1543	return false;
1544}
1545
1546// Clean up any mods installed...
1547function CleanupMods()
1548{
1549	global $db_prefix, $modSettings, $upcontext, $boarddir, $sourcedir, $settings, $smcFunc, $command_line;
1550
1551	// Sorry. Not supported for command line users.
1552	if ($command_line)
1553		return true;
1554
1555	// Skipp…

Large files files are truncated, but you can click here to view the full file