PageRenderTime 69ms CodeModel.GetById 4ms app.highlight 50ms RepoModel.GetById 1ms app.codeStats 1ms

/other/install.php

https://github.com/smf-portal/SMF2.1
PHP | 2588 lines | 2071 code | 308 blank | 209 comment | 369 complexity | f96e529e5dd28aa0c8b991b220282873 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$GLOBALS['current_smf_version'] = '2.1 Alpha 1';
  15$GLOBALS['db_script_version'] = '2-1';
  16
  17$GLOBALS['required_php_version'] = '5.1.0';
  18
  19// Don't have PHP support, do you?
  20// ><html dir="ltr"><head><title>Error!</title></head><body>Sorry, this installer requires PHP!<div style="display: none;">
  21
  22// Database info.
  23$databases = array(
  24	'mysql' => array(
  25		'name' => 'MySQL',
  26		'version' => '4.0.18',
  27		'version_check' => 'return min(mysql_get_server_info(), mysql_get_client_info());',
  28		'supported' => function_exists('mysql_connect'),
  29		'default_user' => 'mysql.default_user',
  30		'default_password' => 'mysql.default_password',
  31		'default_host' => 'mysql.default_host',
  32		'default_port' => 'mysql.default_port',
  33		'utf8_support' => true,
  34		'utf8_version' => '4.1.0',
  35		'utf8_version_check' => 'return mysql_get_server_info();',
  36		'utf8_default' => true,
  37		'utf8_required' => false,
  38		'alter_support' => true,
  39		'validate_prefix' => create_function('&$value', '
  40			$value = preg_replace(\'~[^A-Za-z0-9_\$]~\', \'\', $value);
  41			return true;
  42		'),
  43	),
  44	'postgresql' => array(
  45		'name' => 'PostgreSQL',
  46		'version' => '8.0',
  47		'function_check' => 'pg_connect',
  48		'version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
  49		'supported' => function_exists('pg_connect'),
  50		'always_has_db' => true,
  51		'utf8_default' => true,
  52		'utf8_required' => true,
  53		'utf8_support' => true,
  54		'utf8_version' => '8.0',
  55		'utf8_version_check' => '$request = pg_query(\'SELECT version()\'); list ($version) = pg_fetch_row($request); list($pgl, $version) = explode(" ", $version); return $version;',
  56		'validate_prefix' => create_function('&$value', '
  57			$value = preg_replace(\'~[^A-Za-z0-9_\$]~\', \'\', $value);
  58
  59			// Is it reserved?
  60			if ($value == \'pg_\')
  61				return $txt[\'error_db_prefix_reserved\'];
  62
  63			// Is the prefix numeric?
  64			if (preg_match(\'~^\d~\', $value))
  65				return $txt[\'error_db_prefix_numeric\'];
  66
  67			return true;
  68		'),
  69	),
  70	'sqlite' => array(
  71		'name' => 'SQLite',
  72		'version' => '1',
  73		'function_check' => 'sqlite_open',
  74		'version_check' => 'return 1;',
  75		'supported' => function_exists('sqlite_open'),
  76		'always_has_db' => true,
  77		'utf8_default' => true,
  78		'utf8_required' => true,
  79		'utf8_support' => false,
  80		'validate_prefix' => create_function('&$value', '
  81			global $incontext, $txt;
  82
  83			$value = preg_replace(\'~[^A-Za-z0-9_\$]~\', \'\', $value);
  84
  85			// Is it reserved?
  86			if ($value == \'sqlite_\')
  87				return $txt[\'error_db_prefix_reserved\'];
  88
  89			// Is the prefix numeric?
  90			if (preg_match(\'~^\d~\', $value))
  91				return $txt[\'error_db_prefix_numeric\'];
  92
  93			return true;
  94		'),
  95	),
  96);
  97
  98// Initialize everything and load the language files.
  99initialize_inputs();
 100load_lang_file();
 101
 102// This is what we are.
 103$installurl = $_SERVER['PHP_SELF'];
 104// This is where SMF is.
 105$smfsite = 'http://www.simplemachines.org/smf';
 106
 107// All the steps in detail.
 108// Number,Name,Function,Progress Weight.
 109$incontext['steps'] = array(
 110	0 => array(1, $txt['install_step_welcome'], 'Welcome', 0),
 111	1 => array(2, $txt['install_step_writable'], 'CheckFilesWritable', 10),
 112	2 => array(3, $txt['install_step_databaseset'], 'DatabaseSettings', 15),
 113	3 => array(4, $txt['install_step_forum'], 'ForumSettings', 40),
 114	4 => array(5, $txt['install_step_databasechange'], 'DatabasePopulation', 15),
 115	5 => array(6, $txt['install_step_admin'], 'AdminAccount', 20),
 116	6 => array(7, $txt['install_step_delete'], 'DeleteInstall', 0),
 117);
 118
 119// Default title...
 120$incontext['page_title'] = $txt['smf_installer'];
 121
 122// What step are we on?
 123$incontext['current_step'] = isset($_GET['step']) ? (int) $_GET['step'] : 0;
 124
 125// Loop through all the steps doing each one as required.
 126$incontext['overall_percent'] = 0;
 127foreach ($incontext['steps'] as $num => $step)
 128{
 129	if ($num >= $incontext['current_step'])
 130	{
 131		// The current weight of this step in terms of overall progress.
 132		$incontext['step_weight'] = $step[3];
 133		// Make sure we reset the skip button.
 134		$incontext['skip'] = false;
 135
 136		// Call the step and if it returns false that means pause!
 137		if (function_exists($step[2]) && $step[2]() === false)
 138			break;
 139		elseif (function_exists($step[2]))
 140			$incontext['current_step']++;
 141
 142		// No warnings pass on.
 143		$incontext['warning'] = '';
 144	}
 145	$incontext['overall_percent'] += $step[3];
 146}
 147
 148// Actually do the template stuff.
 149installExit();
 150
 151function initialize_inputs()
 152{
 153	global $databases, $incontext;
 154
 155	// Just so people using older versions of PHP aren't left in the cold.
 156	if (!isset($_SERVER['PHP_SELF']))
 157		$_SERVER['PHP_SELF'] = isset($GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']) ? $GLOBALS['HTTP_SERVER_VARS']['PHP_SELF'] : 'install.php';
 158
 159	// Turn off magic quotes runtime and enable error reporting.
 160	if (function_exists('set_magic_quotes_runtime'))
 161		@set_magic_quotes_runtime(0);
 162	error_reporting(E_ALL);
 163
 164	// Fun.  Low PHP version...
 165	if (!isset($_GET))
 166	{
 167		$GLOBALS['_GET']['step'] = 0;
 168		return;
 169	}
 170
 171	if (!isset($_GET['obgz']))
 172	{
 173		ob_start();
 174
 175		if (ini_get('session.save_handler') == 'user')
 176			@ini_set('session.save_handler', 'files');
 177		if (function_exists('session_start'))
 178			@session_start();
 179	}
 180	else
 181	{
 182		ob_start('ob_gzhandler');
 183
 184		if (ini_get('session.save_handler') == 'user')
 185			@ini_set('session.save_handler', 'files');
 186		session_start();
 187
 188		if (!headers_sent())
 189			echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 190<html xmlns="http://www.w3.org/1999/xhtml">
 191	<head>
 192		<title>', htmlspecialchars($_GET['pass_string']), '</title>
 193	</head>
 194	<body style="background-color: #d4d4d4; margin-top: 16%; text-align: center; font-size: 16pt;">
 195		<strong>', htmlspecialchars($_GET['pass_string']), '</strong>
 196	</body>
 197</html>';
 198		exit;
 199	}
 200
 201	// Are we calling the backup css file?
 202	if (isset($_GET['infile_css']))
 203	{
 204		header('Content-Type: text/css');
 205		template_css();
 206		exit;
 207	}
 208
 209	// Anybody home?
 210	if (!isset($_GET['xml']))
 211	{
 212		$incontext['remote_files_available'] = false;
 213		$test = @fsockopen('www.simplemachines.org', 80, $errno, $errstr, 1);
 214		if ($test)
 215			$incontext['remote_files_available'] = true;
 216		@fclose($test);
 217	}
 218
 219	// Add slashes, as long as they aren't already being added.
 220	if (!function_exists('get_magic_quotes_gpc') || @get_magic_quotes_gpc() == 0)
 221		foreach ($_POST as $k => $v)
 222			if (strpos($k, 'password') === false)
 223				$_POST[$k] = addslashes($v);
 224
 225	// This is really quite simple; if ?delete is on the URL, delete the installer...
 226	if (isset($_GET['delete']))
 227	{
 228		if (isset($_SESSION['installer_temp_ftp']))
 229		{
 230			$ftp = new ftp_connection($_SESSION['installer_temp_ftp']['server'], $_SESSION['installer_temp_ftp']['port'], $_SESSION['installer_temp_ftp']['username'], $_SESSION['installer_temp_ftp']['password']);
 231			$ftp->chdir($_SESSION['installer_temp_ftp']['path']);
 232
 233			$ftp->unlink('install.php');
 234			$ftp->unlink('webinstall.php');
 235
 236			foreach ($databases as $key => $dummy)
 237				$ftp->unlink('install_' . $GLOBALS['db_script_version'] . '_' . $key . '.sql');
 238
 239			$ftp->close();
 240
 241			unset($_SESSION['installer_temp_ftp']);
 242		}
 243		else
 244		{
 245			@unlink(__FILE__);
 246			@unlink(dirname(__FILE__) . '/webinstall.php');
 247
 248			foreach ($databases as $key => $dummy)
 249				@unlink(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $key . '.sql');
 250		}
 251
 252		// Now just redirect to a blank.png...
 253		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');
 254		exit;
 255	}
 256
 257	// PHP 5 might cry if we don't do this now.
 258	if (function_exists('date_default_timezone_set'))
 259	{
 260		$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
 261		date_default_timezone_set('Etc/GMT' . ($server_offset > 0 ? '+' : '') . ($server_offset / 3600));
 262	}
 263
 264	// Force an integer step, defaulting to 0.
 265	$_GET['step'] = (int) @$_GET['step'];
 266}
 267
 268// Load the list of language files, and the current language file.
 269function load_lang_file()
 270{
 271	global $txt, $incontext;
 272
 273	$incontext['detected_languages'] = array();
 274
 275	// Make sure the languages directory actually exists.
 276	if (file_exists(dirname(__FILE__) . '/Themes/default/languages'))
 277	{
 278		// Find all the "Install" language files in the directory.
 279		$dir = dir(dirname(__FILE__) . '/Themes/default/languages');
 280		while ($entry = $dir->read())
 281		{
 282			if (substr($entry, 0, 8) == 'Install.' && substr($entry, -4) == '.php')
 283				$incontext['detected_languages'][$entry] = ucfirst(substr($entry, 8, strlen($entry) - 12));
 284		}
 285		$dir->close();
 286	}
 287
 288	// Didn't find any, show an error message!
 289	if (empty($incontext['detected_languages']))
 290	{
 291		// Let's not cache this message, eh?
 292		header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
 293		header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
 294		header('Cache-Control: no-cache');
 295
 296		echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 297<html xmlns="http://www.w3.org/1999/xhtml">
 298	<head>
 299		<title>SMF Installer: Error!</title>
 300	</head>
 301	<body style="font-family: sans-serif;"><div style="width: 600px;">
 302		<h1 style="font-size: 14pt;">A critical error has occurred.</h1>
 303
 304		<p>This installer was unable to find the installer\'s language file or files.  They should be found under:</p>
 305
 306		<div style="margin: 1ex; font-family: monospace; font-weight: bold;">', dirname($_SERVER['PHP_SELF']) != '/' ? dirname($_SERVER['PHP_SELF']) : '', '/Themes/default/languages</div>
 307
 308		<p>In some cases, FTP clients do not properly upload files with this many folders.  Please double check to make sure you <span style="font-weight: 600;">have uploaded all the files in the distribution</span>.</p>
 309		<p>If that doesn\'t help, please make sure this install.php file is in the same place as the Themes folder.</p>
 310
 311		<p>If you continue to get this error message, feel free to <a href="http://support.simplemachines.org/">look to us for support</a>.</p>
 312	</div></body>
 313</html>';
 314		die;
 315	}
 316
 317	// Override the language file?
 318	if (isset($_GET['lang_file']))
 319		$_SESSION['installer_temp_lang'] = $_GET['lang_file'];
 320	elseif (isset($GLOBALS['HTTP_GET_VARS']['lang_file']))
 321		$_SESSION['installer_temp_lang'] = $GLOBALS['HTTP_GET_VARS']['lang_file'];
 322
 323	// Make sure it exists, if it doesn't reset it.
 324	if (!isset($_SESSION['installer_temp_lang']) || preg_match('~[^\\w_\\-.]~', $_SESSION['installer_temp_lang']) === 1 || !file_exists(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']))
 325	{
 326		// Use the first one...
 327		list ($_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
 328
 329		// If we have english and some other language, use the other language.  We Americans hate english :P.
 330		if ($_SESSION['installer_temp_lang'] == 'Install.english.php' && count($incontext['detected_languages']) > 1)
 331			list (, $_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
 332	}
 333
 334	// And now include the actual language file itself.
 335	require_once(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']);
 336}
 337
 338// This handy function loads some settings and the like.
 339function load_database()
 340{
 341	global $db_prefix, $db_connection, $db_character_set, $sourcedir, $language;
 342	global $smcFunc, $mbname, $scripturl, $boardurl, $modSettings, $db_type, $db_name, $db_user;
 343
 344	if (empty($sourcedir))
 345		$sourcedir = dirname(__FILE__) . '/Sources';
 346
 347	// Need this to check whether we need the database password.
 348	require(dirname(__FILE__) . '/Settings.php');
 349	if (!defined('SMF'))
 350		define('SMF', 1);
 351	if (empty($smcFunc))
 352		$smcFunc = array();
 353
 354	$modSettings['disableQueryCheck'] = true;
 355
 356	// Connect the database.
 357	if (!$db_connection)
 358	{
 359		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
 360		if (version_compare(PHP_VERSION, '5', '<'))
 361			require_once($sourcedir . '/Subs-Compat.php');
 362
 363		if (!$db_connection)
 364			$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('persist' => $db_persist));
 365	}
 366}
 367
 368// This is called upon exiting the installer, for template etc.
 369function installExit($fallThrough = false)
 370{
 371	global $incontext, $installurl, $txt;
 372
 373	// Send character set.
 374	header('Content-Type: text/html; charset=' . (isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'ISO-8859-1'));
 375
 376	// We usually dump our templates out.
 377	if (!$fallThrough)
 378	{
 379		// The top install bit.
 380		template_install_above();
 381
 382		// Call the template.
 383		if (isset($incontext['sub_template']))
 384		{
 385			$incontext['form_url'] = $installurl . '?step=' . $incontext['current_step'];
 386
 387			call_user_func('template_' . $incontext['sub_template']);
 388		}
 389		// @todo REMOVE THIS!!
 390		else
 391		{
 392			if (function_exists('doStep' . $_GET['step']))
 393				call_user_func('doStep' . $_GET['step']);
 394		}
 395		// Show the footer.
 396		template_install_below();
 397	}
 398
 399	// Bang - gone!
 400	die();
 401}
 402
 403function Welcome()
 404{
 405	global $incontext, $txt, $databases, $installurl;
 406
 407	$incontext['page_title'] = $txt['install_welcome'];
 408	$incontext['sub_template'] = 'welcome_message';
 409
 410	// Done the submission?
 411	if (isset($_POST['contbutt']))
 412		return true;
 413
 414	// Check the PHP version.
 415	if ((!function_exists('version_compare') || version_compare($GLOBALS['required_php_version'], PHP_VERSION, '>')))
 416	{
 417		$incontext['warning'] = $txt['error_php_too_low'];
 418	}
 419
 420	// See if we think they have already installed it?
 421	if (is_readable(dirname(__FILE__) . '/Settings.php'))
 422	{
 423		$probably_installed = 0;
 424		foreach (file(dirname(__FILE__) . '/Settings.php') as $line)
 425		{
 426			if (preg_match('~^\$db_passwd\s=\s\'([^\']+)\';$~', $line))
 427				$probably_installed++;
 428			if (preg_match('~^\$boardurl\s=\s\'([^\']+)\';~', $line) && !preg_match('~^\$boardurl\s=\s\'http://127\.0\.0\.1/smf\';~', $line))
 429				$probably_installed++;
 430		}
 431
 432		if ($probably_installed == 2)
 433			$incontext['warning'] = $txt['error_already_installed'];
 434	}
 435
 436	// Is some database support even compiled in?
 437	$incontext['supported_databases'] = array();
 438	foreach ($databases as $key => $db)
 439	{
 440		if ($db['supported'])
 441		{
 442			if (!file_exists(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $key . '.sql'))
 443			{
 444				$databases[$key]['supported'] = false;
 445				$notFoundSQLFile = true;
 446				$txt['error_db_script_missing'] = sprintf($txt['error_db_script_missing'], 'install_' . $GLOBALS['db_script_version'] . '_' . $key . '.sql');
 447			}
 448			else
 449			{
 450				$db_type = $key;
 451				$incontext['supported_databases'][] = $db;
 452			}
 453		}
 454	}
 455
 456	if (empty($incontext['supported_databases']))
 457		$error = empty($notFoundSQLFile) ? 'error_db_missing' : 'error_db_script_missing';
 458	// How about session support?  Some crazy sysadmin remove it?
 459	elseif (!function_exists('session_start'))
 460		$error = 'error_session_missing';
 461	// Make sure they uploaded all the files.
 462	elseif (!file_exists(dirname(__FILE__) . '/index.php'))
 463		$error = 'error_missing_files';
 464	// Very simple check on the session.save_path for Windows.
 465	// @todo Move this down later if they don't use database-driven sessions?
 466	elseif (@ini_get('session.save_path') == '/tmp' && substr(__FILE__, 1, 2) == ':\\')
 467		$error = 'error_session_save_path';
 468
 469	// Since each of the three messages would look the same, anyway...
 470	if (isset($error))
 471		$incontext['error'] = $txt[$error];
 472
 473	// Mod_security blocks everything that smells funny. Let SMF handle security.
 474	if (!fixModSecurity() && !isset($_GET['overmodsecurity']))
 475		$incontext['error'] = $txt['error_mod_security'] . '<br /><br /><a href="' . $installurl . '?overmodsecurity=true">' . $txt['error_message_click'] . '</a> ' . $txt['error_message_bad_try_again'];
 476
 477	return false;
 478}
 479
 480function CheckFilesWritable()
 481{
 482	global $txt, $incontext;
 483
 484	$incontext['page_title'] = $txt['ftp_checking_writable'];
 485	$incontext['sub_template'] = 'chmod_files';
 486
 487	$writable_files = array(
 488		'attachments',
 489		'avatars',
 490		'cache',
 491		'Packages',
 492		'Packages/installed.list',
 493		'Smileys',
 494		'Themes',
 495		'agreement.txt',
 496		'Settings.php',
 497		'Settings_bak.php'
 498	);
 499	foreach ($incontext['detected_languages'] as $lang => $temp)
 500		$extra_files[] = 'Themes/default/languages/' . $lang;
 501
 502	// With mod_security installed, we could attempt to fix it with .htaccess.
 503	if (function_exists('apache_get_modules') && in_array('mod_security', apache_get_modules()))
 504		$writable_files[] = file_exists(dirname(__FILE__) . '/.htaccess') ? '.htaccess' : '.';
 505
 506	$failed_files = array();
 507
 508	// On linux, it's easy - just use is_writable!
 509	if (substr(__FILE__, 1, 2) != ':\\')
 510	{
 511		foreach ($writable_files as $file)
 512		{
 513			if (!is_writable(dirname(__FILE__) . '/' . $file))
 514			{
 515				@chmod(dirname(__FILE__) . '/' . $file, 0755);
 516
 517				// Well, 755 hopefully worked... if not, try 777.
 518				if (!is_writable(dirname(__FILE__) . '/' . $file) && !@chmod(dirname(__FILE__) . '/' . $file, 0777))
 519					$failed_files[] = $file;
 520			}
 521		}
 522		foreach ($extra_files as $file)
 523			@chmod(dirname(__FILE__) . (empty($file) ? '' : '/' . $file), 0777);
 524	}
 525	// Windows is trickier.  Let's try opening for r+...
 526	else
 527	{
 528		foreach ($writable_files as $file)
 529		{
 530			// Folders can't be opened for write... but the index.php in them can ;)
 531			if (is_dir(dirname(__FILE__) . '/' . $file))
 532				$file .= '/index.php';
 533
 534			// Funny enough, chmod actually does do something on windows - it removes the read only attribute.
 535			@chmod(dirname(__FILE__) . '/' . $file, 0777);
 536			$fp = @fopen(dirname(__FILE__) . '/' . $file, 'r+');
 537
 538			// Hmm, okay, try just for write in that case...
 539			if (!is_resource($fp))
 540				$fp = @fopen(dirname(__FILE__) . '/' . $file, 'w');
 541
 542			if (!is_resource($fp))
 543				$failed_files[] = $file;
 544
 545			@fclose($fp);
 546		}
 547		foreach ($extra_files as $file)
 548			@chmod(dirname(__FILE__) . (empty($file) ? '' : '/' . $file), 0777);
 549	}
 550
 551	$failure = count($failed_files) >= 1;
 552
 553	if (!isset($_SERVER))
 554		return !$failure;
 555
 556	// Put the list into context.
 557	$incontext['failed_files'] = $failed_files;
 558
 559	// It's not going to be possible to use FTP on windows to solve the problem...
 560	if ($failure && substr(__FILE__, 1, 2) == ':\\')
 561	{
 562		$incontext['error'] = $txt['error_windows_chmod'] . '
 563					<ul style="margin: 2.5ex; font-family: monospace;">
 564						<li>' . implode('</li>
 565						<li>', $failed_files) . '</li>
 566					</ul>';
 567
 568		return false;
 569	}
 570	// We're going to have to use... FTP!
 571	elseif ($failure)
 572	{
 573		// Load any session data we might have...
 574		if (!isset($_POST['ftp_username']) && isset($_SESSION['installer_temp_ftp']))
 575		{
 576			$_POST['ftp_server'] = $_SESSION['installer_temp_ftp']['server'];
 577			$_POST['ftp_port'] = $_SESSION['installer_temp_ftp']['port'];
 578			$_POST['ftp_username'] = $_SESSION['installer_temp_ftp']['username'];
 579			$_POST['ftp_password'] = $_SESSION['installer_temp_ftp']['password'];
 580			$_POST['ftp_path'] = $_SESSION['installer_temp_ftp']['path'];
 581		}
 582
 583		$incontext['ftp_errors'] = array();
 584
 585		if (isset($_POST['ftp_username']))
 586		{
 587			$ftp = new ftp_connection($_POST['ftp_server'], $_POST['ftp_port'], $_POST['ftp_username'], $_POST['ftp_password']);
 588
 589			if ($ftp->error === false)
 590			{
 591				// Try it without /home/abc just in case they messed up.
 592				if (!$ftp->chdir($_POST['ftp_path']))
 593				{
 594					$incontext['ftp_errors'][] = $ftp->last_message;
 595					$ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $_POST['ftp_path']));
 596				}
 597			}
 598		}
 599
 600		if (!isset($ftp) || $ftp->error !== false)
 601		{
 602			if (!isset($ftp))
 603				$ftp = new ftp_connection(null);
 604			// Save the error so we can mess with listing...
 605			elseif ($ftp->error !== false && empty($incontext['ftp_errors']) && !empty($ftp->last_message))
 606				$incontext['ftp_errors'][] = $ftp->last_message;
 607
 608			list ($username, $detect_path, $found_path) = $ftp->detect_path(dirname(__FILE__));
 609
 610			if (empty($_POST['ftp_path']) && $found_path)
 611				$_POST['ftp_path'] = $detect_path;
 612
 613			if (!isset($_POST['ftp_username']))
 614				$_POST['ftp_username'] = $username;
 615
 616			// Set the username etc, into context.
 617			$incontext['ftp'] = array(
 618				'server' => isset($_POST['ftp_server']) ? $_POST['ftp_server'] : 'localhost',
 619				'port' => isset($_POST['ftp_port']) ? $_POST['ftp_port'] : '21',
 620				'username' => isset($_POST['ftp_username']) ? $_POST['ftp_username'] : '',
 621				'path' => isset($_POST['ftp_path']) ? $_POST['ftp_path'] : '/',
 622				'path_msg' => !empty($found_path) ? $txt['ftp_path_found_info'] : $txt['ftp_path_info'],
 623			);
 624
 625			return false;
 626		}
 627		else
 628		{
 629			$_SESSION['installer_temp_ftp'] = array(
 630				'server' => $_POST['ftp_server'],
 631				'port' => $_POST['ftp_port'],
 632				'username' => $_POST['ftp_username'],
 633				'password' => $_POST['ftp_password'],
 634				'path' => $_POST['ftp_path']
 635			);
 636
 637			$failed_files_updated = array();
 638
 639			foreach ($failed_files as $file)
 640			{
 641				if (!is_writable(dirname(__FILE__) . '/' . $file))
 642					$ftp->chmod($file, 0755);
 643				if (!is_writable(dirname(__FILE__) . '/' . $file))
 644					$ftp->chmod($file, 0777);
 645				if (!is_writable(dirname(__FILE__) . '/' . $file))
 646				{
 647					$failed_files_updated[] = $file;
 648					$incontext['ftp_errors'][] = rtrim($ftp->last_message) . ' -> ' . $file . "\n";
 649				}
 650			}
 651
 652			$ftp->close();
 653
 654			// Are there any errors left?
 655			if (count($failed_files_updated) >= 1)
 656			{
 657				// Guess there are...
 658				$incontext['failed_files'] = $failed_files_updated;
 659
 660				// Set the username etc, into context.
 661				$incontext['ftp'] = $_SESSION['installer_temp_ftp'] += array(
 662					'path_msg' => $txt['ftp_path_info'],
 663				);
 664
 665				return false;
 666			}
 667		}
 668	}
 669
 670	return true;
 671}
 672
 673function DatabaseSettings()
 674{
 675	global $txt, $databases, $incontext, $smcFunc, $sourcedir;
 676
 677	$incontext['sub_template'] = 'database_settings';
 678	$incontext['page_title'] = $txt['db_settings'];
 679	$incontext['continue'] = 1;
 680
 681	// Set up the defaults.
 682	$incontext['db']['server'] = 'localhost';
 683	$incontext['db']['user'] = '';
 684	$incontext['db']['name'] = '';
 685	$incontext['db']['pass'] = '';
 686	$incontext['db']['type'] = '';
 687	$incontext['supported_databases'] = array();
 688
 689	$foundOne = false;
 690	foreach ($databases as $key => $db)
 691	{
 692		// Override with the defaults for this DB if appropriate.
 693		if ($db['supported'])
 694		{
 695			$incontext['supported_databases'][$key] = $db;
 696
 697			if (!$foundOne)
 698			{
 699				if (isset($db['default_host']))
 700					$incontext['db']['server'] = ini_get($db['default_host']) or $incontext['db']['server'] = 'localhost';
 701				if (isset($db['default_user']))
 702				{
 703					$incontext['db']['user'] = ini_get($db['default_user']);
 704					$incontext['db']['name'] = ini_get($db['default_user']);
 705				}
 706				if (isset($db['default_password']))
 707					$incontext['db']['pass'] = ini_get($db['default_password']);
 708				if (isset($db['default_port']))
 709					$db_port = ini_get($db['default_port']);
 710
 711				$incontext['db']['type'] = $key;
 712				$foundOne = true;
 713			}
 714		}
 715	}
 716
 717	// Override for repost.
 718	if (isset($_POST['db_user']))
 719	{
 720		$incontext['db']['user'] = $_POST['db_user'];
 721		$incontext['db']['name'] = $_POST['db_type'] == 'sqlite' && isset($_POST['db_filename']) ? $_POST['db_filename'] : $_POST['db_name'];
 722		$incontext['db']['server'] = $_POST['db_server'];
 723		$incontext['db']['prefix'] = $_POST['db_prefix'];
 724	}
 725	else
 726	{
 727		$incontext['db']['prefix'] = 'smf_';
 728
 729		// Should we use a non standard port?
 730		if (!empty($db_port))
 731			$incontext['db']['server'] .= ':' . $db_port;
 732	}
 733
 734	// Are we submitting?
 735	if (isset($_POST['db_type']))
 736	{
 737		if (isset($_POST['db_filename']))
 738		{
 739			// You better enter enter a database name for SQLite.
 740			if (trim($_POST['db_filename']) == '')
 741			{
 742				$incontext['error'] = $txt['error_db_filename'];
 743				return false;
 744			}
 745			// Duplicate name in the same dir?  Can't do that with SQLite.  Weird things happen.
 746			if (file_exists($_POST['db_filename'] . (substr($_POST['db_filename'], -3) != '.db' ? '.db' : '')))
 747			{
 748				$incontext['error'] = $txt['error_db_filename_exists'];
 749				return false;
 750			}
 751		}
 752
 753		// What type are they trying?
 754		$db_type = preg_replace('~[^A-Za-z0-9]~', '', $_POST['db_type']);
 755		$db_prefix = $_POST['db_prefix'];
 756		// Validate the prefix.
 757		$valid_prefix = $databases[$db_type]['validate_prefix']($db_prefix);
 758
 759		if ($valid_prefix !== true)
 760		{
 761			$incontext['error'] = $valid_prefix;
 762			return false;
 763		}
 764
 765		// Take care of these variables...
 766		$vars = array(
 767			'db_type' => $db_type,
 768			'db_name' => $_POST['db_type'] == 'sqlite' && isset($_POST['db_filename']) ? $_POST['db_filename'] : $_POST['db_name'],
 769			'db_user' => $_POST['db_user'],
 770			'db_passwd' => isset($_POST['db_passwd']) ? $_POST['db_passwd'] : '',
 771			'db_server' => $_POST['db_server'],
 772			'db_prefix' => $db_prefix,
 773			// The cookiename is special; we want it to be the same if it ever needs to be reinstalled with the same info.
 774			'cookiename' => 'SMFCookie' . abs(crc32($_POST['db_name'] . preg_replace('~[^A-Za-z0-9_$]~', '', $_POST['db_prefix'])) % 1000),
 775		);
 776
 777		// God I hope it saved!
 778		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
 779		{
 780			$incontext['error'] = $txt['error_windows_chmod'];
 781			return false;
 782		}
 783
 784		// Make sure it works.
 785		require(dirname(__FILE__) . '/Settings.php');
 786
 787		if (empty($sourcedir))
 788			$sourcedir = dirname(__FILE__) . '/Sources';
 789
 790		// Better find the database file!
 791		if (!file_exists($sourcedir . '/Subs-Db-' . $db_type . '.php'))
 792		{
 793			$incontext['error'] = sprintf($txt['error_db_file'], 'Subs-Db-' . $db_type . '.php');
 794			return false;
 795		}
 796
 797		// Now include it for database functions!
 798		define('SMF', 1);
 799		$modSettings['disableQueryCheck'] = true;
 800		if (empty($smcFunc))
 801			$smcFunc = array();
 802
 803			require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
 804
 805		// What - running PHP4? The shame!
 806		if (version_compare(PHP_VERSION, '5', '<'))
 807			require_once($sourcedir . '/Subs-Compat.php');
 808
 809		// Attempt a connection.
 810		$needsDB = !empty($databases[$db_type]['always_has_db']);
 811		$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('non_fatal' => true, 'dont_select_db' => !$needsDB));
 812
 813		// No dice?  Let's try adding the prefix they specified, just in case they misread the instructions ;)
 814		if ($db_connection == null)
 815		{
 816			$db_error = @$smcFunc['db_error']();
 817
 818			$db_connection = smf_db_initiate($db_server, $db_name, $_POST['db_prefix'] . $db_user, $db_passwd, $db_prefix, array('non_fatal' => true, 'dont_select_db' => !$needsDB));
 819			if ($db_connection != null)
 820			{
 821				$db_user = $_POST['db_prefix'] . $db_user;
 822				updateSettingsFile(array('db_user' => $db_user));
 823			}
 824		}
 825
 826		// Still no connection?  Big fat error message :P.
 827		if (!$db_connection)
 828		{
 829			$incontext['error'] = $txt['error_db_connect'] . '<div style="margin: 2.5ex; font-family: monospace;"><strong>' . $db_error . '</strong></div>';
 830			return false;
 831		}
 832
 833		// Do they meet the install requirements?
 834		// @todo Old client, new server?
 835		if (version_compare($databases[$db_type]['version'], preg_replace('~^\D*|\-.+?$~', '', eval($databases[$db_type]['version_check']))) > 0)
 836		{
 837			$incontext['error'] = $txt['error_db_too_low'];
 838			return false;
 839		}
 840
 841		// Let's try that database on for size... assuming we haven't already lost the opportunity.
 842		if ($db_name != '' && !$needsDB)
 843		{
 844			$smcFunc['db_query']('', "
 845				CREATE DATABASE IF NOT EXISTS `$db_name`",
 846				array(
 847					'security_override' => true,
 848					'db_error_skip' => true,
 849				),
 850				$db_connection
 851			);
 852
 853			// Okay, let's try the prefix if it didn't work...
 854			if (!$smcFunc['db_select_db']($db_name, $db_connection) && $db_name != '')
 855			{
 856				$smcFunc['db_query']('', "
 857					CREATE DATABASE IF NOT EXISTS `$_POST[db_prefix]$db_name`",
 858					array(
 859						'security_override' => true,
 860						'db_error_skip' => true,
 861					),
 862					$db_connection
 863				);
 864
 865				if ($smcFunc['db_select_db']($_POST['db_prefix'] . $db_name, $db_connection))
 866				{
 867					$db_name = $_POST['db_prefix'] . $db_name;
 868					updateSettingsFile(array('db_name' => $db_name));
 869				}
 870			}
 871
 872			// Okay, now let's try to connect...
 873			if (!$smcFunc['db_select_db']($db_name, $db_connection))
 874			{
 875				$incontext['error'] = sprintf($txt['error_db_database'], $db_name);
 876				return false;
 877			}
 878		}
 879
 880		return true;
 881	}
 882
 883	return false;
 884}
 885
 886// Let's start with basic forum type settings.
 887function ForumSettings()
 888{
 889	global $txt, $incontext, $databases, $smcFunc, $db_connection, $db_type;
 890
 891	$incontext['sub_template'] = 'forum_settings';
 892	$incontext['page_title'] = $txt['install_settings'];
 893
 894	// Let's see if we got the database type correct.
 895	if (isset($_POST['db_type'], $databases[$_POST['db_type']]))
 896		$db_type = $_POST['db_type'];
 897
 898	// Else we'd better be able to get the connection.
 899	else
 900		load_database();
 901
 902	$db_type = isset($_POST['db_type']) ? $_POST['db_type'] : $db_type;
 903
 904	// What host and port are we on?
 905	$host = empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST'];
 906
 907	// Now, to put what we've learned together... and add a path.
 908	$incontext['detected_url'] = 'http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . $host . substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
 909
 910	// Check if the database sessions will even work.
 911	$incontext['test_dbsession'] = ini_get('session.auto_start') != 1;
 912	$incontext['utf8_default'] = $databases[$db_type]['utf8_default'];
 913	$incontext['utf8_required'] = $databases[$db_type]['utf8_required'];
 914
 915	$incontext['continue'] = 1;
 916
 917	// Submitting?
 918	if (isset($_POST['boardurl']))
 919	{
 920		if (substr($_POST['boardurl'], -10) == '/index.php')
 921			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -10);
 922		elseif (substr($_POST['boardurl'], -1) == '/')
 923			$_POST['boardurl'] = substr($_POST['boardurl'], 0, -1);
 924		if (substr($_POST['boardurl'], 0, 7) != 'http://' && substr($_POST['boardurl'], 0, 7) != 'file://' && substr($_POST['boardurl'], 0, 8) != 'https://')
 925			$_POST['boardurl'] = 'http://' . $_POST['boardurl'];
 926
 927		// Save these variables.
 928		$vars = array(
 929			'boardurl' => $_POST['boardurl'],
 930			'boarddir' => addslashes(dirname(__FILE__)),
 931			'sourcedir' => addslashes(dirname(__FILE__)) . '/Sources',
 932			'cachedir' => addslashes(dirname(__FILE__)) . '/cache',
 933			'mbname' => strtr($_POST['mbname'], array('\"' => '"')),
 934			'language' => substr($_SESSION['installer_temp_lang'], 8, -4),
 935		);
 936
 937		// Must save!
 938		if (!updateSettingsFile($vars) && substr(__FILE__, 1, 2) == ':\\')
 939		{
 940			$incontext['error'] = $txt['error_windows_chmod'];
 941			return false;
 942		}
 943
 944		// Make sure it works.
 945		require(dirname(__FILE__) . '/Settings.php');
 946
 947		// UTF-8 requires a setting to override the language charset.
 948		if ((!empty($databases[$db_type]['utf8_support']) && !empty($databases[$db_type]['utf8_required'])) || (empty($databases[$db_type]['utf8_required']) && !empty($databases[$db_type]['utf8_support']) && isset($_POST['utf8'])))
 949		{
 950			if (!empty($databases[$db_type]['utf8_version_check']) && version_compare($databases[$db_type]['utf8_version'], preg_replace('~\-.+?$~', '', eval($databases[$db_type]['utf8_version_check'])), '>'))
 951			{
 952				$incontext['error'] = sprintf($txt['error_utf8_version'], $databases[$db_type]['utf8_version']);
 953				return false;
 954			}
 955			else
 956				// Set the character set here.
 957				updateSettingsFile(array('db_character_set' => 'utf8'));
 958		}
 959
 960		// Good, skip on.
 961		return true;
 962	}
 963
 964	return false;
 965}
 966
 967// Step one: Do the SQL thang.
 968function DatabasePopulation()
 969{
 970	global $db_character_set, $txt, $db_connection, $smcFunc, $databases, $modSettings, $db_type, $sourcedir, $db_prefix, $incontext, $db_name, $boardurl;
 971
 972	$incontext['sub_template'] = 'populate_database';
 973	$incontext['page_title'] = $txt['db_populate'];
 974	$incontext['continue'] = 1;
 975
 976	// Already done?
 977	if (isset($_POST['pop_done']))
 978		return true;
 979
 980	// Reload settings.
 981	require(dirname(__FILE__) . '/Settings.php');
 982	load_database();
 983
 984	// Before running any of the queries, let's make sure another version isn't already installed.
 985	$result = $smcFunc['db_query']('', '
 986		SELECT variable, value
 987		FROM {db_prefix}settings',
 988		array(
 989			'db_error_skip' => true,
 990		)
 991	);
 992	$modSettings = array();
 993	if ($result !== false)
 994	{
 995		while ($row = $smcFunc['db_fetch_assoc']($result))
 996			$modSettings[$row['variable']] = $row['value'];
 997		$smcFunc['db_free_result']($result);
 998
 999		// Do they match?  If so, this is just a refresh so charge on!
1000		if (!isset($modSettings['smfVersion']) || $modSettings['smfVersion'] != $GLOBALS['current_smf_version'])
1001		{
1002			$incontext['error'] = $txt['error_versions_do_not_match'];
1003			return false;
1004		}
1005	}
1006	$modSettings['disableQueryCheck'] = true;
1007
1008	// If doing UTF8, select it. PostgreSQL requires passing it as a string...
1009	if (!empty($db_character_set) && $db_character_set == 'utf8' && !empty($databases[$db_type]['utf8_support']))
1010		$smcFunc['db_query']('', '
1011			SET NAMES {'. ($db_type == 'postgresql' ? 'string' : 'raw') . ':utf8}',
1012			array(
1013				'db_error_skip' => true,
1014				'utf8' => 'utf8',
1015			)
1016		);
1017
1018	$replaces = array(
1019		'{$db_prefix}' => $db_prefix,
1020		'{$boarddir}' => $smcFunc['db_escape_string'](dirname(__FILE__)),
1021		'{$boardurl}' => $boardurl,
1022		'{$enableCompressedOutput}' => isset($_POST['compress']) ? '1' : '0',
1023		'{$databaseSession_enable}' => isset($_POST['dbsession']) ? '1' : '0',
1024		'{$smf_version}' => $GLOBALS['current_smf_version'],
1025		'{$current_time}' => time(),
1026		'{$sched_task_offset}' => 82800 + mt_rand(0, 86399),
1027	);
1028
1029	foreach ($txt as $key => $value)
1030	{
1031		if (substr($key, 0, 8) == 'default_')
1032			$replaces['{$' . $key . '}'] = $smcFunc['db_escape_string']($value);
1033	}
1034	$replaces['{$default_reserved_names}'] = strtr($replaces['{$default_reserved_names}'], array('\\\\n' => '\\n'));
1035
1036	// If the UTF-8 setting was enabled, add it to the table definitions.
1037	if (empty($databases[$db_type]['utf8_required']) && isset($_POST['utf8']) && !empty($databases[$db_type]['utf8_support']))
1038		$replaces[') ENGINE=MyISAM;'] = ') ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;';
1039
1040	// Read in the SQL.  Turn this on and that off... internationalize... etc.
1041	$sql_lines = explode("\n", strtr(implode(' ', file(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $db_type . '.sql')), $replaces));
1042
1043	// Execute the SQL.
1044	$current_statement = '';
1045	$exists = array();
1046	$incontext['failures'] = array();
1047	$incontext['sql_results'] = array(
1048		'tables' => 0,
1049		'inserts' => 0,
1050		'table_dups' => 0,
1051		'insert_dups' => 0,
1052	);
1053	foreach ($sql_lines as $count => $line)
1054	{
1055		// No comments allowed!
1056		if (substr(trim($line), 0, 1) != '#')
1057			$current_statement .= "\n" . rtrim($line);
1058
1059		// Is this the end of the query string?
1060		if (empty($current_statement) || (preg_match('~;[\s]*$~s', $line) == 0 && $count != count($sql_lines)))
1061			continue;
1062
1063		// Does this table already exist?  If so, don't insert more data into it!
1064		if (preg_match('~^\s*INSERT INTO ([^\s\n\r]+?)~', $current_statement, $match) != 0 && in_array($match[1], $exists))
1065		{
1066			$incontext['sql_results']['insert_dups']++;
1067			$current_statement = '';
1068			continue;
1069		}
1070
1071		if ($smcFunc['db_query']('', $current_statement, array('security_override' => true, 'db_error_skip' => true), $db_connection) === false)
1072		{
1073			// Error 1050: Table already exists!
1074			// @todo Needs to be made better!
1075			if (($db_type != 'mysql' || mysql_errno($db_connection) === 1050) && preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1076			{
1077				$exists[] = $match[1];
1078				$incontext['sql_results']['table_dups']++;
1079			}
1080			// Don't error on duplicate indexes (or duplicate operators in PostgreSQL.)
1081			elseif (!preg_match('~^\s*CREATE( UNIQUE)? INDEX ([^\n\r]+?)~', $current_statement, $match) && !($db_type == 'postgresql' && preg_match('~^\s*CREATE OPERATOR (^\n\r]+?)~', $current_statement, $match)))
1082			{
1083				$incontext['failures'][$count] = $smcFunc['db_error']();
1084			}
1085		}
1086		else
1087		{
1088			if (preg_match('~^\s*CREATE TABLE ([^\s\n\r]+?)~', $current_statement, $match) == 1)
1089				$incontext['sql_results']['tables']++;
1090			else
1091			{
1092				preg_match_all('~\)[,;]~', $current_statement, $matches);
1093				if (!empty($matches[0]))
1094					$incontext['sql_results']['inserts'] += count($matches[0]);
1095				else
1096					$incontext['sql_results']['inserts']++;
1097			}
1098		}
1099
1100		$current_statement = '';
1101	}
1102
1103	// Sort out the context for the SQL.
1104	foreach ($incontext['sql_results'] as $key => $number)
1105	{
1106		if ($number == 0)
1107			unset($incontext['sql_results'][$key]);
1108		else
1109			$incontext['sql_results'][$key] = sprintf($txt['db_populate_' . $key], $number);
1110	}
1111
1112	// Make sure UTF will be used globally.
1113	if ((!empty($databases[$db_type]['utf8_support']) && !empty($databases[$db_type]['utf8_required'])) || (empty($databases[$db_type]['utf8_required']) && !empty($databases[$db_type]['utf8_support']) && isset($_POST['utf8'])))
1114		$smcFunc['db_insert']('replace',
1115			$db_prefix . 'settings',
1116			array(
1117				'variable' => 'string-255', 'value' => 'string-65534',
1118			),
1119			array(
1120				'global_character_set', 'UTF-8',
1121			),
1122			array('variable')
1123		);
1124
1125	// Maybe we can auto-detect better cookie settings?
1126	preg_match('~^http[s]?://([^\.]+?)([^/]*?)(/.*)?$~', $boardurl, $matches);
1127	if (!empty($matches))
1128	{
1129		// Default = both off.
1130		$localCookies = false;
1131		$globalCookies = false;
1132
1133		// Okay... let's see.  Using a subdomain other than www.? (not a perfect check.)
1134		if ($matches[2] != '' && (strpos(substr($matches[2], 1), '.') === false || in_array($matches[1], array('forum', 'board', 'community', 'forums', 'support', 'chat', 'help', 'talk', 'boards', 'www'))))
1135			$globalCookies = true;
1136		// If there's a / in the middle of the path, or it starts with ~... we want local.
1137		if (isset($matches[3]) && strlen($matches[3]) > 3 && (substr($matches[3], 0, 2) == '/~' || strpos(substr($matches[3], 1), '/') !== false))
1138			$localCookies = true;
1139
1140		if ($globalCookies)
1141			$rows[] = array('globalCookies', '1');
1142		if ($localCookies)
1143			$rows[] = array('localCookies', '1');
1144
1145		if (!empty($rows))
1146		{
1147			$smcFunc['db_insert']('replace',
1148				$db_prefix . 'settings',
1149				array('variable' => 'string-255', 'value' => 'string-65534'),
1150				$rows,
1151				array('variable')
1152			);
1153		}
1154	}
1155
1156	// Are we allowing stat collection?
1157	if (isset($_POST['stats']) && strpos($_POST['boardurl'], 'http://localhost') !== 0)
1158	{
1159		// Attempt to register the site etc.
1160		$fp = @fsockopen("www.simplemachines.org", 80, $errno, $errstr);
1161		if ($fp)
1162		{
1163			$out = "GET /smf/stats/register_stats.php?site=" . base64_encode($_POST['boardurl']) . " HTTP/1.1\r\n";
1164			$out .= "Host: www.simplemachines.org\r\n";
1165			$out .= "Connection: Close\r\n\r\n";
1166			fwrite($fp, $out);
1167
1168			$return_data = '';
1169			while (!feof($fp))
1170				$return_data .= fgets($fp, 128);
1171
1172			fclose($fp);
1173
1174			// Get the unique site ID.
1175			preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1176
1177			if (!empty($ID[1]))
1178				$smcFunc['db_insert']('',
1179					$db_prefix . 'settings',
1180					array(
1181						'variable' => 'string-255', 'value' => 'string-65534',
1182					),
1183					array(
1184						'allow_sm_stats', $ID[1],
1185					),
1186					array('variable')
1187				);
1188		}
1189	}
1190
1191	// As of PHP 5.1, setting a timezone is required.
1192	if (!isset($modSettings['default_timezone']) && function_exists('date_default_timezone_set'))
1193	{
1194		$server_offset = mktime(0, 0, 0, 1, 1, 1970);
1195		$timezone_id = 'Etc/GMT' . ($server_offset > 0 ? '+' : '') . ($server_offset / 3600);
1196		if (date_default_timezone_set($timezone_id))
1197			$smcFunc['db_insert']('',
1198				$db_prefix . 'settings',
1199				array(
1200					'variable' => 'string-255', 'value' => 'string-65534',
1201				),
1202				array(
1203					'default_timezone', $timezone_id,
1204				),
1205				array('variable')
1206			);
1207	}
1208
1209	// Let's optimize those new tables.
1210	db_extend();
1211	$tables = $smcFunc['db_list_tables']($db_name, $db_prefix . '%');
1212	foreach ($tables as $table)
1213	{
1214		$smcFunc['db_optimize_table']($table) != -1 or $db_messed = true;
1215
1216		// Optimizing one sqlite table, optimizes them all
1217		if($db_type == 'sqlite')
1218			break;
1219
1220		if (!empty($db_messed))
1221		{
1222			$incontext['failures'][-1] = $smcFunc['db_error']();
1223			break;
1224		}
1225	}
1226
1227	// Check for the ALTER privilege.
1228	if (!empty($databases[$db_type]['alter_support']) && $smcFunc['db_query']('', "ALTER TABLE {$db_prefix}boards ORDER BY id_board", array('security_override' => true, 'db_error_skip' => true)) === false)
1229	{
1230		$incontext['error'] = $txt['error_db_alter_priv'];
1231		return false;
1232	}
1233
1234	if (!empty($exists))
1235	{
1236		$incontext['page_title'] = $txt['user_refresh_install'];
1237		$incontext['was_refresh'] = true;
1238	}
1239
1240	return false;
1241}
1242
1243// Ask for the administrator login information.
1244function AdminAccount()
1245{
1246	global $txt, $db_type, $db_connection, $databases, $smcFunc, $incontext, $db_prefix, $db_passwd, $sourcedir;
1247
1248	$incontext['sub_template'] = 'admin_account';
1249	$incontext['page_title'] = $txt['user_settings'];
1250	$incontext['continue'] = 1;
1251
1252	// Skipping?
1253	if (!empty($_POST['skip']))
1254		return true;
1255
1256	// Need this to check whether we need the database password.
1257	require(dirname(__FILE__) . '/Settings.php');
1258	load_database();
1259
1260	// Define the sha1 function, if it doesn't exist.
1261	if (!function_exists('sha1') || version_compare(PHP_VERSION, '5', '<'))
1262		require_once($sourcedir . '/Subs-Compat.php');
1263
1264	if (!isset($_POST['username']))
1265		$_POST['username'] = '';
1266	if (!isset($_POST['email']))
1267		$_POST['email'] = '';
1268
1269	$incontext['username'] = htmlspecialchars(stripslashes($_POST['username']));
1270	$incontext['email'] = htmlspecialchars(stripslashes($_POST['email']));
1271
1272	$incontext['require_db_confirm'] = empty($db_type) || $db_type != 'sqlite';
1273
1274	// Only allow skipping if we think they already have an account setup.
1275	$request = $smcFunc['db_query']('', '
1276		SELECT id_member
1277		FROM {db_prefix}members
1278		WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
1279		LIMIT 1',
1280		array(
1281			'db_error_skip' => true,
1282			'admin_group' => 1,
1283		)
1284	);
1285	if ($smcFunc['db_num_rows']($request) != 0)
1286		$incontext['skip'] = 1;
1287	$smcFunc['db_free_result']($request);
1288
1289	// Trying to create an account?
1290	if (isset($_POST['password1']) && !empty($_POST['contbutt']))
1291	{
1292		// Wrong password?
1293		if ($incontext['require_db_confirm'] && $_POST['password3'] != $db_passwd)
1294		{
1295			$incontext['error'] = $txt['error_db_connect'];
1296			return false;
1297		}
1298		// Not matching passwords?
1299		if ($_POST['password1'] != $_POST['password2'])
1300		{
1301			$incontext['error'] = $txt['error_user_settings_again_match'];
1302			return false;
1303		}
1304		// No password?
1305		if (strlen($_POST['password1']) < 4)
1306		{
1307			$incontext['error'] = $txt['error_user_settings_no_password'];
1308			return false;
1309		}
1310		if (!file_exists($sourcedir . '/Subs.php'))
1311		{
1312			$incontext['error'] = $txt['error_subs_missing'];
1313			return false;
1314		}
1315
1316		// Update the main contact email?
1317		if (!empty($_POST['email']) && (empty($webmaster_email) || $webmaster_email == 'noreply@myserver.com'))
1318			updateSettingsFile(array('webmaster_email' => $_POST['email']));
1319
1320		// Work out whether we're going to have dodgy characters and remove them.
1321		$invalid_characters = preg_match('~[<>&"\'=\\\]~', $_POST['username']) != 0;
1322		$_POST['username'] = preg_replace('~[<>&"\'=\\\]~', '', $_POST['username']);
1323
1324		$result = $smcFunc['db_query']('', '
1325			SELECT id_member, password_salt
1326			FROM {db_prefix}members
1327			WHERE member_name = {string:username} OR email_address = {string:email}
1328			LIMIT 1',
1329			array(
1330				'username' => stripslashes($_POST['username']),
1331				'email' => stripslashes($_POST['email']),
1332				'db_error_skip' => true,
1333			)
1334		);
1335		if ($smcFunc['db_num_rows']($result) != 0)
1336		{
1337			list ($incontext['member_id'], $incontext['member_salt']) = $smcFunc['db_fetch_row']($result);
1338			$smcFunc['db_free_result']($result);
1339
1340			$incontext['account_existed'] = $txt['error_user_settings_taken'];
1341		}
1342		elseif ($_POST['username'] == '' || strlen($_POST['username']) > 25)
1343		{
1344			// Try the previous step again.
1345			$incontext['error'] = $_POST['username'] == '' ? $txt['error_username_left_empty'] : $txt['error_username_too_long'];
1346			return false;
1347		}
1348		elseif ($invalid_characters || $_POST['username'] == '_' || $_POST['username'] == '|' || strpos($_POST['username'], '[code') !== false || strpos($_POST['username'], '[/code') !== false)
1349		{
1350			// Try the previous step again.
1351			$incontext['error'] = $txt['error_invalid_characters_username'];
1352			return false;
1353		}
1354		elseif (empty($_POST['email']) || preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', stripslashes($_POST['email'])) === 0 || strlen(stripslashes($_POST['email'])) > 255)
1355		{
1356			// One step back, this time fill out a proper email address.
1357			$incontext['error'] = sprintf($txt['error_valid_email_needed'], $_POST['username']);
1358			return false;
1359		}
1360		elseif ($_POST['username'] != '')
1361		{
1362			$incontext['member_salt'] = substr(md5(mt_rand()), 0, 4);
1363
1364			// Format the username properly.
1365			$_POST['username'] = preg_replace('~[\t\n\r\x0B\0\xA0]+~', ' ', $_POST['username']);
1366			$ip = isset($_SERVER['REMOTE_ADDR']) ? substr($_SERVER['REMOTE_ADDR'], 0, 255) : '';
1367
1368			$request = $smcFunc['db_insert']('',
1369				$db_prefix . 'members',
1370				array(
1371					'member_name' => 'string-25', 'real_name' => 'string-25', 'passwd' => 'string', 'email_address' => 'string',
1372					'id_group' => 'int', 'posts' => 'int', 'date_registered' => 'int', 'hide_email' => 'int',
1373					'password_salt' => 'string', 'lngfile' => 'string', 'personal_text' => 'string', 'avatar' => 'string',
1374					'member_ip' => 'string', 'member_ip2' => 'string', 'buddy_list' => 'string', 'pm_ignore_list' => 'string',
1375					'message_labels' => 'string', 'website_title' => 'string', 'website_url' => 'string', 'location' => 'string',
1376					'aim' => 'string', 'icq' => 'string', 'msn' => 'string', 'signature' => 'string', 'usertitle' => 'string', 'secret_question' => 'string',
1377					'additional_groups' => 'string', 'ignore_boards' => 'string', 'openid_uri' => 'string',
1378				),
1379				array(
1380					stripslashes($_POST['username']), stripslashes($_POST['username']), sha1(strtolower(stripslashes($_POST['username'])) . stripslashes($_POST['password1'])), stripslashes($_POST['email']),
1381					1, 0, time(), 0,
1382					$incontext['member_salt'], '', '', '',
1383					$ip, $ip, '', '',
1384					'', '', '', '',
1385					'', '', '', '', '', '',
1386					'', '', '',
1387				),
1388				array('id_member')
1389			);
1390
1391			// Awww, crud!
1392			if ($request === false)
1393			{
1394				$incontext['error'] = $txt['error_user_settings_query'] . '<br />
1395				<div style="margin: 2ex;">' . nl2br(htmlspecialchars($smcFunc['db_error']($db_connection))) . '</div>';
1396				return false;
1397			}
1398
1399			$incontext['member_id'] = $smcFunc['db_insert_id']("{$db_prefix}members", 'id_member');
1400		}
1401
1402		// If we're here we're good.
1403		return true;
1404	}
1405
1406	return false;
1407}
1408
1409// Final step, clean up and a complete message!
1410function DeleteInstall()
1411{
1412	global $txt, $db_prefix, $db_connection, $HTTP_SESSION_VARS, $cookiename, $incontext;
1413	global $smcFunc, $db_character_set, $mbname, $context, $scripturl, $boardurl;
1414	global $current_smf_version, $databases, $sourcedir, $forum_version, $modSettings, $user_info, $language, $db_type;
1415
1416	$incontext['page_title'] = $txt['congratulations'];
1417	$incontext['sub_template'] = 'delete_install';
1418	$incontext['continue'] = 0;
1419
1420	require(dirname(__FILE__) . '/Settings.php');
1421	load_database();
1422
1423	chdir(dirname(__FILE__));
1424
1425	require_once($sourcedir . '/Errors.php');
1426	require_once($sourcedir . '/Logging.php');
1427	require_once($sourcedir . '/Subs.php');
1428	require_once($sourcedir . '/Load.php');
1429	require_once($sourcedir . '/Security.php');
1430	require_once($sourcedir . '/Subs-Auth.php');
1431
1432	// Bring a warning over.
1433	if (!empty($incontext['account_existed']))
1434		$incontext['warning'] = $incontext['account_existed'];
1435
1436	if (!empty($db_character_set) && !empty($databases[$db_type]['utf8_support']))
1437		$smcFunc['db_query']('', '
1438			SET NAMES {raw:db_character_set}',
1439			array(
1440				'db_character_set' => $db_character_set,
1441				'db_error_skip' => true,
1442			)
1443		);
1444
1445	// As track stats is by default enabled let's add some activity.
1446	$smcFunc['db_insert']('ignore',
1447		'{db_prefix}log_activity',
1448		array('date' => 'date', 'topics' => 'int', 'posts' => 'int', 'registers' => 'int'),
1449		array(strftime('%Y-%m-%d', time()), 1, 1, (!empty($incontext['member_id']) ? 1 : 0)),
1450		array('date')
1451	);
1452
1453	// We're going to want our lovely $modSettings now.
1454	$request = $smcFunc['db_query']('', '
1455		SELECT variable, value
1456		FROM {db_prefix}settings',
1457		array(
1458			'db_error_skip' => true,
1459		)
1460	);
1461	// Only proceed if we can load the data.
1462	if ($request)
1463	{
1464		while ($row = $smcFunc['db_fetch_row']($request))
1465			$modSettings[$row[0]] = $row[1];
1466		$smcFunc['db_free_result']($request);
1467	}
1468
1469	// Automatically log them in ;)
1470	if (isset($incontext['member_id']) && isset($incontext['member_salt']))
1471		setLoginCookie(3153600 * 60, $incontext['member_id'], sha1(sha1(strtolower($_POST['username']) . $_POST['password1']) . $incontext['member_salt']));
1472
1473	$result = $smcFunc['db_query']('', '
1474		SELECT value
1475		FROM {db_prefix}settings
1476		WHERE variable = {string:db_sessions}',
1477		array(
1478			'db_sessions' => 'databaseSession_enable',
1479			'db_error_skip' => true,
1480		)
1481	);
1482	if ($smcFunc['db_num_rows']($result) != 0)
1483		list ($db_sessions) = $smcFunc['db_fetch_row']($result);
1484	$smcFunc['db_free_result']($result);
1485
1486	if (empty($db_sessions))
1487		$_SESSION['admin_time'] = time();
1488	else
1489	{
1490		$_SERVER['HTTP_USER_AGENT'] = substr($_SERVER['HTTP_USER_AGENT'], 0, 211);
1491
1492		$smcFunc['db_insert']('replace',
1493			'{db_prefix}sessions',
1494			array(
1495				'session_id' => 'string', 'last_update' => 'int', 'data' => 'string',
1496			),
1497			array(
1498				session_id(), time(), 'USER_AGENT|s:' . strlen($_SERVER['HTTP_USER_AGENT']) . ':"' . $_SERVER['HTTP_USER_AGENT'] . '";admin_time|i:' . time() . ';',
1499			),
1500			array('session_id')
1501		);
1502	}
1503
1504	updateStats('member');
1505	updateStats('message');
1506	updateStats('topic');
1507
1508	// This function is needed to do the updat…

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