PageRenderTime 146ms CodeModel.GetById 83ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 1ms

/install/upgrade.php

https://github.com/Arantor/Elkarte
PHP | 4467 lines | 3461 code | 597 blank | 409 comment | 721 complexity | 3fe4172b1f5f9edd38337f4143b567e3 MD5 | raw file

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

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

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