Index: branches/unlabeled/unlabeled-1.6.2/core/install.php =================================================================== diff -u -r7471 -r7525 --- branches/unlabeled/unlabeled-1.6.2/core/install.php (.../install.php) (revision 7471) +++ branches/unlabeled/unlabeled-1.6.2/core/install.php (.../install.php) (revision 7525) @@ -7,6 +7,12 @@ define('FULL_PATH', realpath(dirname(__FILE__).'/..') ); define('REL_PATH', '/core'); + /** + * Upgrade sqls are located using this mask + * + */ + define('UPGRADES_FILE', FULL_PATH.'/%sinstall/upgrades.sql'); + // print_pre($_POST); $install_engine = new kInstallator(); @@ -73,20 +79,26 @@ 'fresh_install' => Array ('check_paths', 'db_config', 'root_password', 'choose_modules', 'finish'), 'already_installed' => Array ('install_setup'), - 'upgrade' => Array ('install_setup',/* ..., */ 'finish'), + 'upgrade' => Array ('install_setup', 'upgrade_modules', /* ..., */ 'finish'), 'db_reconfig' => Array ('install_setup',/* ..., */ 'finish'), 'fix_paths' => Array ('install_setup',/* ..., */ 'finish'), ); /** + * Steps, that doesn't required admin to be logged-in to proceed + * + * @var Array + */ + var $skipLoginSteps = Array ('root_password', 'choose_modules', 'finish', -1); + + /** * Steps, on which kApplication should not be initialized, because of missing correct db table structure * * @var Array */ + var $skipApplicationSteps = Array ('check_paths', 'db_config'/*, 'install_setup'*/); // remove install_setup when application will work separately from install - var $skipApplicationSteps = Array ('check_paths', 'db_config', 'install_setup'); // remove install_setup when application will work separately from install - /** * Folders that should be writeable to continue installation * @@ -131,17 +143,24 @@ $this->currentStep = $this->GetVar('step'); + // can't check login on steps where no application present anyways :) + $this->skipLoginSteps = array_unique(array_merge($this->skipLoginSteps, $this->skipApplicationSteps)); + $this->SelectPreset(); if (!$this->currentStep) { - // first step of current preset - reset($this->steps[$this->stepsPreset]); - $this->currentStep = current($this->steps[$this->stepsPreset]); + $this->SetFirstStep(); // sets first step of current preset } $this->InitStep(); } + function SetFirstStep() + { + reset($this->steps[$this->stepsPreset]); + $this->currentStep = current($this->steps[$this->stepsPreset]); + } + /** * Selects preset to proceed based on various criteria * @@ -153,8 +172,12 @@ // only at installation first step $status = $this->CheckDatabase(false); if ($status && $this->AlreadyInstalled()) { - $preset = 'already_installed'; - $this->currentStep = ''; + // if already installed, then all future actions need login to work + $this->skipLoginSteps = Array (-1); + if (!$preset) { + $preset = 'already_installed'; + $this->currentStep = ''; + } } } if ($preset === false) { @@ -163,7 +186,7 @@ $this->stepsPreset = $preset; } - + function GetVar($name) { return isset($_REQUEST[$name]) ? $_REQUEST[$name] : false; @@ -175,8 +198,17 @@ */ function InitStep() { - $this->InitApplication(); + $require_login = !in_array($this->currentStep, $this->skipLoginSteps); + $this->InitApplication($require_login); + if ($require_login) { + // step require login to proceed + if (!$this->Application->LoggedIn()) { + $this->stepsPreset = 'already_installed'; + $this->SetFirstStep(); + } + } + switch ($this->currentStep) { case 'check_paths': foreach ($this->writeableFolders as $folder_path) { @@ -217,30 +249,43 @@ } break; - case 'install_setup': - if ($this->stepsPreset == 'already_installed') { - // if preset was not choosen, then raise error - $this->errorMessage = 'Please select action to perform'; + case 'upgrade_modules': + // get installed modules from db and compare their versions to upgrade script + $modules = $this->GetUpgradableModules(); + if (!$modules) { + $this->currentStep = $this->GetNextStep(); } - else { - // if preset was choosen, then check root password entered - $user_name = $this->GetVar('user_name'); - $user_password = $this->GetVar('user_password'); - - if ($user_name == 'root') { - $sql = 'SELECT VariableValue - FROM '.$this->systemConfig['Database']['TablePrefix'].' - WHERE VariableName = "RootPass"'; - $root_password = $this->Conn->GetOne($sql); - $user_password = md5( md5($user_password) . 'b38'); - if ($user_password != $root_password) { - $this->errorMessage = 'Invalid User Name or Password. If you don\'t know your username or password, contact Intechnic Support'; + break; + + case 'install_setup': + $next_preset = $this->Application->GetVar('next_preset'); + if ($next_preset !== false && $this->Application->GetVar('login') == 'root') { + // option was choosen, then verify password & login user + $login_event = new kEvent('u.current:OnLogin'); + $this->Application->HandleEvent($login_event); + + if ($login_event->status == erSUCCESS) { + // login succeeded + + if (!isset($this->steps[$next_preset])) { + $this->errorMessage = 'Preset "'.$next_preset.'" not yet implemented'; } + else { + $this->stepsPreset = $next_preset; + } } else { - $this->errorMessage = 'By now only login using "root" username is supported'; + // login failed + $user =& $this->Application->recallObject('u.current'); + /* @var $user UsersItem */ + + $this->errorMessage = $user->GetErrorMsg('ValidateLogin').'. If you don\'t know your username or password, contact Intechnic Support'; } } + else { + // if preset was not choosen, then raise error + $this->errorMessage = 'Please select action to perform'; + } break; } @@ -341,13 +386,14 @@ case 'choose_modules': // run module install scripts $modules = $this->Application->GetVar('modules'); - foreach ($modules as $module) { - $install_file = MODULES_PATH.'/'.$module.'/install.php'; - if (file_exists($install_file)) { - include_once($install_file); + if ($modules) { + foreach ($modules as $module) { + $install_file = MODULES_PATH.'/'.$module.'/install.php'; + if (file_exists($install_file)) { + include_once($install_file); + } } } - // scan themes $themes_helper =& $this->Application->recallObject('ThemesHelper'); /* @var $themes_helper kThemesHelper */ @@ -362,8 +408,50 @@ $updater->OneStepRun(); break; + + case 'upgrade_modules': + // get installed modules from db and compare their versions to upgrade script + $modules = $this->Application->GetVar('modules'); + if ($modules) { + $upgrade_data = $this->GetUpgradableModules(); + + foreach ($modules as $module_name) { + $module_info = $upgrade_data[$module_name]; + $upgrades_file = sprintf(UPGRADES_FILE, $module_info['Path']); + + $sqls = file_get_contents($upgrades_file); + $version_mark = '# ===== v '.$module_info['FromVersion'].' ====='; + + $start_pos = strpos($sqls, $version_mark); + $sqls = substr($sqls, $start_pos); + $this->RunSQLText($sqls); + + // after upgrade sqls are executed update version + $sql = 'UPDATE '.TABLE_PREFIX.'Modules + SET Version = "'.$module_info['ToVersion'].'" + WHERE Name = "'.$module_name.'"'; + $this->Conn->Query($sql); + } + } + else { + $this->errorMessage = 'Please select module(-s) to upgrade'; + } + break; + case 'finish': - $this->Conn->Query('INSERT INTO '.TABLE_PREFIX.'ConfigurationValues (VariableName, VariableValue) VALUE (\'InstallFinished\', 1)'); + // delete cache + $sql = 'DELETE FROM '.TABLE_PREFIX.'Cache + WHERE VarName IN ("config_files","configs_parsed","sections_parsed")'; + $this->Conn->Query($sql); + + // set installation finished mark + if ($this->Application->ConfigValue('InstallFinished') === false) { + $fields_hash = Array ( + 'VariableName' => 'InstallFinished', + 'VariableValue' => 1, + ); + $this->Conn->doInsert($fields_hash, TABLE_PREFIX.'ConfigurationValues'); + } break; } @@ -397,11 +485,16 @@ $this->Conn->Query($sql); } - function InitApplication() + /** + * Initialize kApplication + * + * @param bool $force initialize in any case + */ + function InitApplication($force = false) { - if (!in_array($this->currentStep, $this->skipApplicationSteps) && !isset($this->Application)) { + if (($force || !in_array($this->currentStep, $this->skipApplicationSteps)) && !isset($this->Application)) { // step is allowed for application usage & it was not initialized in previous step - global $debugger; + global $start, $debugger, $dbg_options; include_once(FULL_PATH.'/core/kernel/startup.php'); $this->Application =& kApplication::Instance(); @@ -425,7 +518,7 @@ if (isset($this->Application)) { $this->Application->Done(); - echo 'SID: ['.$this->Application->GetSID().']
'; +// echo 'SID: ['.$this->Application->GetSID().']
'; } exit; @@ -545,14 +638,32 @@ return $all_found; } + /** + * Runs SQLs from file + * + * @param string $filename + * @param mixed $replace_from + * @param mixed $replace_to + */ function RunSQL($filename, $replace_from = null, $replace_to = null) { if (!file_exists(FULL_PATH.$filename)) { return ; } $sqls = file_get_contents(FULL_PATH.$filename); + $this->RunSQLText($sqls, $replace_from, $replace_to); + } + /** + * Runs SQLs from string + * + * @param string $sqls + * @param mixed $replace_from + * @param mixed $replace_to + */ + function RunSQLText(&$sqls, $replace_from = null, $replace_to = null) + { $table_prefix = $this->systemConfig['Database']['TablePrefix']; // add prefix to all tables @@ -568,13 +679,15 @@ // replace something additionally, e.g. module root category $sqls = str_replace($replace_from, $replace_to, $sqls); } - + + $sqls = str_replace("\r\n", "\n", $sqls); // convert to linux line endings + $sqls = preg_replace("/#(.*?)\n/", '', $sqls); // remove all comments $sqls = explode(";\n", $sqls); foreach ($sqls as $sql) { $sql = trim($sql); - if (!$sql || substr($sql, 0, 1) == '#') { - continue; // usually last line || comment + if (!$sql) { + continue; // usually last line } $this->Conn->Query($sql); if ($this->Conn->getErrorCode() != 0) { @@ -584,7 +697,7 @@ } } } - + function ImportLanguage($lang_file) { $lang_file = FULL_PATH.$lang_file.'.lang'; @@ -627,6 +740,69 @@ } /** + * Converts module version in format X.Y.Z to signle integer + * + * @param string $version + * @return int + */ + function ConvertModuleVersion($version) + { + $parts = explode('.', $version); + + $bin = ''; + foreach ($parts as $part) { + $bin .= str_pad(decbin($part), 8, '0', STR_PAD_LEFT); + } + + return bindec($bin); + } + + /** + * Returns list of modules, that can be upgraded + * + */ + function GetUpgradableModules() + { + $ret = Array (); + + foreach ($this->Application->ModuleInfo as $module_name => $module_info) { + $upgrades_file = sprintf(UPGRADES_FILE, $module_info['Path']); + if (!file_exists($upgrades_file)) { + // no upgrade file + continue; + } + + $sqls = file_get_contents($upgrades_file); + $versions_found = preg_match_all('/# ===== v ([\d]+\.[\d]+\.[\d]+) =====/s', $sqls, $regs); + if (!$versions_found) { + // upgrades file doesn't contain version definitions + continue; + } + + $to_version = end($regs[1]); + $this_version = $this->ConvertModuleVersion($module_info['Version']); + if ($this->ConvertModuleVersion($to_version) > $this_version) { + // destination version is greather then current + foreach ($regs[1] as $version) { + if ($this->ConvertModuleVersion($version) > $this_version) { + $from_version = $version; + break; + } + } + + $version_info = Array ( + 'FromVersion' => $from_version, + 'ToVersion' => $to_version, + ); + + $ret[$module_name] = array_merge_recursive2($module_info, $version_info); + } + } + + return $ret; + } + + /** * Returns content to show for current step * * @return string