use wcf\data\user\User;
use wcf\data\user\UserAction;
use wcf\system\cache\builder\LanguageCacheBuilder;
+use wcf\system\database\exception\DatabaseException;
use wcf\system\database\util\SQLParser;
+use wcf\system\database\MySQLDatabase;
use wcf\system\exception\SystemException;
use wcf\system\exception\UserInputException;
use wcf\system\io\File;
use wcf\system\template\SetupTemplateEngine;
use wcf\util\DirectoryUtil;
use wcf\util\FileUtil;
+use wcf\util\HeaderUtil;
use wcf\util\StringUtil;
use wcf\util\UserUtil;
use wcf\util\XML;
// define
-define('PACKAGE_ID', '0');
-define('HTTP_ENABLE_NO_CACHE_HEADERS', 0);
+define('PACKAGE_ID', 0);
define('HTTP_ENABLE_GZIP', 0);
define('HTTP_GZIP_LEVEL', 0);
define('HTTP_SEND_X_FRAME_OPTIONS', 0);
* Executes the installation of the basic WCF systems.
*
* @author Marcel Werk
- * @copyright 2001-2015 WoltLab GmbH
+ * @copyright 2001-2016 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package com.woltlab.wcf
- * @subpackage system
- * @category Community Framework
+ * @package WoltLabSuite\Core\System
*/
class WCFSetup extends WCF {
/**
*/
protected static $installedFiles = [];
- /**
- * name of installed primary application
- * @var string
- */
- protected static $setupPackageName = 'WoltLab Community Framework';
-
/**
* indicates if developer mode is used to install
* @var boolean
*/
protected static $developerMode = 0;
- /**
- * supported databases
- * @var string[][]
- */
- protected static $dbClasses = [
- 'MySQLDatabase' => ['class' => 'wcf\system\database\MySQLDatabase', 'minversion' => '5.1.17']//, // MySQL 5.1.17+
- //'PostgreSQLDatabase' => ['class' => 'wcf\system\database\PostgreSQLDatabase', 'minversion' => '8.2.0'] // PostgreSQL 8.2.0+
- ];
-
+ /** @noinspection PhpMissingParentConstructorInspection */
/**
* Calls all init functions of the WCFSetup class and starts the setup process.
*/
public function __construct() {
@set_time_limit(0);
- $this->getDeveloperMode();
- $this->getLanguageSelection();
- $this->getInstallationDirectories();
+ static::getDeveloperMode();
+ static::getLanguageSelection();
+ static::getInstallationDirectories();
$this->initLanguage();
$this->initTPL();
+ /** @noinspection PhpUndefinedMethodInspection */
self::getLanguage()->loadLanguage();
- $this->getPackageName();
+ static::getPackageNames();
// start setup
$this->setup();
}
/**
- * Gets the status of the developer mode.
+ * Sets the status of the developer mode.
*/
protected static function getDeveloperMode() {
if (isset($_GET['dev'])) self::$developerMode = intval($_GET['dev']);
}
/**
- * Gets the selected language.
+ * Sets the selected language.
*/
protected static function getLanguageSelection() {
self::$availableLanguages = self::getAvailableLanguages();
}
/**
- * Gets the available database classes.
+ * Sets the selected wcf dir from request.
*
- * @return string[]
- */
- protected static function getAvailableDBClasses() {
- $availableDBClasses = [];
- foreach (self::$dbClasses as $class => $data) {
- if (call_user_func([$data['class'], 'isSupported'])) {
- $availableDBClasses[$class] = $data;
- }
- }
-
- return $availableDBClasses;
- }
-
- /**
- * Gets the selected wcf dir from request.
- *
- * @since 2.2
+ * @since 3.0
*/
protected static function getInstallationDirectories() {
- if (self::$developerMode && isset($_ENV['WCFSETUP_USEDEFAULTWCFDIR'])) {
- if (!isset($_REQUEST['directories']) || !is_array($_REQUEST['directories'])) $_REQUEST['directories'] = [];
- $_REQUEST['directories']['wcf'] = FileUtil::unifyDirSeparator(INSTALL_SCRIPT_DIR).'wcf/';
- }
-
if (!empty($_REQUEST['directories']) && is_array($_REQUEST['directories'])) {
foreach ($_REQUEST['directories'] as $application => $directory) {
self::$directories[$application] = $directory;
break;
}
- /** @noinspection PhpMissingBreakStatementInspection */
case 'configureDirectories':
- if (!self::$developerMode || !isset($_ENV['WCFSETUP_USEDEFAULTWCFDIR'])) {
- $this->calcProgress(3);
- $this->configureDirectories();
- break;
- }
+ $this->calcProgress(3);
+ $this->configureDirectories();
+ break;
case 'unzipFiles':
$this->calcProgress(4);
$system['phpVersion']['result'] = (version_compare($comparePhpVersion, '5.5.4') >= 0);
// sql
- $system['sql']['value'] = array_keys(self::getAvailableDBClasses());
- $system['sql']['result'] = !empty($system['sql']['value']);
+ $system['sql']['result'] = MySQLDatabase::isSupported();
// upload_max_filesize
- $system['uploadMaxFilesize']['value'] = ini_get('upload_max_filesize');
+ $system['uploadMaxFilesize']['value'] = min(ini_get('upload_max_filesize'), ini_get('post_max_size'));
$system['uploadMaxFilesize']['result'] = (intval($system['uploadMaxFilesize']['value']) > 0);
// gdlib version
$system['memoryLimit']['value'] = ini_get('memory_limit');
$system['memoryLimit']['result'] = $this->compareMemoryLimit();
+ // openssl extension
+ $system['openssl']['result'] = @extension_loaded('openssl');
+
WCF::getTPL()->assign([
'system' => $system,
'nextStep' => 'configureDirectories'
/**
* Searches the wcf dir.
*
- * @since 2.2
+ * @since 3.0
*/
protected function configureDirectories() {
// get available packages
- $applications = $packages = [];
+ $packages = [];
foreach (glob(TMP_DIR . 'install/packages/*') as $file) {
$filename = basename($file);
if (preg_match('~\.(?:tar|tar\.gz|tgz)$~', $filename)) {
$application = Package::getAbbreviation($package->getPackageInfo('name'));
- $applications[] = $application;
$packages[$application] = [
- 'directory' => ($package->getPackageInfo('applicationDirectory') ?: $application),
+ 'directory' => $package->getPackageInfo('applicationDirectory') ?: $application,
'packageDescription' => $package->getLocalizedPackageInfo('packageDescription'),
'packageName' => $package->getLocalizedPackageInfo('packageName')
];
-
}
}
if ($application !== 'wcf') $showOrder[] = $application;
}
- $documentRoot = FileUtil::unifyDirSeparator($_SERVER['DOCUMENT_ROOT']);
+ $documentRoot = FileUtil::unifyDirSeparator(realpath($_SERVER['DOCUMENT_ROOT']));
+ if (self::$developerMode && isset($_ENV['WCFSETUP_USEDEFAULTWCFDIR'])) {
+ // resolve path relative to document root
+ $relativePath = FileUtil::getRelativePath($documentRoot, INSTALL_SCRIPT_DIR);
+ foreach ($packages as $application => $packageData) {
+ self::$directories[$application] = $relativePath . ($application === 'wcf' ? '' : $packageData['directory'] . '/');
+ }
+ }
+
$errors = [];
if (!empty(self::$directories)) {
$applicationPaths = $knownPaths = [];
- // use $showOrder instead of $applications to ensure that the error message for
- // duplicate directories will trigger in display order rather than the random
- // sort order returned by glob() above
+ // use $showOrder to ensure that the error message for duplicate directories
+ // will trigger in display order rather than the random sort order returned
+ // by glob() above
foreach ($showOrder as $application) {
$path = FileUtil::getRealPath($documentRoot . '/' . FileUtil::addTrailingSlash(FileUtil::removeLeadingSlash(self::$directories[$application])));
if (strpos($path, $documentRoot) !== 0) {
}
else {
// resolve path relative to document root
- $relativePath = str_replace(FileUtil::unifyDirSeparator($_SERVER['DOCUMENT_ROOT']), '', FileUtil::unifyDirSeparator(INSTALL_SCRIPT_DIR));
+ $relativePath = FileUtil::getRelativePath($documentRoot, INSTALL_SCRIPT_DIR);
foreach ($packages as $application => $packageData) {
- self::$directories[$application] = $relativePath . ($application === 'wcf' ? '' : $packageData['directory'] . '/');
+ $dir = $relativePath . ($application === 'wcf' ? '' : $packageData['directory'] . '/');
+ if (mb_strpos($dir, './') === 0) $dir = mb_substr($dir, 1);
+
+ self::$directories[$application] = $dir;
}
}
}
// WCF not yet installed, install files first
else {
- $this->installFiles();
+ static::installFiles();
$this->gotoNextStep('selectLanguages');
}
}
/**
- * Shows the page for configurating the database connection.
+ * Shows the page for configuring the database connection.
*/
protected function configureDB() {
- $availableDBClasses = self::getAvailableDBClasses();
- $dbClass = '';
if (self::$developerMode && isset($_ENV['WCFSETUP_DBHOST'])) {
$dbHost = $_ENV['WCFSETUP_DBHOST'];
$dbUser = $_ENV['WCFSETUP_DBUSER'];
$dbNumber = 1;
}
- // set $dbClass to first item in $availableDBClasses
- foreach ($availableDBClasses as $dbClass) {
- $dbClass = $dbClass['class'];
- break;
- }
-
if (isset($_POST['send']) || (self::$developerMode && isset($_ENV['WCFSETUP_DBHOST']))) {
if (isset($_POST['dbHost'])) $dbHost = $_POST['dbHost'];
if (isset($_POST['dbUser'])) $dbUser = $_POST['dbUser'];
// ensure that $dbNumber is zero or a positive integer
if (isset($_POST['dbNumber'])) $dbNumber = max(0, intval($_POST['dbNumber']));
- if (isset($_POST['dbClass'])) $dbClass = $_POST['dbClass'];
// get port
$dbPort = 0;
// test connection
try {
- // check db class
- $validDB = false;
- foreach ($availableDBClasses as $dbData) {
- if ($dbData['class'] == $dbClass) {
- $validDB = true;
- break;
- }
- }
-
- if (!$validDB) {
- throw new SystemException("Database type '".$dbClass."'. is not available on this system.");
- }
-
// check connection data
/** @var \wcf\system\database\Database $db */
- $db = new $dbClass($dbHost, $dbUser, $dbPassword, $dbName, $dbPort, true);
- $db->connect();
+ try {
+ $db = new MySQLDatabase($dbHost, $dbUser, $dbPassword, $dbName, $dbPort, true);
+ }
+ catch (DatabaseException $e) {
+ if ($e->getPrevious()->getCode() == 1115) { // work-around for older MySQL versions that don't know utf8mb4
+ throw new SystemException("Insufficient MySQL version. Version '5.5.35' or greater is needed.");
+ }
+
+ throw $e;
+ }
// check sql version
- if (!empty($availableDBClasses[$dbClass]['minversion'])) {
- $compareSQLVersion = preg_replace('/^(\d+\.\d+\.\d+).*$/', '\\1', $db->getVersion());
- if (!(version_compare($compareSQLVersion, $availableDBClasses[$dbClass]['minversion']) >= 0)) {
- throw new SystemException("Insufficient SQL version '".$compareSQLVersion."'. Version '".$availableDBClasses[$dbClass]['minversion']."' or greater is needed.");
+ $sqlVersion = $db->getVersion();
+ $compareSQLVersion = preg_replace('/^(\d+\.\d+\.\d+).*$/', '\\1', $sqlVersion);
+ if (stripos($sqlVersion, 'MariaDB')) {
+ // MariaDB 10.0.22+
+ if (!(version_compare($compareSQLVersion, '10.0.22') >= 0)) {
+ throw new SystemException("Insufficient MariaDB version '".$compareSQLVersion."'. Version '10.0.22' or greater is needed.");
}
}
- // check innodb support
- if ($dbClass == 'wcf\system\database\MySQLDatabase') {
- $sql = "SHOW ENGINES";
- $statement = $db->prepareStatement($sql);
- $statement->execute();
- $hasInnoDB = false;
- while ($row = $statement->fetchArray()) {
- if ($row['Engine'] == 'InnoDB' && in_array($row['Support'], ['DEFAULT', 'YES'])) {
- $hasInnoDB = true;
- break;
- }
+ else {
+ // MySQL 5.5.35+
+ if (!(version_compare($compareSQLVersion, '5.5.35') >= 0)) {
+ throw new SystemException("Insufficient MySQL version '".$compareSQLVersion."'. Version '5.5.35' or greater is needed.");
}
-
- if (!$hasInnoDB) {
- throw new SystemException("Support for InnoDB is missing.");
+ }
+
+ // check innodb support
+ $sql = "SHOW ENGINES";
+ $statement = $db->prepareStatement($sql);
+ $statement->execute();
+ $hasInnoDB = false;
+ while ($row = $statement->fetchArray()) {
+ if ($row['Engine'] == 'InnoDB' && in_array($row['Support'], ['DEFAULT', 'YES'])) {
+ $hasInnoDB = true;
+ break;
}
}
+ if (!$hasInnoDB) {
+ throw new SystemException("Support for InnoDB is missing.");
+ }
+
// check for table conflicts
$conflictedTables = $this->getConflictedTables($db, $dbNumber);
$file->write("\$dbUser = '".str_replace("'", "\\'", $dbUser)."';\n");
$file->write("\$dbPassword = '".str_replace("'", "\\'", $dbPassword)."';\n");
$file->write("\$dbName = '".str_replace("'", "\\'", $dbName)."';\n");
- $file->write("\$dbClass = '".str_replace("'", "\\'", $dbClass)."';\n");
$file->write("if (!defined('WCF_N')) define('WCF_N', $dbNumber);\n");
$file->close();
'dbPassword' => $dbPassword,
'dbName' => $dbName,
'dbNumber' => $dbNumber,
- 'dbClass' => $dbClass,
- 'availableDBClasses' => $availableDBClasses,
'nextStep' => 'configureDB'
]);
WCF::getTPL()->display('stepConfigureDB');
// split by offsets
$sqlData = explode('/* SQL_PARSER_OFFSET */', $sql);
- $offset = (isset($_POST['offset'])) ? intval($_POST['offset']) : 0;
+ $offset = isset($_POST['offset']) ? intval($_POST['offset']) : 0;
if (!isset($sqlData[$offset])) {
throw new SystemException("Offset for SQL parser is out of bounds, ".$offset." was requested, but there are only ".count($sqlData)." sections");
}
}
else {
// regular file
- $fileInserts[] = str_replace(WCF_DIR, '', $file);
+ $fileInserts[] = preg_replace('/^'.preg_quote(WCF_DIR, '/').'/', '', $file);
}
}
}
else {
$username = $password = $confirmPassword = 'root';
- $email = $confirmEmail = 'woltlab@woltlab.com';
+ $email = $confirmEmail = 'wsc-developer-mode@example.com';
}
// error handling
throw new UserInputException('username');
}
if (!UserUtil::isValidUsername($username)) {
- throw new UserInputException('username', 'notValid');
+ throw new UserInputException('username', 'invalid');
}
// e-mail address
throw new UserInputException('email');
}
if (!UserUtil::isValidEmail($email)) {
- throw new UserInputException('email', 'notValid');
+ throw new UserInputException('email', 'invalid');
}
// confirm e-mail address
}
$tar->close();
+ // delete install files
+ $installPhpDeleted = @unlink('./install.php');
+ @unlink('./test.php');
+ $wcfSetupTarDeleted = @unlink('./WCFSetup.tar.gz');
+
+ // render page
+ WCF::getTPL()->assign([
+ 'installPhpDeleted' => $installPhpDeleted,
+ 'wcfSetupTarDeleted' => $wcfSetupTarDeleted
+ ]);
+ $output = WCF::getTPL()->fetch('stepInstallPackages');
+
// register packages in queue
// get new process id
$sql = "SELECT MAX(processNo) AS processNo
'processNo' => $processNo,
'userID' => $admin->userID,
'package' => 'com.woltlab.wcf',
- 'packageName' => 'WoltLab Community Framework',
+ 'packageName' => 'WoltLab Suite Core',
'archive' => TMP_DIR.'install/packages/'.$wcfPackageFile,
'isApplication' => 1
]);
FROM wcf".WCF_N."_package_installation_queue";
$statement = WCF::getDB()->prepareStatement($sql);
$statement->execute();
- $queues = [];
- while ($row = $statement->fetchArray()) {
- $queues[$row['queueID']] = $row['parentQueueID'];
- }
+ $queues = $statement->fetchMap('queueID', 'parentQueueID');
$queueIDs = [];
+ /** @noinspection PhpUndefinedVariableInspection */
$queueID = $queue->queueID;
while ($queueID) {
$queueIDs[] = $queueID;
- $queueID = (isset($queues[$queueID])) ? $queues[$queueID] : 0;
+ $queueID = isset($queues[$queueID]) ? $queues[$queueID] : 0;
}
// remove previously created queues
throw new SystemException('', 0, '', $e);
}
+ /** @noinspection PhpUndefinedVariableInspection */
$queue = PackageInstallationQueueEditor::create([
'parentQueueID' => $queue->queueID,
'processNo' => $processNo,
}
// login as admin
- define('COOKIE_PREFIX', 'wcf22_');
+ define('COOKIE_PREFIX', 'wsc30_');
$factory = new ACPSessionFactory();
$factory->load();
SessionHandler::getInstance()->register('masterPassword', 1);
SessionHandler::getInstance()->register('__wcfSetup_developerMode', self::$developerMode);
SessionHandler::getInstance()->register('__wcfSetup_directories', self::$directories);
+ SessionHandler::getInstance()->unregister('__changeSessionID');
SessionHandler::getInstance()->update();
- $installPhpDeleted = @unlink('./install.php');
- @unlink('./test.php');
- $wcfSetupTarDeleted = @unlink('./WCFSetup.tar.gz');
-
// print page
- WCF::getTPL()->assign([
- 'installPhpDeleted' => $installPhpDeleted,
- 'wcfSetupTarDeleted' => $wcfSetupTarDeleted
- ]);
- WCF::getTPL()->display('stepInstallPackages');
+ HeaderUtil::sendHeaders();
+ echo $output;
// delete tmp files
$directory = TMP_DIR.'/';
}
/**
- * Gets the package name of the first application in WCFSetup.tar.gz.
+ * Reads the package names of the bundled applications in WCFSetup.tar.gz.
*/
- protected static function getPackageName() {
+ protected static function getPackageNames() {
// get package name
+ $packageNames = [];
$tar = new Tar(SETUP_FILE);
foreach ($tar->getContentList() as $file) {
if ($file['type'] != 'folder' && mb_strpos($file['filename'], 'install/packages/') === 0) {
$packageFile = basename($file['filename']);
- $packageName = preg_replace('!\.(tar\.gz|tgz|tar)$!', '', $packageFile);
- if ($packageName != 'com.woltlab.wcf') {
- try {
- $archive = new PackageArchive(TMP_DIR.'install/packages/'.$packageFile);
- $archive->openArchive();
- self::$setupPackageName = $archive->getLocalizedPackageInfo('packageName');
- $archive->getTar()->close();
- break;
- }
- catch (SystemException $e) {}
+ try {
+ $archive = new PackageArchive(TMP_DIR.'install/packages/'.$packageFile);
+ $archive->openArchive();
+ $packageNames[] = $archive->getLocalizedPackageInfo('packageName');
+ $archive->getTar()->close();
}
+ catch (SystemException $e) {}
}
}
$tar->close();
+ sort($packageNames);
+
// assign package name
- WCF::getTPL()->assign(['setupPackageName' => self::$setupPackageName]);
+ WCF::getTPL()->assign(['setupPackageNames' => $packageNames]);
}
}