PageRenderTime 77ms CodeModel.GetById 4ms app.highlight 59ms RepoModel.GetById 1ms app.codeStats 0ms

/php/install.php

https://github.com/dekoza/openshift-smf-2.0.7
PHP | 2590 lines | 2070 code | 310 blank | 210 comment | 376 complexity | ad8dd5f7cc263dfcfb0548c2255ee31f 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 2011 Simple Machines
   9 * @license http://www.simplemachines.org/about/smf/license.php BSD
  10 *
  11 * @version 2.0.7
  12 */
  13
  14$GLOBALS['current_smf_version'] = '2.0.7';
  15$GLOBALS['db_script_version'] = '2-0';
  16
  17$GLOBALS['required_php_version'] = '4.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' => false,
  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		'validate_prefix' => create_function('&$value', '
  80			global $incontext, $txt;
  81
  82			$value = preg_replace(\'~[^A-Za-z0-9_\$]~\', \'\', $value);
  83
  84			// Is it reserved?
  85			if ($value == \'sqlite_\')
  86				return $txt[\'error_db_prefix_reserved\'];
  87
  88			// Is the prefix numeric?
  89			if (preg_match(\'~^\d~\', $value))
  90				return $txt[\'error_db_prefix_numeric\'];
  91
  92			return true;
  93		'),
  94	),
  95);
  96
  97// Initialize everything and load the language files.
  98initialize_inputs();
  99load_lang_file();
 100
 101// This is what we are.
 102$installurl = $_SERVER['PHP_SELF'];
 103// This is where SMF is.
 104$smfsite = 'http://www.simplemachines.org/smf';
 105
 106// All the steps in detail.
 107// Number,Name,Function,Progress Weight.
 108$incontext['steps'] = array(
 109	0 => array(1, $txt['install_step_welcome'], 'Welcome', 0),
 110	1 => array(2, $txt['install_step_writable'], 'CheckFilesWritable', 10),
 111	2 => array(3, $txt['install_step_databaseset'], 'DatabaseSettings', 15),
 112	3 => array(4, $txt['install_step_forum'], 'ForumSettings', 40),
 113	4 => array(5, $txt['install_step_databasechange'], 'DatabasePopulation', 15),
 114	5 => array(6, $txt['install_step_admin'], 'AdminAccount', 20),
 115	6 => array(7, $txt['install_step_delete'], 'DeleteInstall', 0),
 116);
 117
 118// Default title...
 119$incontext['page_title'] = $txt['smf_installer'];
 120
 121// What step are we on?
 122$incontext['current_step'] = isset($_GET['step']) ? (int) $_GET['step'] : 0;
 123
 124// Loop through all the steps doing each one as required.
 125$incontext['overall_percent'] = 0;
 126foreach ($incontext['steps'] as $num => $step)
 127{
 128	if ($num >= $incontext['current_step'])
 129	{
 130		// The current weight of this step in terms of overall progress.
 131		$incontext['step_weight'] = $step[3];
 132		// Make sure we reset the skip button.
 133		$incontext['skip'] = false;
 134
 135		// Call the step and if it returns false that means pause!
 136		if (function_exists($step[2]) && $step[2]() === false)
 137			break;
 138		elseif (function_exists($step[2]))
 139			$incontext['current_step']++;
 140
 141		// No warnings pass on.
 142		$incontext['warning'] = '';
 143	}
 144	$incontext['overall_percent'] += $step[3];
 145}
 146
 147// Actually do the template stuff.
 148installExit();
 149
 150function initialize_inputs()
 151{
 152	global $databases, $incontext;
 153
 154	// Just so people using older versions of PHP aren't left in the cold.
 155	if (!isset($_SERVER['PHP_SELF']))
 156		$_SERVER['PHP_SELF'] = isset($GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']) ? $GLOBALS['HTTP_SERVER_VARS']['PHP_SELF'] : 'install.php';
 157
 158	// Turn off magic quotes runtime and enable error reporting.
 159	if (function_exists('set_magic_quotes_runtime'))
 160		@set_magic_quotes_runtime(0);
 161	error_reporting(E_ALL);
 162
 163	// Fun.  Low PHP version...
 164	if (!isset($_GET))
 165	{
 166		$GLOBALS['_GET']['step'] = 0;
 167		return;
 168	}
 169
 170	if (!isset($_GET['obgz']))
 171	{
 172		ob_start();
 173
 174		if (@ini_get('session.save_handler') == 'user')
 175			@ini_set('session.save_handler', 'files');
 176		if (function_exists('session_start'))
 177			@session_start();
 178	}
 179	else
 180	{
 181		ob_start('ob_gzhandler');
 182
 183		if (@ini_get('session.save_handler') == 'user')
 184			@ini_set('session.save_handler', 'files');
 185		session_start();
 186
 187		if (!headers_sent())
 188			echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 189<html xmlns="http://www.w3.org/1999/xhtml">
 190	<head>
 191		<title>', htmlspecialchars($_GET['pass_string']), '</title>
 192	</head>
 193	<body style="background-color: #d4d4d4; margin-top: 16%; text-align: center; font-size: 16pt;">
 194		<strong>', htmlspecialchars($_GET['pass_string']), '</strong>
 195	</body>
 196</html>';
 197		exit;
 198	}
 199
 200	// Are we calling the backup css file?
 201	if (isset($_GET['infile_css']))
 202	{
 203		header('Content-Type: text/css');
 204		template_css();
 205		exit;
 206	}
 207
 208	// Anybody home?
 209	if (!isset($_GET['xml']))
 210	{
 211		$incontext['remote_files_available'] = false;
 212		$test = @fsockopen('www.simplemachines.org', 80, $errno, $errstr, 1);
 213		if ($test)
 214			$incontext['remote_files_available'] = true;
 215		@fclose($test);
 216	}
 217
 218	// Add slashes, as long as they aren't already being added.
 219	if (!function_exists('get_magic_quotes_gpc') || @get_magic_quotes_gpc() == 0)
 220		foreach ($_POST as $k => $v)
 221			$_POST[$k] = addslashes($v);
 222
 223	// This is really quite simple; if ?delete is on the URL, delete the installer...
 224	if (isset($_GET['delete']))
 225	{
 226		if (isset($_SESSION['installer_temp_ftp']))
 227		{
 228			$ftp = new ftp_connection($_SESSION['installer_temp_ftp']['server'], $_SESSION['installer_temp_ftp']['port'], $_SESSION['installer_temp_ftp']['username'], $_SESSION['installer_temp_ftp']['password']);
 229			$ftp->chdir($_SESSION['installer_temp_ftp']['path']);
 230
 231			$ftp->unlink('install.php');
 232			$ftp->unlink('webinstall.php');
 233
 234			foreach ($databases as $key => $dummy)
 235				$ftp->unlink('install_' . $GLOBALS['db_script_version'] . '_' . $key . '.sql');
 236
 237			$ftp->close();
 238
 239			unset($_SESSION['installer_temp_ftp']);
 240		}
 241		else
 242		{
 243			@unlink(__FILE__);
 244			@unlink(dirname(__FILE__) . '/webinstall.php');
 245
 246			foreach ($databases as $key => $dummy)
 247				@unlink(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $key . '.sql');
 248		}
 249
 250		// Now just redirect to a blank.gif...
 251		header('Location: http://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.gif');
 252		exit;
 253	}
 254
 255	// PHP 5 might cry if we don't do this now.
 256	if (function_exists('date_default_timezone_set'))
 257	{
 258		$server_offset = @mktime(0, 0, 0, 1, 1, 1970);
 259		date_default_timezone_set('Etc/GMT' . ($server_offset > 0 ? '+' : '') . ($server_offset / 3600));
 260	}
 261
 262	// Force an integer step, defaulting to 0.
 263	$_GET['step'] = (int) @$_GET['step'];
 264}
 265
 266// Load the list of language files, and the current language file.
 267function load_lang_file()
 268{
 269	global $txt, $incontext;
 270
 271	$incontext['detected_languages'] = array();
 272
 273	// Make sure the languages directory actually exists.
 274	if (file_exists(dirname(__FILE__) . '/Themes/default/languages'))
 275	{
 276		// Find all the "Install" language files in the directory.
 277		$dir = dir(dirname(__FILE__) . '/Themes/default/languages');
 278		while ($entry = $dir->read())
 279		{
 280			if (substr($entry, 0, 8) == 'Install.' && substr($entry, -4) == '.php')
 281				$incontext['detected_languages'][$entry] = ucfirst(substr($entry, 8, strlen($entry) - 12));
 282		}
 283		$dir->close();
 284	}
 285
 286	// Didn't find any, show an error message!
 287	if (empty($incontext['detected_languages']))
 288	{
 289		// Let's not cache this message, eh?
 290		header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
 291		header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
 292		header('Cache-Control: no-cache');
 293
 294		echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 295<html xmlns="http://www.w3.org/1999/xhtml">
 296	<head>
 297		<title>SMF Installer: Error!</title>
 298	</head>
 299	<body style="font-family: sans-serif;"><div style="width: 600px;">
 300		<h1 style="font-size: 14pt;">A critical error has occurred.</h1>
 301
 302		<p>This installer was unable to find the installer\'s language file or files.  They should be found under:</p>
 303
 304		<div style="margin: 1ex; font-family: monospace; font-weight: bold;">', dirname($_SERVER['PHP_SELF']) != '/' ? dirname($_SERVER['PHP_SELF']) : '', '/Themes/default/languages</div>
 305
 306		<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>
 307		<p>If that doesn\'t help, please make sure this install.php file is in the same place as the Themes folder.</p>
 308
 309		<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>
 310	</div></body>
 311</html>';
 312		die;
 313	}
 314
 315	// Override the language file?
 316	if (isset($_GET['lang_file']))
 317		$_SESSION['installer_temp_lang'] = $_GET['lang_file'];
 318	elseif (isset($GLOBALS['HTTP_GET_VARS']['lang_file']))
 319		$_SESSION['installer_temp_lang'] = $GLOBALS['HTTP_GET_VARS']['lang_file'];
 320
 321	// Make sure it exists, if it doesn't reset it.
 322	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']))
 323	{
 324		// Use the first one...
 325		list ($_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
 326
 327		// If we have english and some other language, use the other language.  We Americans hate english :P.
 328		if ($_SESSION['installer_temp_lang'] == 'Install.english.php' && count($incontext['detected_languages']) > 1)
 329			list (, $_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
 330	}
 331
 332	// And now include the actual language file itself.
 333	require_once(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']);
 334}
 335
 336// This handy function loads some settings and the like.
 337function load_database()
 338{
 339	global $db_prefix, $db_connection, $db_character_set, $sourcedir, $language;
 340	global $smcFunc, $mbname, $scripturl, $boardurl, $modSettings, $db_type, $db_name, $db_user;
 341
 342	if (empty($sourcedir))
 343		$sourcedir = dirname(__FILE__) . '/Sources';
 344
 345	// Need this to check whether we need the database password.
 346	require(dirname(__FILE__) . '/Settings.php');
 347	if (!defined('SMF'))
 348		define('SMF', 1);
 349	if (empty($smcFunc))
 350		$smcFunc = array();
 351
 352	$modSettings['disableQueryCheck'] = true;
 353
 354	// Connect the database.
 355	if (!$db_connection)
 356	{
 357		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
 358		if (@version_compare(PHP_VERSION, '5') == -1)
 359			require_once($sourcedir . '/Subs-Compat.php');
 360
 361		if (!$db_connection)
 362			$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('persist' => $db_persist));
 363	}
 364}
 365
 366// This is called upon exiting the installer, for template etc.
 367function installExit($fallThrough = false)
 368{
 369	global $incontext, $installurl, $txt;
 370
 371	// Send character set.
 372	header('Content-Type: text/html; charset=' . (isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'ISO-8859-1'));
 373
 374	// We usually dump our templates out.
 375	if (!$fallThrough)
 376	{
 377		// The top install bit.
 378		template_install_above();
 379
 380		// Call the template.
 381		if (isset($incontext['sub_template']))
 382		{
 383			$incontext['form_url'] = $installurl . '?step=' . $incontext['current_step'];
 384
 385			call_user_func('template_' . $incontext['sub_template']);
 386		}
 387		//!!! REMOVE THIS!!
 388		else
 389		{
 390			if (function_exists('doStep' . $_GET['step']))
 391				call_user_func('doStep' . $_GET['step']);
 392		}
 393		// Show the footer.
 394		template_install_below();
 395	}
 396
 397	// Bang - gone!
 398	die();
 399}
 400
 401function Welcome()
 402{
 403	global $incontext, $txt, $databases, $installurl;
 404
 405	$incontext['page_title'] = $txt['install_welcome'];
 406	$incontext['sub_template'] = 'welcome_message';
 407
 408	// Done the submission?
 409	if (isset($_POST['contbutt']))
 410		return true;
 411
 412	// Check the PHP version.
 413	if ((!function_exists('version_compare') || version_compare($GLOBALS['required_php_version'], PHP_VERSION) > 0))
 414	{
 415		$incontext['warning'] = $txt['error_php_too_low'];
 416	}
 417
 418	// See if we think they have already installed it?
 419	if (is_readable(dirname(__FILE__) . '/Settings.php'))
 420	{
 421		$probably_installed = 0;
 422		foreach (file(dirname(__FILE__) . '/Settings.php') as $line)
 423		{
 424			if (preg_match('~^\$db_passwd\s=\s\'([^\']+)\';$~', $line))
 425				$probably_installed++;
 426			if (preg_match('~^\$boardurl\s=\s\'([^\']+)\';~', $line) && !preg_match('~^\$boardurl\s=\s\'http://127\.0\.0\.1/smf\';~', $line))
 427				$probably_installed++;
 428		}
 429
 430		if ($probably_installed == 2)
 431			$incontext['warning'] = $txt['error_already_installed'];
 432	}
 433
 434	// Is some database support even compiled in?
 435	$incontext['supported_databases'] = array();
 436	foreach ($databases as $key => $db)
 437	{
 438		if ($db['supported'])
 439		{
 440			if (!file_exists(dirname(__FILE__) . '/install_' . $GLOBALS['db_script_version'] . '_' . $key . '.sql'))
 441			{
 442				$databases[$key]['supported'] = false;
 443				$notFoundSQLFile = true;
 444				$txt['error_db_script_missing'] = sprintf($txt['error_db_script_missing'], 'install_' . $GLOBALS['db_script_version'] . '_' . $key . '.sql');
 445			}
 446			else
 447			{
 448				$db_type = $key;
 449				$incontext['supported_databases'][] = $db;
 450			}
 451		}
 452	}
 453
 454	if (empty($incontext['supported_databases']))
 455		$error = empty($notFoundSQLFile) ? 'error_db_missing' : 'error_db_script_missing';
 456	// How about session support?  Some crazy sysadmin remove it?
 457	elseif (!function_exists('session_start'))
 458		$error = 'error_session_missing';
 459	// Make sure they uploaded all the files.
 460	elseif (!file_exists(dirname(__FILE__) . '/index.php'))
 461		$error = 'error_missing_files';
 462	// Very simple check on the session.save_path for Windows.
 463	// !!! Move this down later if they don't use database-driven sessions?
 464	elseif (@ini_get('session.save_path') == '/tmp' && substr(__FILE__, 1, 2) == ':\\')
 465		$error = 'error_session_save_path';
 466
 467	// Since each of the three messages would look the same, anyway...
 468	if (isset($error))
 469		$incontext['error'] = $txt[$error];
 470
 471	// Mod_security blocks everything that smells funny. Let SMF handle security.
 472	if (!fixModSecurity() && !isset($_GET['overmodsecurity']))
 473		$incontext['error'] = $txt['error_mod_security'] . '<br /><br /><a href="' . $installurl . '?overmodsecurity=true">' . $txt['error_message_click'] . '</a> ' . $txt['error_message_bad_try_again'];
 474
 475	return false;
 476}
 477
 478function CheckFilesWritable()
 479{
 480	global $txt, $incontext;
 481
 482	$incontext['page_title'] = $txt['ftp_checking_writable'];
 483	$incontext['sub_template'] = 'chmod_files';
 484
 485	$writable_files = array(
 486		'attachments',
 487		'avatars',
 488		'cache',
 489		'Packages',
 490		'Packages/installed.list',
 491		'Smileys',
 492		'Themes',
 493		'agreement.txt',
 494		'Settings.php',
 495		'Settings_bak.php'
 496	);
 497	$extra_files = array(
 498		'Themes/classic/index.template.php',
 499		'Themes/classic/style.css'
 500	);
 501	foreach ($incontext['detected_languages'] as $lang => $temp)
 502		$extra_files[] = 'Themes/default/languages/' . $lang;
 503
 504	// With mod_security installed, we could attempt to fix it with .htaccess.
 505	if (function_exists('apache_get_modules') && in_array('mod_security', apache_get_modules()))
 506		$writable_files[] = file_exists(dirname(__FILE__) . '/.htaccess') ? '.htaccess' : '.';
 507
 508	$failed_files = array();
 509
 510	// On linux, it's easy - just use is_writable!
 511	if (substr(__FILE__, 1, 2) != ':\\')
 512	{
 513		foreach ($writable_files as $file)
 514		{
 515			if (!is_writable(dirname(__FILE__) . '/' . $file))
 516			{
 517				@chmod(dirname(__FILE__) . '/' . $file, 0755);
 518
 519				// Well, 755 hopefully worked... if not, try 777.
 520				if (!is_writable(dirname(__FILE__) . '/' . $file) && !@chmod(dirname(__FILE__) . '/' . $file, 0777))
 521					$failed_files[] = $file;
 522			}
 523		}
 524		foreach ($extra_files as $file)
 525			@chmod(dirname(__FILE__) . (empty($file) ? '' : '/' . $file), 0777);
 526	}
 527	// Windows is trickier.  Let's try opening for r+...
 528	else
 529	{
 530		foreach ($writable_files as $file)
 531		{
 532			// Folders can't be opened for write... but the index.php in them can ;)
 533			if (is_dir(dirname(__FILE__) . '/' . $file))
 534				$file .= '/index.php';
 535
 536			// Funny enough, chmod actually does do something on windows - it removes the read only attribute.
 537			@chmod(dirname(__FILE__) . '/' . $file, 0777);
 538			$fp = @fopen(dirname(__FILE__) . '/' . $file, 'r+');
 539
 540			// Hmm, okay, try just for write in that case...
 541			if (!is_resource($fp))
 542				$fp = @fopen(dirname(__FILE__) . '/' . $file, 'w');
 543
 544			if (!is_resource($fp))
 545				$failed_files[] = $file;
 546
 547			@fclose($fp);
 548		}
 549		foreach ($extra_files as $file)
 550			@chmod(dirname(__FILE__) . (empty($file) ? '' : '/' . $file), 0777);
 551	}
 552
 553	$failure = count($failed_files) >= 1;
 554
 555	if (!isset($_SERVER))
 556		return !$failure;
 557
 558	// Put the list into context.
 559	$incontext['failed_files'] = $failed_files;
 560
 561	// It's not going to be possible to use FTP on windows to solve the problem...
 562	if ($failure && substr(__FILE__, 1, 2) == ':\\')
 563	{
 564		$incontext['error'] = $txt['error_windows_chmod'] . '
 565					<ul style="margin: 2.5ex; font-family: monospace;">
 566						<li>' . implode('</li>
 567						<li>', $failed_files) . '</li>
 568					</ul>';
 569
 570		return false;
 571	}
 572	// We're going to have to use... FTP!
 573	elseif ($failure)
 574	{
 575		// Load any session data we might have...
 576		if (!isset($_POST['ftp_username']) && isset($_SESSION['installer_temp_ftp']))
 577		{
 578			$_POST['ftp_server'] = $_SESSION['installer_temp_ftp']['server'];
 579			$_POST['ftp_port'] = $_SESSION['installer_temp_ftp']['port'];
 580			$_POST['ftp_username'] = $_SESSION['installer_temp_ftp']['username'];
 581			$_POST['ftp_password'] = $_SESSION['installer_temp_ftp']['password'];
 582			$_POST['ftp_path'] = $_SESSION['installer_temp_ftp']['path'];
 583		}
 584
 585		$incontext['ftp_errors'] = array();
 586
 587		if (isset($_POST['ftp_username']))
 588		{
 589			$ftp = new ftp_connection($_POST['ftp_server'], $_POST['ftp_port'], $_POST['ftp_username'], $_POST['ftp_password']);
 590
 591			if ($ftp->error === false)
 592			{
 593				// Try it without /home/abc just in case they messed up.
 594				if (!$ftp->chdir($_POST['ftp_path']))
 595				{
 596					$incontext['ftp_errors'][] = $ftp->last_message;
 597					$ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $_POST['ftp_path']));
 598				}
 599			}
 600		}
 601
 602		if (!isset($ftp) || $ftp->error !== false)
 603		{
 604			if (!isset($ftp))
 605				$ftp = new ftp_connection(null);
 606			// Save the error so we can mess with listing...
 607			elseif ($ftp->error !== false && empty($incontext['ftp_errors']) && !empty($ftp->last_message))
 608				$incontext['ftp_errors'][] = $ftp->last_message;
 609
 610			list ($username, $detect_path, $found_path) = $ftp->detect_path(dirname(__FILE__));
 611
 612			if (empty($_POST['ftp_path']) && $found_path)
 613				$_POST['ftp_path'] = $detect_path;
 614
 615			if (!isset($_POST['ftp_username']))
 616				$_POST['ftp_username'] = $username;
 617
 618			// Set the username etc, into context.
 619			$incontext['ftp'] = array(
 620				'server' => isset($_POST['ftp_server']) ? $_POST['ftp_server'] : 'localhost',
 621				'port' => isset($_POST['ftp_port']) ? $_POST['ftp_port'] : '21',
 622				'username' => isset($_POST['ftp_username']) ? $_POST['ftp_username'] : '',
 623				'path' => isset($_POST['ftp_path']) ? $_POST['ftp_path'] : '/',
 624				'path_msg' => !empty($found_path) ? $txt['ftp_path_found_info'] : $txt['ftp_path_info'],
 625			);
 626
 627			return false;
 628		}
 629		else
 630		{
 631			$_SESSION['installer_temp_ftp'] = array(
 632				'server' => $_POST['ftp_server'],
 633				'port' => $_POST['ftp_port'],
 634				'username' => $_POST['ftp_username'],
 635				'password' => $_POST['ftp_password'],
 636				'path' => $_POST['ftp_path']
 637			);
 638
 639			$failed_files_updated = array();
 640
 641			foreach ($failed_files as $file)
 642			{
 643				if (!is_writable(dirname(__FILE__) . '/' . $file))
 644					$ftp->chmod($file, 0755);
 645				if (!is_writable(dirname(__FILE__) . '/' . $file))
 646					$ftp->chmod($file, 0777);
 647				if (!is_writable(dirname(__FILE__) . '/' . $file))
 648				{
 649					$failed_files_updated[] = $file;
 650					$incontext['ftp_errors'][] = rtrim($ftp->last_message) . ' -> ' . $file . "\n";
 651				}
 652			}
 653
 654			$ftp->close();
 655
 656			// Are there any errors left?
 657			if (count($failed_files_updated) >= 1)
 658			{
 659				// Guess there are...
 660				$incontext['failed_files'] = $failed_files_updated;
 661
 662				// Set the username etc, into context.
 663				$incontext['ftp'] = $_SESSION['installer_temp_ftp'] += array(
 664					'path_msg' => $txt['ftp_path_info'],
 665				);
 666
 667				return false;
 668			}
 669		}
 670	}
 671
 672	return true;
 673}
 674
 675function DatabaseSettings()
 676{
 677	global $txt, $databases, $incontext, $smcFunc;
 678
 679	$incontext['sub_template'] = 'database_settings';
 680	$incontext['page_title'] = $txt['db_settings'];
 681	$incontext['continue'] = 1;
 682
 683	// Set up the defaults.
 684	$incontext['db']['server'] = 'localhost';
 685	$incontext['db']['user'] = '';
 686	$incontext['db']['name'] = '';
 687	$incontext['db']['pass'] = '';
 688	$incontext['db']['type'] = '';
 689	$incontext['supported_databases'] = array();
 690
 691	$foundOne = false;
 692	foreach ($databases as $key => $db)
 693	{
 694		// Override with the defaults for this DB if appropriate.
 695		if ($db['supported'])
 696		{
 697			$incontext['supported_databases'][$key] = $db;
 698
 699			if (!$foundOne)
 700			{
 701				if (isset($db['default_host']))
 702					$incontext['db']['server'] = @ini_get($db['default_host']) or $incontext['db']['server'] = 'localhost';
 703				if (isset($db['default_user']))
 704				{
 705					$incontext['db']['user'] = @ini_get($db['default_user']);
 706					$incontext['db']['name'] = @ini_get($db['default_user']);
 707				}
 708				if (isset($db['default_password']))
 709					$incontext['db']['pass'] = @ini_get($db['default_password']);
 710				if (isset($db['default_port']))
 711					$db_port = @ini_get($db['default_port']);
 712
 713				$incontext['db']['type'] = $key;
 714				$foundOne = true;
 715			}
 716		}
 717	}
 718
 719	// Override for repost.
 720	if (isset($_POST['db_user']))
 721	{
 722		$incontext['db']['user'] = $_POST['db_user'];
 723		$incontext['db']['name'] = $_POST['db_type'] == 'sqlite' && isset($_POST['db_filename']) ? $_POST['db_filename'] : $_POST['db_name'];
 724		$incontext['db']['server'] = $_POST['db_server'];
 725		$incontext['db']['prefix'] = $_POST['db_prefix'];
 726	}
 727	else
 728		$incontext['db']['prefix'] = 'smf_';
 729
 730	// Should we use a non standard port?
 731	if (!empty($db_port))
 732		$incontext['db']['server'] .= ':' . $db_port;
 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		require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
 803
 804		// What - running PHP4? The shame!
 805		if (@version_compare(PHP_VERSION, '5') == -1)
 806			require_once($sourcedir . '/Subs-Compat.php');
 807
 808		// Attempt a connection.
 809		$needsDB = !empty($databases[$db_type]['always_has_db']);
 810		$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, array('non_fatal' => true, 'dont_select_db' => !$needsDB));
 811
 812		// No dice?  Let's try adding the prefix they specified, just in case they misread the instructions ;)
 813		if ($db_connection == null)
 814		{
 815			$db_error = @$smcFunc['db_error']();
 816
 817			$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));
 818			if ($db_connection != null)
 819			{
 820				$db_user = $_POST['db_prefix'] . $db_user;
 821				updateSettingsFile(array('db_user' => $db_user));
 822			}
 823		}
 824
 825		// Still no connection?  Big fat error message :P.
 826		if (!$db_connection)
 827		{
 828			$incontext['error'] = $txt['error_db_connect'] . '<div style="margin: 2.5ex; font-family: monospace;"><strong>' . $db_error . '</strong></div>';
 829			return false;
 830		}
 831
 832		// Do they meet the install requirements?
 833		// !!! Old client, new server?
 834		if (version_compare($databases[$db_type]['version'], preg_replace('~^\D*|\-.+?$~', '', eval($databases[$db_type]['version_check']))) > 0)
 835		{
 836			$incontext['error'] = $txt['error_db_too_low'];
 837			return false;
 838		}
 839
 840		// Let's try that database on for size... assuming we haven't already lost the opportunity.
 841		if ($db_name != '' && !$needsDB)
 842		{
 843			$smcFunc['db_query']('', "
 844				CREATE DATABASE IF NOT EXISTS `$db_name`",
 845				array(
 846					'security_override' => true,
 847					'db_error_skip' => true,
 848				),
 849				$db_connection
 850			);
 851
 852			// Okay, let's try the prefix if it didn't work...
 853			if (!$smcFunc['db_select_db']($db_name, $db_connection) && $db_name != '')
 854			{
 855				$smcFunc['db_query']('', "
 856					CREATE DATABASE IF NOT EXISTS `$_POST[db_prefix]$db_name`",
 857					array(
 858						'security_override' => true,
 859						'db_error_skip' => true,
 860					),
 861					$db_connection
 862				);
 863
 864				if ($smcFunc['db_select_db']($_POST['db_prefix'] . $db_name, $db_connection))
 865				{
 866					$db_name = $_POST['db_prefix'] . $db_name;
 867					updateSettingsFile(array('db_name' => $db_name));
 868				}
 869			}
 870
 871			// Okay, now let's try to connect...
 872			if (!$smcFunc['db_select_db']($db_name, $db_connection))
 873			{
 874				$incontext['error'] = sprintf($txt['error_db_database'], $db_name);
 875				return false;
 876			}
 877		}
 878
 879		return true;
 880	}
 881
 882	return false;
 883}
 884
 885// Let's start with basic forum type settings.
 886function ForumSettings()
 887{
 888	global $txt, $incontext, $databases, $smcFunc, $db_connection, $db_type;
 889
 890	$incontext['sub_template'] = 'forum_settings';
 891	$incontext['page_title'] = $txt['install_settings'];
 892
 893	// Let's see if we got the database type correct.
 894	if (isset($_POST['db_type'], $databases[$_POST['db_type']]))
 895		$db_type = $_POST['db_type'];
 896
 897	// Else we'd better be able to get the connection.
 898	else
 899		load_database();
 900
 901	$db_type = isset($_POST['db_type']) ? $_POST['db_type'] : $db_type;
 902
 903	// What host and port are we on?
 904	$host = empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST'];
 905
 906	// Now, to put what we've learned together... and add a path.
 907	$incontext['detected_url'] = 'http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . $host . substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
 908
 909	// Check if the database sessions will even work.
 910	$incontext['test_dbsession'] = @ini_get('session.auto_start') != 1 && @version_compare(PHP_VERSION, '4.2.0') != -1;
 911	$incontext['utf8_should_work'] = strpos(strtolower(PHP_OS), 'win') === false || @version_compare(PHP_VERSION, '4.2.3') != -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 (isset($_POST['utf8']) && !empty($databases[$db_type]['utf8_support']))
 949		{
 950			if (version_compare($databases[$db_type]['utf8_version'], preg_replace('~\-.+?$~', '', eval($databases[$db_type]['utf8_version_check']))) > 0)
 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
1007	// If doing UTF8, select it. PostgreSQL requires passing it as a string...
1008	if (!empty($db_character_set) && $db_character_set == 'utf8' && !empty($databases[$db_type]['utf8_support']))
1009		$smcFunc['db_query']('', '
1010			SET NAMES {'. ($db_type == 'postgresql' ? 'string' : 'raw') . ':utf8}',
1011			array(
1012				'db_error_skip' => true,
1013				'utf8' => 'utf8',
1014			)
1015		);
1016
1017	$replaces = array(
1018		'{$db_prefix}' => $db_prefix,
1019		'{$boarddir}' => $smcFunc['db_escape_string'](dirname(__FILE__)),
1020		'{$boardurl}' => $boardurl,
1021		'{$enableCompressedOutput}' => isset($_POST['compress']) ? '1' : '0',
1022		'{$databaseSession_enable}' => isset($_POST['dbsession']) ? '1' : '0',
1023		'{$smf_version}' => $GLOBALS['current_smf_version'],
1024		'{$current_time}' => time(),
1025		'{$sched_task_offset}' => 82800 + mt_rand(0, 86399),
1026	);
1027
1028	foreach ($txt as $key => $value)
1029	{
1030		if (substr($key, 0, 8) == 'default_')
1031			$replaces['{$' . $key . '}'] = $smcFunc['db_escape_string']($value);
1032	}
1033	$replaces['{$default_reserved_names}'] = strtr($replaces['{$default_reserved_names}'], array('\\\\n' => '\\n'));
1034
1035	// If the UTF-8 setting was enabled, add it to the table definitions.
1036	//!!! Very MySQL specific still
1037	if ($db_type == 'mysql' && 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			//!!! 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 (isset($_POST['utf8']) && !empty($databases[$db_type]['utf8_support']))
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		$rows = array();
1141		if ($globalCookies)
1142			$rows[] = array('globalCookies', '1');
1143		if ($localCookies)
1144			$rows[] = array('localCookies', '1');
1145
1146		if (!empty($rows))
1147		{
1148			$smcFunc['db_insert']('replace',
1149				$db_prefix . 'settings',
1150				array('variable' => 'string-255', 'value' => 'string-65534'),
1151				$rows,
1152				array('variable')
1153			);
1154		}
1155	}
1156
1157	// Are we allowing stat collection?
1158	if (isset($_POST['stats']) && substr($_POST['boardurl'], 0, 16) != 'http://localhost')
1159	{
1160		// Attempt to register the site etc.
1161		$fp = @fsockopen("www.simplemachines.org", 80, $errno, $errstr);
1162		if ($fp)
1163		{
1164			$out = "GET /smf/stats/register_stats.php?site=" . base64_encode($_POST['boardurl']) . " HTTP/1.1\r\n";
1165			$out .= "Host: www.simplemachines.org\r\n";
1166			$out .= "Connection: Close\r\n\r\n";
1167			fwrite($fp, $out);
1168
1169			$return_data = '';
1170			while (!feof($fp))
1171				$return_data .= fgets($fp, 128);
1172
1173			fclose($fp);
1174
1175			// Get the unique site ID.
1176			preg_match('~SITE-ID:\s(\w{10})~', $return_data, $ID);
1177
1178			if (!empty($ID[1]))
1179				$smcFunc['db_insert']('',
1180					$db_prefix . 'settings',
1181					array(
1182						'variable' => 'string-255', 'value' => 'string-65534',
1183					),
1184					array(
1185						'allow_sm_stats', $ID[1],
1186					),
1187					array('variable')
1188				);
1189		}
1190	}
1191
1192	// As of PHP 5.1, setting a timezone is required.
1193	if (!isset($modSettings['default_timezone']) && function_exists('date_default_timezone_set'))
1194	{
1195		$server_offset = mktime(0, 0, 0, 1, 1, 1970);
1196		$timezone_id = 'Etc/GMT' . ($server_offset > 0 ? '+' : '') . ($server_offset / 3600);
1197		if (date_default_timezone_set($timezone_id))
1198			$smcFunc['db_insert']('',
1199				$db_prefix . 'settings',
1200				array(
1201					'variable' => 'string-255', 'value' => 'string-65534',
1202				),
1203				array(
1204					'default_timezone', $timezone_id,
1205				),
1206				array('variable')
1207			);
1208	}
1209
1210	// Let's optimize those new tables.
1211	db_extend();
1212	$tables = $smcFunc['db_list_tables']($db_name, $db_prefix . '%');
1213	foreach ($tables as $table)
1214	{
1215		$smcFunc['db_optimize_table']($table) != -1 or $db_messed = true;
1216
1217		// Optimizing one sqlite table, optimizes them all
1218		if($db_type == 'sqlite')
1219			break;
1220
1221		if (!empty($db_messed))
1222		{
1223			$incontext['failures'][-1] = $smcFunc['db_error']();
1224			break;
1225		}
1226	}
1227
1228	// Check for the ALTER privilege.
1229	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)
1230	{
1231		$incontext['error'] = $txt['error_db_alter_priv'];
1232		return false;
1233	}
1234
1235	if (!empty($exists))
1236	{
1237		$incontext['page_title'] = $txt['user_refresh_install'];
1238		$incontext['was_refresh'] = true;
1239	}
1240
1241	return false;
1242}
1243
1244// Ask for the administrator login information.
1245function AdminAccount()
1246{
1247	global $txt, $db_type, $db_connection, $databases, $smcFunc, $incontext, $db_prefix, $db_passwd, $sourcedir;
1248
1249	$incontext['sub_template'] = 'admin_account';
1250	$incontext['page_title'] = $txt['user_settings'];
1251	$incontext['continue'] = 1;
1252
1253	// Skipping?
1254	if (!empty($_POST['skip']))
1255		return true;
1256
1257	// Need this to check whether we need the database password.
1258	require(dirname(__FILE__) . '/Settings.php');
1259	load_database();
1260
1261	// Define the sha1 function, if it doesn't exist.
1262	if (!function_exists('sha1') || @version_compare(PHP_VERSION, '5') == -1)
1263		require_once($sourcedir . '/Subs-Compat.php');
1264
1265	if (!isset($_POST['username']))
1266		$_POST['username'] = '';
1267	if (!isset($_POST['email']))
1268		$_POST['email'] = '';
1269
1270	$incontext['username'] = htmlspecialchars(stripslashes($_POST['username']));
1271	$incontext['email'] = htmlspecialchars(stripslashes($_POST['email']));
1272
1273	$incontext['require_db_confirm'] = empty($db_type) || $db_type != 'sqlite';
1274
1275	// Only allow skipping if we think they already have an account setup.
1276	$request = $smcFunc['db_query']('', '
1277		SELECT id_member
1278		FROM {db_prefix}members
1279		WHERE id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0
1280		LIMIT 1',
1281		array(
1282			'db_error_skip' => true,
1283			'admin_group' => 1,
1284		)
1285	);
1286	if ($smcFunc['db_num_rows']($request) != 0)
1287		$incontext['skip'] = 1;
1288	$smcFunc['db_free_result']($request);
1289
1290	// Trying to create an account?
1291	if (isset($_POST['password1']) && !empty($_POST['contbutt']))
1292	{
1293		// Wrong password?
1294		if ($incontext['require_db_confirm'] && $_POST['password3'] != $db_passwd)
1295		{
1296			$incontext['error'] = $txt['error_db_connect'];
1297			return false;
1298		}
1299		// Not matching passwords?
1300		if ($_POST['password1'] != $_POST['password2'])
1301		{
1302			$incontext['error'] = $txt['error_user_settings_again_match'];
1303			return false;
1304		}
1305		// No password?
1306		if (strlen($_POST['password1']) < 4)
1307		{
1308			$incontext['error'] = $txt['error_user_settings_no_password'];
1309			return false;
1310		}
1311		if (!file_exists($sourcedir . '/Subs.php'))
1312		{
1313			$incontext['error'] = $txt['error_subs_missing'];
1314			return false;
1315		}
1316
1317		// Update the main contact email?
1318		if (!empty($_POST['email']) && (empty($webmaster_email) || $webmaster_email == 'noreply@myserver.com'))
1319			updateSettingsFile(array('webmaster_email' => $_POST['email']));
1320
1321		// Work out whether we're going to have dodgy characters and remove them.
1322		$invalid_characters = preg_match('~[<>&"\'=\\\]~', $_POST['username']) != 0;
1323		$_POST['username'] = preg_replace('~[<>&"\'=\\\]~', '', $_POST['username']);
1324
1325		$result = $smcFunc['db_query']('', '
1326			SELECT id_member, password_salt
1327			FROM {db_prefix}members
1328			WHERE member_name = {string:username} OR email_address = {string:email}
1329			LIMIT 1',
1330			array(
1331				'username' => stripslashes($_POST['username']),
1332				'email' => stripslashes($_POST['email']),
1333				'db_error_skip' => true,
1334			)
1335		);
1336		if ($smcFunc['db_num_rows']($result) != 0)
1337		{
1338			list ($incontext['member_id'], $incontext['member_salt']) = $smcFunc['db_fetch_row']($result);
1339			$smcFunc['db_free_result']($result);
1340
1341			$incontext['account_existed'] = $txt['error_user_settings_taken'];
1342		}
1343		elseif ($_POST['username'] == '' || strlen($_POST['username']) > 25)
1344		{
1345			// Try the previous step again.
1346			$incontext['error'] = $_POST['username'] == '' ? $txt['error_username_left_empty'] : $txt['error_username_too_long'];
1347			return false;
1348		}
1349		elseif ($invalid_characters || $_POST['username'] == '_' || $_POST['username'] == '|' || strpos($_POST['username'], '[code') !== false || strpos($_POST['username'], '[/code') !== false)
1350		{
1351			// Try the previous step again.
1352			$incontext['error'] = $txt['error_invalid_characters_username'];
1353			return false;
1354		}
1355		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)
1356		{
1357			// One step back, this time fill out a proper email address.
1358			$incontext['error'] = sprintf($txt['error_valid_email_needed'], $_POST['username']);
1359			return false;
1360		}
1361		elseif ($_POST['username'] != '')
1362		{
1363			$incontext['member_salt'] = substr(md5(mt_rand()), 0, 4);
1364
1365			// Format the username properly.
1366			$_POST['username'] = preg_replace('~[\t\n\r\x0B\0\xA0]+~', ' ', $_POST['username']);
1367			$ip = isset($_SERVER['REMOTE_ADDR']) ? substr($_SERVER['REMOTE_ADDR'], 0, 255) : '';
1368
1369			$request = $smcFunc['db_insert']('',
1370				$db_prefix . 'members',
1371				array(
1372					'member_name' => 'string-25', 'real_name' => 'string-25', 'passwd' => 'string', 'email_address' => 'string',
1373					'id_group' => 'int', 'posts' => 'int', 'date_registered' => 'int', 'hide_email' => 'int',
1374					'password_salt' => 'string', 'lngfile' => 'string', 'personal_text' => 'string', 'avatar' => 'string',
1375					'member_ip' => 'string', 'member_ip2' => 'string', 'buddy_list' => 'string', 'pm_ignore_list' => 'string',
1376					'message_labels' => 'string', 'website_title' => 'string', 'website_url' => 'string', 'location' => 'string',
1377					'aim' => 'string', 'icq' => 'string', 'msn' => 'string', 'signature' => 'string', 'usertitle' => 'string', 'secret_question' => 'string',
1378					'additional_groups' => 'string', 'ignore_boards' => 'string', 'openid_uri' => 'string',
1379				),
1380				array(
1381					stripslashes($_POST['username']), stripslashes($_POST['username']), sha1(strtolower(stripslashes($_POST['username'])) . stripslashes($_POST['password1'])), stripslashes($_POST['email']),
1382					1, 0, time(), 0,
1383					$incontext['member_salt'], '', '', '',
1384					$ip, $ip, '', '',
1385					'', '', '', '',
1386					'', '', '', '', '', '',
1387					'', '', '',
1388				),
1389				array('id_member')
1390			);
1391
1392			// Awww, crud!
1393			if ($request === false)
1394			{
1395				$incontext['error'] = $txt['error_user_settings_query'] . '<br />
1396				<div style="margin: 2ex;">' . nl2br(htmlspecialchars($smcFunc['db_error']($db_connection))) . '</div>';
1397				return false;
1398			}
1399
1400			$incontext['member_id'] = $smcFunc['db_insert_id']("{$db_prefix}members", 'id_member');
1401		}
1402
1403		// If we're here we're good.
1404		return true;
1405	}
1406
1407	return false;
1408}
1409
1410// Final step, clean up and a complete message!
1411function DeleteInstall()
1412{
1413	global $txt, $db_prefix, $db_connection, $HTTP_SESSION_VARS, $cookiename, $incontext;
1414	global $smcFunc, $db_character_set, $mbname, $context, $scripturl, $boardurl;
1415	global $current_smf_version, $databases, $sourcedir, $forum_version, $modSettings, $user_info, $language, $db_type;
1416
1417	$incontext['page_title'] = $txt['congratulations'];
1418	$incontext['sub_template'] = 'delete_install';
1419	$incontext['continue'] = 0;
1420
1421	require(dirname(__FILE__) . '/Settings.php');
1422	load_database();
1423
1424	chdir(dirname(__FILE__));
1425
1426	require_once($sourcedir . '/Errors.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	// Automatically log them in ;)
1454	if (isset($incontext['member_id']) && isset($incontext['member_salt']))
1455		setLoginCookie(3153600 * 60, $incontext['member_id'], sha1(sha1(strtolower($_POST['username']) . $_POST['password1']) . $incontext['member_salt']));
1456
1457	$result = $smcFunc['db_query']('', '
1458		SELECT value
1459		FROM {db_prefix}settings
1460		WHERE variable = {string:db_sessions}',
1461		array(
1462			'db_sessions' => 'databaseSession_enable',
1463			'db_error_skip' => true,
1464		)
1465	);
1466	if ($smcFunc['db_num_rows']($result) != 0)
1467		list ($db_sessions) = $smcFunc['db_fetch_row']($result);
1468	$smcFunc['db_free_result']($result);
1469
1470	if (empty($db_sessions))
1471	{
1472		if (@version_compare(PHP_VERSION, '4.2.0') == -1)
1473			$HTTP_SESSION_VARS['php_412_bugfix'] = true;
1474		$_SESSION['admin_time'] = time();
1475	}
1476	else
1477	{
1478		$_SERVER['HTTP_USER_AGENT'] = substr($_SERVER['HTTP_USER_AGENT'], 0, 211);
1479
1480		$smcFunc['db_insert']('replace',
1481			'{db_prefix}sessions',
1482			array(
1483				'session_id' => 'string', 'last_update' => 'int', 'data' => 'string',
1484			),
1485			array(
1486				session_id(), time(), 'USER_AGENT|s:' . strlen($_SERVER['HTTP_USER_AGENT']) . ':"' . $_SERVER['HTTP_USER_AGENT'] . '";admin_time|i:' . time() . ';',
1487			),
1488			array('session_id')
1489		);
1490	}
1491
1492	// We're going to want our lovely $modSettings now.
1493	$request = $smcFunc['db_query']('', '
1494		SELECT variable, value
1495		FROM {db_prefix}settings',
1496		array(
1497			'db_error_skip' => true,
1498		)
1499	);
1500	// Only proceed if we can load the data.
1501	if ($request)
1502	{
1503		while ($row = $smcFunc['db_fetch_row']($request))
1504			$modSettings[$row[0]] = $row[1];
1505		$smcFunc['db_free_result']($request);
1506	}
1507
1508	updateStats('member');
1509	updateStats('message');
1510	updateStats('topic');
1511
1512	// This function is needed to do the updateStats('subject') call.
1513	$smcFunc['strtolower'] = $db_character_set === 'utf8' || $txt['lang_character_set'] === 'UTF-8' ? create_func…

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