rhymix/modules/install/install.controller.php

643 lines
17 KiB
PHP

<?php
/* Copyright (C) NAVER <http://www.navercorp.com> */
/**
* @class installController
* @author NAVER (developers@xpressengine.com)
* @brief install module of the Controller class
*/
class installController extends install
{
var $flagLicenseAgreement = './files/env/license_agreement';
/**
* @brief Initialization
*/
function init()
{
// Stop if already installed.
if (Context::isInstalled())
{
throw new Rhymix\Framework\Exception('msg_already_installed');
}
// Increase time limit.
@set_time_limit(0);
}
/**
* @brief division install step... DB Config temp file create
*/
function procDBConfig()
{
// Get DB config variables.
$config = Context::gets('db_type', 'db_host', 'db_port', 'db_user', 'db_pass', 'db_database', 'db_prefix');
// Disallow installation using the root account.
if (trim($config->db_user) === 'root' && !preg_match('/Development Server$/', $_SERVER['SERVER_SOFTWARE']))
{
return new BaseObject(-1, 'msg_dbroot_disallowed');
}
// Create a temporary setting object.
Rhymix\Framework\Config::set('db.master', array(
'type' => $config->db_type,
'host' => $config->db_host,
'port' => $config->db_port,
'user' => $config->db_user,
'pass' => $config->db_pass,
'database' => $config->db_database,
'prefix' => $config->db_prefix ? (rtrim($config->db_prefix, '_') . '_') : '',
));
// Check connection to the DB.
$oDB = DB::getInstance();
$output = $oDB->getError();
if (!$output->toBool() || !$oDB->getHandle())
{
return $output;
}
// Check MySQL server capabilities.
if(stripos($config->db_type, 'mysql') !== false)
{
// Check if InnoDB is supported.
$show_engines = $oDB->query('SHOW ENGINES')->fetchAll();
foreach($show_engines as $engine_info)
{
if ($engine_info->Engine === 'InnoDB' && $engine_info->Support !== 'NO')
{
$config->db_type .= '_innodb';
break;
}
}
// Check if utf8mb4 is supported.
$oDB->charset = $oDB->getBestSupportedCharset();
$config->db_charset = $oDB->charset;
}
// Check if tables already exist.
$table_check = array('documents', 'comments', 'modules', 'sites');
foreach ($table_check as $table_name)
{
if ($oDB->isTableExists($table_name))
{
throw new Rhymix\Framework\Exception('msg_table_already_exists');
}
}
// Save DB config in session.
$_SESSION['db_config'] = $config;
// Continue the installation.
if(!in_array(Context::getRequestMethod(), array('XMLRPC','JSON')))
{
$returnUrl = Context::get('success_return_url') ? Context::get('success_return_url') : getNotEncodedUrl('', 'act', 'dispInstallOtherConfig');
$this->setRedirectUrl($returnUrl);
}
}
/**
* @brief Install with received information
*/
function procInstall($install_config = null)
{
// Check if it is already installed
if (Context::isInstalled())
{
throw new Rhymix\Framework\Exception('msg_already_installed');
}
// Get install parameters.
$config = Rhymix\Framework\Config::getDefaults();
if ($install_config)
{
$install_config = (array)$install_config;
$config['db']['master']['type'] = 'mysql';
$config['db']['master']['host'] = $install_config['db_hostname'];
$config['db']['master']['port'] = $install_config['db_port'];
$config['db']['master']['user'] = $install_config['db_userid'];
$config['db']['master']['pass'] = $install_config['db_password'];
$config['db']['master']['database'] = $install_config['db_database'];
$config['db']['master']['prefix'] = $install_config['db_table_prefix'];
$config['db']['master']['charset'] = $install_config['db_charset'];
$config['db']['master']['engine'] = strpos($install_config['db_type'], 'innodb') !== false ? 'innodb' : 'myisam';
$config['use_rewrite'] = $install_config['use_rewrite'] === 'Y' ? true : false;
$config['url']['ssl'] = $install_config['use_ssl'] ?: 'none';
$time_zone = $install_config['time_zone'];
$user_info = new stdClass;
$user_info->email_address = $install_config['email_address'];
$user_info->password = $install_config['password'];
$user_info->nick_name = $install_config['nick_name'];
$user_info->user_id = $install_config['user_id'];
}
else
{
$config['db']['master']['type'] = 'mysql';
$config['db']['master']['host'] = $_SESSION['db_config']->db_host;
$config['db']['master']['port'] = $_SESSION['db_config']->db_port;
$config['db']['master']['user'] = $_SESSION['db_config']->db_user;
$config['db']['master']['pass'] = $_SESSION['db_config']->db_pass;
$config['db']['master']['database'] = $_SESSION['db_config']->db_database;
$config['db']['master']['prefix'] = $_SESSION['db_config']->db_prefix;
$config['db']['master']['charset'] = $_SESSION['db_config']->db_charset;
$config['db']['master']['engine'] = strpos($_SESSION['db_config']->db_type, 'innodb') !== false ? 'innodb' : 'myisam';
$config['use_rewrite'] = $_SESSION['use_rewrite'] === 'Y' ? true : false;
$config['url']['ssl'] = Context::get('use_ssl') ?: 'none';
$time_zone = Context::get('time_zone');
$user_info = Context::gets('email_address', 'password', 'nick_name', 'user_id');
}
// Fix the database table prefix.
$config['db']['master']['prefix'] = rtrim($config['db']['master']['prefix'], '_');
if ($config['db']['master']['prefix'] !== '')
{
$config['db']['master']['prefix'] .= '_';
}
// Create new crypto keys.
$config['crypto']['encryption_key'] = Rhymix\Framework\Security::getRandom(64, 'alnum');
$config['crypto']['authentication_key'] = Rhymix\Framework\Security::getRandom(64, 'alnum');
$config['crypto']['session_key'] = Rhymix\Framework\Security::getRandom(64, 'alnum');
// Set the default language.
$config['locale']['default_lang'] = Context::getLangType();
$config['locale']['enabled_lang'] = array($config['locale']['default_lang']);
// Set the default time zone.
if (strpos($time_zone, '/') !== false)
{
$config['locale']['default_timezone'] = $time_zone;
$user_timezone = null;
}
else
{
$user_timezone = intval(Rhymix\Framework\DateTime::getTimezoneOffsetByLegacyFormat($time_zone ?: '+0900') / 3600);
switch ($user_timezone)
{
case 9:
$config['locale']['default_timezone'] = 'Asia/Seoul'; break;
case 0:
$config['locale']['default_timezone'] = 'Etc/UTC'; break;
default:
$config['locale']['default_timezone'] = 'Etc/GMT' . ($user_timezone > 0 ? '-' : '+') . abs($user_timezone);
}
}
// Set the internal time zone.
if ($config['locale']['default_timezone'] === 'Asia/Seoul')
{
$config['locale']['internal_timezone'] = 32400;
}
elseif ($user_timezone !== null)
{
$config['locale']['internal_timezone'] = $user_timezone * 3600;
}
else
{
$config['locale']['internal_timezone'] = 0;
}
// Set the default URL.
$config['url']['default'] = Context::getRequestUri();
// Set the default umask.
$config['file']['umask'] = Rhymix\Framework\Storage::recommendUmask();
// Load the new configuration.
Rhymix\Framework\Config::setAll($config);
Context::loadDBInfo($config);
// Check DB.
$oDB = DB::getInstance('master');
if (!$oDB->getHandle())
{
return $oDB->getError();
}
// Assign a temporary administrator while installing.
foreach ($user_info as $key => $val)
{
Context::set($key, $val, true);
}
$user_info->is_admin = 'Y';
Context::set('logged_info', $user_info);
// Install all the modules.
try
{
$oDB->begin();
$this->installDownloadedModule();
$oDB->commit();
}
catch(Exception $e)
{
$oDB->rollback();
throw new Rhymix\Framework\Exception($e->getMessage());
}
// Execute the install script.
$scripts = FileHandler::readDir(RX_BASEDIR . 'modules/install/script', '/(\.php)$/');
if(count($scripts))
{
sort($scripts);
foreach($scripts as $script)
{
$script_path = FileHandler::getRealPath('./modules/install/script/');
$output = include($script_path . $script);
}
}
// Apply site lock.
if (Context::get('use_sitelock') === 'Y')
{
$user_ip_range = getView('install')->detectUserIPRange();
Rhymix\Framework\Config::set('lock.locked', true);
Rhymix\Framework\Config::set('lock.message', 'This site is locked.');
Rhymix\Framework\Config::set('lock.allow', array('127.0.0.1', $user_ip_range));
}
// Use APC cache if available.
if (function_exists('apcu_exists'))
{
Rhymix\Framework\Config::set('cache.type', 'apc');
}
// Save the new configuration.
Rhymix\Framework\Config::save();
// Unset temporary session variables.
unset($_SESSION['use_rewrite']);
unset($_SESSION['db_config']);
// Redirect to the home page.
$this->setMessage('msg_install_completed');
$returnUrl = Context::get('success_return_url') ? Context::get('success_return_url') : RX_BASEURL;
$this->setRedirectUrl($returnUrl);
return new BaseObject();
}
/**
* @brief Result returned after checking the installation environment
*/
function checkInstallEnv()
{
// Check each item
$checklist = array();
// Check PHP version
if(version_compare(PHP_VERSION, __XE_MIN_PHP_VERSION__, '>='))
{
$checklist['php_version'] = true;
}
else
{
$checklist['php_version'] = false;
}
// Check DB
if(extension_loaded('pdo_mysql'))
{
$checklist['db_support'] = true;
}
else
{
$checklist['db_support'] = false;
}
// Check permission
if(is_writable(RX_BASEDIR) || is_writable(RX_BASEDIR . 'files'))
{
$checklist['permission'] = true;
}
else
{
$checklist['permission'] = false;
}
// Check session availability
$license_agreement_time = intval(trim(FileHandler::readFile($this->flagLicenseAgreement)));
if(isset($_SESSION['license_agreement']) && (!$license_agreement_time || ($license_agreement_time == $_SESSION['license_agreement'])))
{
$sess_autostart = intval(ini_get('session.auto_start'));
if($sess_autostart === 0)
{
$checklist['session'] = true;
}
else
{
$checklist['session'] = false;
}
}
else
{
$checklist['session'] = false;
}
// Check curl
if(function_exists('curl_init') && function_exists('curl_exec'))
{
$checklist['curl'] = true;
}
else
{
$checklist['curl'] = false;
}
// Check GD
if(function_exists('imagecreatefromjpeg') && function_exists('imagecreatefrompng'))
{
$checklist['gd'] = true;
}
else
{
$checklist['gd'] = false;
}
// Check iconv or mbstring
if(function_exists('iconv') || function_exists('mb_convert_encoding'))
{
$checklist['iconv'] = true;
}
else
{
$checklist['iconv'] = false;
}
// Check json
if(function_exists('json_encode') && function_exists('json_decode'))
{
$checklist['json'] = true;
}
else
{
$checklist['json'] = false;
}
// Check mcrypt or openssl
if(function_exists('mcrypt_encrypt') || function_exists('openssl_encrypt'))
{
$checklist['mcrypt'] = true;
}
else
{
$checklist['mcrypt'] = false;
}
// Check xml & simplexml
if(function_exists('xml_parser_create') && function_exists('simplexml_load_string'))
{
$checklist['xml'] = true;
}
else
{
$checklist['xml'] = false;
}
// Enable install if all conditions are met
$install_enable = true;
foreach($checklist as $k => $v)
{
if (!$v)
{
$install_enable = false;
break;
}
}
// Save the checked result to the Context
Context::set('checklist', $checklist);
Context::set('install_enable', $install_enable);
Context::set('phpversion', PHP_VERSION);
return $install_enable;
}
/**
* @brief License agreement
*/
function procInstallLicenseAgreement()
{
$vars = Context::getRequestVars();
if($vars->license_agreement !== 'Y')
{
throw new Rhymix\Framework\Exception('msg_must_accept_license_agreement');
}
$license_agreement_time = time();
$_SESSION['license_agreement'] = $license_agreement_time;
FileHandler::writeFile($this->flagLicenseAgreement, $license_agreement_time . PHP_EOL);
$this->setRedirectUrl(getNotEncodedUrl('', 'act', 'dispInstallCheckEnv'));
}
/**
* @brief Create files and subdirectories
* Local evironment setting before installation by using DB information
*/
function makeDefaultDirectory()
{
$directory_list = array(
'./files/config',
'./files/cache/queries',
'./files/cache/js_filter_compiled',
'./files/cache/template_compiled',
);
foreach($directory_list as $dir)
{
FileHandler::makeDir($dir);
}
}
/**
* @brief Install all the modules
*
* Create a table by using schema xml file in the shcema directory of each module
*/
function installDownloadedModule()
{
// Create a table ny finding schemas/*.xml file in each module
$module_list = FileHandler::readDir('./modules/', NULL, false, true);
$modules = array();
foreach($module_list as $module_path)
{
// Get module name
$module = basename($module_path);
// Only install default modules at this time
if (!Context::isDefaultPlugin($module, 'module'))
{
continue;
}
// Try to group modules by category
$xml_info = ModuleModel::getModuleInfoXml($module);
if (!$xml_info)
{
continue;
}
$modules[$xml_info->category ?: 'other'][] = $module;
}
// Install "module" module in advance
$this->installModule('module','./modules/module');
$this->updateModule('module');
// Determine the order of module installation depending on category
$install_step = array('system','content','member');
$update_order = [];
// Install all the remaining modules
foreach($install_step as $category)
{
if(is_array($modules[$category]) && count($modules[$category]))
{
foreach($modules[$category] as $module)
{
if($module == 'module') continue;
$this->installModule($module, sprintf('./modules/%s', $module));
$update_order[] = $module;
}
unset($modules[$category]);
}
}
// Install all the remaining modules
if(count($modules))
{
foreach($modules as $category => $module_list)
{
if(is_array($module_list) && count($module_list))
{
foreach($module_list as $module)
{
if($module == 'module') continue;
$this->installModule($module, sprintf('./modules/%s', $module));
$update_order[] = $module;
}
}
}
}
// Update all modules
foreach ($update_order as $module)
{
$this->updateModule($module);
}
return new BaseObject();
}
/**
* @brief Install an each module
*/
function installModule($module, $module_path)
{
// create db instance
$oDB = DB::getInstance();
// Create a table if the schema xml exists in the "schemas" directory of the module
$schema_dir = sprintf('%s/schemas/', $module_path);
$schema_files = FileHandler::readDir($schema_dir, NULL, false, true);
$schema_sorted = [];
foreach ($schema_files as $filename)
{
if (!preg_match('/\/([a-zA-Z0-9_]+)\.xml$/', $filename, $matches))
{
continue;
}
if (preg_match('/<table\s[^>]*deleted="true"/i', file_get_contents($filename)))
{
continue;
}
$table_name = $matches[1];
if(isset($schema_sorted[$table_name]) || $oDB->isTableExists($table_name))
{
continue;
}
$schema_sorted[$table_name] = $filename;
}
$schema_sorted = Rhymix\Framework\Parsers\DBTableParser::resolveDependency($schema_sorted);
foreach ($schema_sorted as $table_name => $filename)
{
$output = $oDB->createTable($filename);
if(!$output->toBool())
{
throw new Exception(lang('msg_create_table_failed') . ': ' . $table_name . ': ' . $oDB->getError()->getMessage());
}
}
// Create a table and module instance and then execute install() method
$oModule = ModuleModel::getModuleInstallClass($module);
if($oModule && method_exists($oModule, 'moduleInstall'))
{
$oModule->moduleInstall();
}
return new BaseObject();
}
/**
* Update a module if necessary.
*
* @param string $module
* @return mixed
*/
public function updateModule($module)
{
$oModuleController = ModuleController::getInstance();
$oModule = ModuleModel::getModuleInstallClass($module);
if (is_object($oModule) && method_exists($oModule, 'checkUpdate') && method_exists($oModule, 'moduleUpdate'))
{
if ($oModule->checkUpdate())
{
$output = $oModule->moduleUpdate();
if($output instanceof BaseObject && !$output->toBool())
{
return $output;
}
}
}
$output = $oModuleController->registerActionForwardRoutes($module);
if($output instanceof BaseObject && !$output->toBool())
{
return $output;
}
$output = $oModuleController->registerEventHandlers($module);
if($output instanceof BaseObject && !$output->toBool())
{
return $output;
}
$output = $oModuleController->registerNamespaces($module);
if($output instanceof BaseObject && !$output->toBool())
{
return $output;
}
$output = $oModuleController->registerPrefixes($module);
if($output instanceof BaseObject && !$output->toBool())
{
return $output;
}
return new BaseObject();
}
/**
* Placeholder for third-party apps that try to manipulate system configuration.
*
* @return void
*/
public function makeConfigFile()
{
return true;
}
}
/* End of file install.controller.php */
/* Location: ./modules/install/install.controller.php */