// Let's pull in useful classes
if (!defined('SMF'))
define('SMF', 1);
require_once('Sources/Class-Package.php');
if (version_compare(PHP_VERSION, '8.0.0', '>='))
require_once('Sources/Subs-Compat.php');
// Database info.
$databases = array(
'mysql' => array(
'name' => 'MySQL',
'version' => '5.6.0',
'version_check' => function() {
global $db_connection;
if (!function_exists('mysqli_fetch_row'))
return false;
return mysqli_fetch_row(mysqli_query($db_connection, 'SELECT VERSION();'))[0];
},
'supported' => function_exists('mysqli_connect'),
'default_user' => 'mysql.default_user',
'default_password' => 'mysql.default_password',
'default_host' => 'mysql.default_host',
'default_port' => 'mysql.default_port',
'utf8_support' => function()
{
return true;
},
'utf8_version' => '5.0.22',
'utf8_version_check' => function() {
global $db_connection;
return mysqli_get_server_info($db_connection);
},
'alter_support' => true,
'validate_prefix' => function(&$value)
{
$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
return true;
},
),
'postgresql' => array(
'name' => 'PostgreSQL',
'version' => '9.6',
'version_check' => function() {
global $db_connection;
$request = pg_query($db_connection, 'SELECT version()');
list ($version) = pg_fetch_row($request);
list($pgl, $version) = explode(' ', $version);
return $version;
},
'supported' => function_exists('pg_connect'),
'always_has_db' => true,
'utf8_support' => function()
{
global $db_connection;
$request = pg_query($db_connection, 'SHOW SERVER_ENCODING');
list ($charcode) = pg_fetch_row($request);
if ($charcode == 'UTF8')
return true;
else
return false;
},
'utf8_version' => '8.0',
'utf8_version_check' => function (){
global $db_connection;
$request = pg_query($db_connection, 'SELECT version()');
list ($version) = pg_fetch_row($request);
list($pgl, $version) = explode(' ', $version);
return $version;
},
'validate_prefix' => function(&$value)
{
global $txt;
$value = preg_replace('~[^A-Za-z0-9_\$]~', '', $value);
// Is it reserved?
if ($value == 'pg_')
return $txt['error_db_prefix_reserved'];
// Is the prefix numeric?
if (preg_match('~^\d~', $value))
return $txt['error_db_prefix_numeric'];
return true;
},
),
);
global $txt;
// Initialize everything and load the language files.
initialize_inputs();
load_lang_file();
// This is what we are.
$installurl = $_SERVER['PHP_SELF'];
// All the steps in detail.
// Number,Name,Function,Progress Weight.
$incontext['steps'] = array(
0 => array(1, $txt['install_step_welcome'], 'Welcome', 0),
1 => array(2, $txt['install_step_writable'], 'CheckFilesWritable', 10),
2 => array(3, $txt['install_step_databaseset'], 'DatabaseSettings', 15),
3 => array(4, $txt['install_step_forum'], 'ForumSettings', 40),
4 => array(5, $txt['install_step_databasechange'], 'DatabasePopulation', 15),
5 => array(6, $txt['install_step_admin'], 'AdminAccount', 20),
6 => array(7, $txt['install_step_delete'], 'DeleteInstall', 0),
);
// Default title...
$incontext['page_title'] = $txt['smf_installer'];
// What step are we on?
$incontext['current_step'] = isset($_GET['step']) ? (int) $_GET['step'] : 0;
// Loop through all the steps doing each one as required.
$incontext['overall_percent'] = 0;
foreach ($incontext['steps'] as $num => $step)
{
if ($num >= $incontext['current_step'])
{
// The current weight of this step in terms of overall progress.
$incontext['step_weight'] = $step[3];
// Make sure we reset the skip button.
$incontext['skip'] = false;
// Call the step and if it returns false that means pause!
if (function_exists($step[2]) && $step[2]() === false)
break;
elseif (function_exists($step[2]))
$incontext['current_step']++;
// No warnings pass on.
$incontext['warning'] = '';
}
$incontext['overall_percent'] += $step[3];
}
// Actually do the template stuff.
installExit();
function initialize_inputs()
{
global $databases;
// Just so people using older versions of PHP aren't left in the cold.
if (!isset($_SERVER['PHP_SELF']))
$_SERVER['PHP_SELF'] = isset($GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']) ? $GLOBALS['HTTP_SERVER_VARS']['PHP_SELF'] : 'install.php';
// In pre-release versions, report all errors.
if (strspn(SMF_VERSION, '1234567890.') !== strlen(SMF_VERSION))
error_reporting(E_ALL);
// Otherwise, report all errors except for deprecation notices.
else
error_reporting(E_ALL & ~E_DEPRECATED);
// Fun. Low PHP version...
if (!isset($_GET))
{
$GLOBALS['_GET']['step'] = 0;
return;
}
if (!isset($_GET['obgz']))
{
ob_start();
if (ini_get('session.save_handler') == 'user')
@ini_set('session.save_handler', 'files');
if (function_exists('session_start'))
@session_start();
}
else
{
ob_start('ob_gzhandler');
if (ini_get('session.save_handler') == 'user')
@ini_set('session.save_handler', 'files');
session_start();
if (!headers_sent())
echo '
', htmlspecialchars($_GET['pass_string']), '
', htmlspecialchars($_GET['pass_string']), '
';
exit;
}
// This is really quite simple; if ?delete is on the URL, delete the installer...
if (isset($_GET['delete']))
{
if (isset($_SESSION['installer_temp_ftp']))
{
$ftp = new ftp_connection($_SESSION['installer_temp_ftp']['server'], $_SESSION['installer_temp_ftp']['port'], $_SESSION['installer_temp_ftp']['username'], $_SESSION['installer_temp_ftp']['password']);
$ftp->chdir($_SESSION['installer_temp_ftp']['path']);
$ftp->unlink('install.php');
foreach ($databases as $key => $dummy)
{
$type = ($key == 'mysqli') ? 'mysql' : $key;
$ftp->unlink('install_' . DB_SCRIPT_VERSION . '_' . $type . '.sql');
}
$ftp->close();
unset($_SESSION['installer_temp_ftp']);
}
else
{
@unlink(__FILE__);
foreach ($databases as $key => $dummy)
{
$type = ($key == 'mysqli') ? 'mysql' : $key;
@unlink(dirname(__FILE__) . '/install_' . DB_SCRIPT_VERSION . '_' . $type . '.sql');
}
}
// Now just redirect to a blank.png...
$secure = false;
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on')
$secure = true;
elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on')
$secure = true;
header('location: http' . ($secure ? 's' : '') . '://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/Themes/default/images/blank.png');
exit;
}
// PHP 5 might cry if we don't do this now.
if (function_exists('date_default_timezone_set'))
{
// Get PHP's default timezone, if set
$ini_tz = ini_get('date.timezone');
if (!empty($ini_tz))
$timezone_id = $ini_tz;
else
$timezone_id = '';
// If date.timezone is unset, invalid, or just plain weird, make a best guess
if (!in_array($timezone_id, timezone_identifiers_list()))
{
$server_offset = @mktime(0, 0, 0, 1, 1, 1970) * -1;
$timezone_id = timezone_name_from_abbr('', $server_offset, 0);
if (empty($timezone_id))
$timezone_id = 'UTC';
}
date_default_timezone_set($timezone_id);
}
header('X-Frame-Options: SAMEORIGIN');
header('X-XSS-Protection: 1');
header('X-Content-Type-Options: nosniff');
// Force an integer step, defaulting to 0.
$_GET['step'] = (int) @$_GET['step'];
}
// Load the list of language files, and the current language file.
function load_lang_file()
{
global $incontext, $user_info, $txt;
$incontext['detected_languages'] = array();
// Make sure the languages directory actually exists.
if (file_exists(dirname(__FILE__) . '/Themes/default/languages'))
{
// Find all the "Install" language files in the directory.
$dir = dir(dirname(__FILE__) . '/Themes/default/languages');
while ($entry = $dir->read())
{
if (substr($entry, 0, 8) == 'Install.' && substr($entry, -4) == '.php')
$incontext['detected_languages'][$entry] = ucfirst(substr($entry, 8, strlen($entry) - 12));
}
$dir->close();
}
// Didn't find any, show an error message!
if (empty($incontext['detected_languages']))
{
// Let's not cache this message, eh?
header('expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('last-modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('cache-control: no-cache');
echo '
SMF Installer: Error!
A critical error has occurred.
This installer was unable to find the installer\'s language file or files. They should be found under:
', dirname($_SERVER['PHP_SELF']) != '/' ? dirname($_SERVER['PHP_SELF']) : '', '/Themes/default/languages
In some cases, FTP clients do not properly upload files with this many folders. Please double check to make sure you have uploaded all the files in the distribution.
If that doesn\'t help, please make sure this install.php file is in the same place as the Themes folder.
If you continue to get this error message, feel free to look to us for support.
';
die;
}
// Override the language file?
if (isset($_GET['lang_file']))
$_SESSION['installer_temp_lang'] = $_GET['lang_file'];
elseif (isset($GLOBALS['HTTP_GET_VARS']['lang_file']))
$_SESSION['installer_temp_lang'] = $GLOBALS['HTTP_GET_VARS']['lang_file'];
// Make sure it exists, if it doesn't reset it.
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']))
{
// Use the first one...
list ($_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
// If we have english and some other language, use the other language. We Americans hate english :P.
if ($_SESSION['installer_temp_lang'] == 'Install.english.php' && count($incontext['detected_languages']) > 1)
list (, $_SESSION['installer_temp_lang']) = array_keys($incontext['detected_languages']);
}
// And now include the actual language file itself.
require_once(dirname(__FILE__) . '/Themes/default/languages/' . $_SESSION['installer_temp_lang']);
// Which language did we load? Assume that he likes his language.
preg_match('~^Install\.(.+[^-utf8])\.php$~', $_SESSION['installer_temp_lang'], $matches);
$user_info['language'] = $matches[1];
}
// This handy function loads some settings and the like.
function load_database()
{
global $db_prefix, $db_connection, $sourcedir, $smcFunc, $modSettings, $db_port;
global $db_server, $db_passwd, $db_type, $db_name, $db_user, $db_persist, $db_mb4;
if (empty($sourcedir))
$sourcedir = dirname(__FILE__) . '/Sources';
// Need this to check whether we need the database password.
require(dirname(__FILE__) . '/Settings.php');
if (!defined('SMF'))
define('SMF', 1);
if (empty($smcFunc))
$smcFunc = array();
$modSettings['disableQueryCheck'] = true;
// Connect the database.
if (!$db_connection)
{
require_once($sourcedir . '/Subs-Db-' . $db_type . '.php');
$options = array('persist' => $db_persist);
if (!empty($db_port))
$options['port'] = $db_port;
if (!empty($db_mb4))
$options['db_mb4'] = $db_mb4;
if (!$db_connection)
$db_connection = smf_db_initiate($db_server, $db_name, $db_user, $db_passwd, $db_prefix, $options);
}
}
// This is called upon exiting the installer, for template etc.
function installExit($fallThrough = false)
{
global $incontext, $installurl, $txt;
// Send character set.
header('content-type: text/html; charset=' . (isset($txt['lang_character_set']) ? $txt['lang_character_set'] : 'UTF-8'));
// We usually dump our templates out.
if (!$fallThrough)
{
// The top install bit.
template_install_above();
// Call the template.
if (isset($incontext['sub_template']))
{
$incontext['form_url'] = $installurl . '?step=' . $incontext['current_step'];
call_user_func('template_' . $incontext['sub_template']);
}
// @todo REMOVE THIS!!
else
{
if (function_exists('doStep' . $_GET['step']))
call_user_func('doStep' . $_GET['step']);
}
// Show the footer.
template_install_below();
}
// Bang - gone!
die();
}
function Welcome()
{
global $incontext, $txt, $databases, $installurl;
$incontext['page_title'] = $txt['install_welcome'];
$incontext['sub_template'] = 'welcome_message';
// Done the submission?
if (isset($_POST['contbutt']))
return true;
// See if we think they have already installed it?
if (is_readable(dirname(__FILE__) . '/Settings.php'))
{
$probably_installed = 0;
foreach (file(dirname(__FILE__) . '/Settings.php') as $line)
{
if (preg_match('~^\$db_passwd\s=\s\'([^\']+)\';$~', $line))
$probably_installed++;
if (preg_match('~^\$boardurl\s=\s\'([^\']+)\';~', $line) && !preg_match('~^\$boardurl\s=\s\'http://127\.0\.0\.1/smf\';~', $line))
$probably_installed++;
}
if ($probably_installed == 2)
$incontext['warning'] = $txt['error_already_installed'];
}
// Is some database support even compiled in?
$incontext['supported_databases'] = array();
foreach ($databases as $key => $db)
{
if ($db['supported'])
{
$type = ($key == 'mysqli') ? 'mysql' : $key;
if (!file_exists(dirname(__FILE__) . '/install_' . DB_SCRIPT_VERSION . '_' . $type . '.sql'))
{
$databases[$key]['supported'] = false;
$notFoundSQLFile = true;
$txt['error_db_script_missing'] = sprintf($txt['error_db_script_missing'], 'install_' . DB_SCRIPT_VERSION . '_' . $type . '.sql');
}
else
$incontext['supported_databases'][] = $db;
}
}
// Check the PHP version.
if ((!function_exists('version_compare') || version_compare($GLOBALS['required_php_version'], PHP_VERSION, '>=')))
$error = 'error_php_too_low';
// Make sure we have a supported database
elseif (empty($incontext['supported_databases']))
$error = empty($notFoundSQLFile) ? 'error_db_missing' : 'error_db_script_missing';
// How about session support? Some crazy sysadmin remove it?
elseif (!function_exists('session_start'))
$error = 'error_session_missing';
// Make sure they uploaded all the files.
elseif (!file_exists(dirname(__FILE__) . '/index.php'))
$error = 'error_missing_files';
// Very simple check on the session.save_path for Windows.
// @todo Move this down later if they don't use database-driven sessions?
elseif (@ini_get('session.save_path') == '/tmp' && substr(__FILE__, 1, 2) == ':\\')
$error = 'error_session_save_path';
// Since each of the three messages would look the same, anyway...
if (isset($error))
$incontext['error'] = $txt[$error];
// Mod_security blocks everything that smells funny. Let SMF handle security.
if (!fixModSecurity() && !isset($_GET['overmodsecurity']))
$incontext['error'] = $txt['error_mod_security'] . '