$uploaded_data = fn_filter_uploaded_data('language_data', array('po', 'zip')); if (!empty($uploaded_data['po_file']['path'])) { $ext = fn_get_file_ext($uploaded_data['po_file']['name']); if ($ext == 'po') { $result = Languages::installLanguagePack($uploaded_data['po_file']['path']); } else { $result = Languages::installZipPack($uploaded_data['po_file']['path']); } if (!$result) { fn_delete_notification('changes_saved'); } } } if ($mode == 'install' && !empty($_REQUEST['pack'])) { $pack_path = Registry::get('config.dir.lang_packs') . fn_basename($_REQUEST['pack']); if (Languages::installCrowdinPack($pack_path, array())) { return array(CONTROLLER_STATUS_OK, 'languages.manage'); } else { return array(CONTROLLER_STATUS_OK, 'languages.manage?selected_section=available_languages'); } } if ($mode == 'delete_variable') { LanguageValues::deleteVariables($_REQUEST['name']); return array(CONTROLLER_STATUS_REDIRECT); } if ($mode == 'update_status') { if (fn_allowed_for('ULTIMATE:FREE')) { if ($_REQUEST['status'] == 'H') { fn_set_notification('E', __('error'), __('language_hidden_status_free')); return array(CONTROLLER_STATUS_REDIRECT, 'languages.manage'); }
/** * Validates and installs package * * @todo Implement language installer * @todo Additional migrations validation * * @param string $package_id Package id like "core", "access_restrictions", etc * @return array($result, $data) Installation result */ public function install($package_id, $request) { $result = true; $logger = Log::instance($package_id); $logger->add(''); $logger->add(str_replace('[package_id]', $package_id, 'Start installation of the "[package_id]" upgrade package')); $logger->add('================================================'); $logger->add('Get all available validators'); Output::steps(5); // Validators, Backups (database/files), Copying Files, Migrations, Languages Output::display(__('uc_title_validators'), __('uc_upgrade_progress'), false); $validators = $this->getValidators(); $schema = $this->getSchema($package_id, true); $information_schema = $this->getSchema($package_id, false); $package_validators = $this->getPackageValidators($package_id, $schema); if (!empty($package_validators)) { $validators = array_merge($package_validators, $validators); } foreach ($validators as $validator) { $logger->add(str_replace('[validator]', $validator->getName(), 'Execute "[validator]" validator')); Output::display(__('uc_execute_validator', array('[validator]' => $validator->getName())), '', false); list($result, $data) = $validator->check($schema, $request); if (!$result) { break; } } if (!$result) { $logger->add('Upgrade stopped: Awaiting resolving validation errors: ' . $validator->getName()); return array($result, array($validator->getName() => $data)); } else { $backup_filename = "upg_{$package_id}_{$information_schema['from_version']}-{$information_schema['to_version']}_" . date('dMY_His', TIME); // Prepare restore.php file. Paste necessary data and access information $restore_key = $this->prepareRestore($backup_filename . '.zip'); if (empty($restore_key)) { $logger->add('Upgrade stopped: Unable to prepare restore file. restore.php was locally modified/removed or renamed.'); return array(false, array(__('restore') => __('upgrade_center.unable_to_prepare_restore'))); } $content_path = $this->getPackagesDir() . $package_id . '/content/'; // Run pre script if (!empty($schema['scripts']['pre'])) { include_once $content_path . 'scripts/' . $schema['scripts']['pre']; } $this->closeStore(); $logger->add('Backup files and Database'); Output::display(__('backup_data'), '', true); $backup_file = DataKeeper::backup(array('pack_name' => $backup_filename, 'compress' => 'zip', 'set_comet_steps' => false, 'move_progress' => false)); if (empty($backup_file) || !file_exists($backup_file)) { $logger->add('Upgrade stopped: Failed to backup DB/Files'); return array(false, array(__('backup') => __('text_uc_failed_to_backup_tables'))); } // Send mail to admin e-mail with information about backup Mailer::sendMail(array('to' => 'company_site_administrator', 'from' => 'default_company_site_administrator', 'data' => array('backup_file' => $backup_file, 'settings_section_url' => fn_url('settings.manage'), 'restore_link' => Registry::get('config.http_location') . '/var/upgrade/restore.php?uak=' . $restore_key), 'tpl' => 'upgrade/backup_info.tpl'), 'A', Registry::get('settings.Appearance.backend_default_language')); $logger->add('Copy package files'); Output::display(__('uc_copy_files'), '', true); // Move files from package $this->applyPackageFiles($content_path . 'package', $this->config['dir']['root']); $this->cleanupOldFiles($schema, $this->config['dir']['root']); // Copy files from themes_repository to design folder $this->processThemesFiles($schema); Output::display(__('uc_run_migrations'), '', true); // Run migrations if (!empty($schema['migrations'])) { $logger->add('Run migrations'); $minimal_date = 0; foreach ($schema['migrations'] as $migration) { preg_match('/^[0-9]+/', $migration, $matches); if (!empty($matches[0])) { $date = $matches[0]; if ($date < $minimal_date || empty($minimal_date)) { $minimal_date = $date; } } } $config = array('migration_dir' => $content_path . 'migrations/', 'package_id' => $package_id); Migration::instance($config)->migrate($minimal_date); } // Install languages Output::display(__('uc_install_languages'), '', true); if (!empty($schema['languages'])) { $logger->add('Install langauges from the upgrade package'); $avail_languages = Languages::getAvailable('A', true); foreach ($avail_languages as $lang_code => $language) { if (in_array($lang_code, $schema['languages'])) { $logger->add(str_replace('[lang_code]', $lang_code, 'Install the \\"[lang_code]\\" language')); Output::display(__('install') . ': ' . $lang_code, '', false); Languages::installCrowdinPack($content_path . 'languages/' . $lang_code, array('install_newly_added' => true, 'validate_lang_code' => true, 'reinstall' => true)); } else { $pack_code = ''; if (in_array(CART_LANGUAGE, $schema['languages'])) { $pack_code = CART_LANGUAGE; } elseif (in_array('en', $schema['languages'])) { $pack_code = 'en'; } if (file_exists($content_path . 'languages/' . $pack_code)) { // Fill the unknown language by the Default/EN language variables Languages::installCrowdinPack($content_path . 'languages/' . $pack_code, array('reinstall' => true, 'force_lang_code' => $lang_code, 'install_newly_added' => true)); } } } } } // Run post script if (!empty($schema['scripts']['post'])) { include_once $content_path . 'scripts/' . $schema['scripts']['post']; } Output::display(__('text_uc_upgrade_completed'), '', true); $logger->add('Upgrade completed'); $this->deletePackage($package_id); // Clear obsolete files fn_clear_cache(); fn_rm(Registry::get('config.dir.cache_templates')); return array(true, array()); }
public static function setActualLangValues() { $addons = self::getInstalledAddons(); $languages = db_get_fields("SELECT lang_code FROM ?:languages"); foreach ($addons as $addon) { $addon_scheme = AddonSchemesManager::getScheme($addon); if (!empty($addon_scheme)) { // Add optional language variables $language_variables = $addon_scheme->getLanguageValues(); if (!empty($language_variables)) { db_query('REPLACE INTO ?:language_values ?m', $language_variables); } foreach ($languages as $lang_code) { $description = $addon_scheme->getDescription($lang_code); $addon_name = $addon_scheme->getName($lang_code); db_query("UPDATE ?:addon_descriptions SET description = ?s, name = ?s WHERE addon = ?s AND lang_code = ?s", $description, $addon_name, $addon, $lang_code); } $tabs = $addon_scheme->getSections(); if (!empty($tabs)) { foreach ($tabs as $tab_index => $tab) { $addon_section_id = db_get_field("SELECT section_id FROM ?:settings_sections WHERE name = ?s AND parent_id = (SELECT section_id FROM ?:settings_sections WHERE name = ?s)", $tab['id'], $addon); //Can't check edition here, so just skip description update if addon section was not found. if (!empty($addon_section_id)) { fn_update_addon_settings_descriptions($addon_section_id, Settings::SECTION_DESCRIPTION, $tab['translations']); $settings = $addon_scheme->getSettings($tab['id']); foreach ($settings as $k => $setting) { $setting_id = db_get_field("SELECT object_id FROM ?:settings_objects WHERE name = ?s AND section_tab_id = ?i", $setting['id'], $addon_section_id); if (!empty($setting_id)) { fn_update_addon_settings_descriptions($setting_id, Settings::SETTING_DESCRIPTION, $setting['translations']); if (isset($setting['variants'])) { foreach ($setting['variants'] as $variant_k => $variant) { $variant_id = db_get_field("SELECT variant_id FROM ?:settings_variants WHERE object_id = ?i AND name = ?s", $setting_id, $variant['id']); if (!empty($variant_id)) { fn_update_addon_settings_descriptions($variant_id, Settings::VARIANT_DESCRIPTION, $variant['translations']); } } } } } } } } } } General::connectToOriginalDB(array('table_prefix' => General::formatPrefix())); $prefix = Registry::get('config.table_prefix'); /* db_query("INSERT INTO ?:state_descriptions (SELECT state_id, ?s as lang_code, state FROM " . $prefix . "state_descriptions WHERE lang_code = ?s) ON DUPLICATE KEY UPDATE ?:state_descriptions.state_id = ?:state_descriptions.state_id", General::$default_language, DEFAULT_LANGUAGE); if (fn_allowed_for('ULTIMATE')) { db_query("INSERT INTO ?:ult_language_values (SELECT ?s as lang_code, name, value, company_id FROM " . $prefix . "ult_language_values WHERE lang_code = ?s) ON DUPLICATE KEY UPDATE ?:ult_language_values.value = ?:ult_language_values.value", General::$default_language, DEFAULT_LANGUAGE); } $new_ver_langs = db_get_fields("SELECT lang_code FROM " . $prefix . "languages"); foreach (db_get_fields("SELECT lang_code FROM ?:languages") as $lang_code) { $_lang_code = in_array($lang_code, $new_ver_langs) ? $lang_code : DEFAULT_LANGUAGE; //We can update only core settings descriptions because addons descriptions were updated during settings restore. db_query("INSERT INTO ?:settings_descriptions " . "(SELECT object_id, object_type, ?s as lang_code, value, tooltip FROM " . $prefix . "settings_descriptions WHERE object_id IN " . "(SELECT object_id FROM " . $prefix . "settings_objects WHERE section_id IN " . "(SELECT section_id FROM " . $prefix . "settings_sections WHERE type = 'CORE')) " . "AND lang_code = ?s) " . "ON DUPLICATE KEY UPDATE ?:settings_descriptions.value = " . $prefix . "settings_descriptions.value, ?:settings_descriptions.tooltip = " . $prefix . "settings_descriptions.tooltip", $lang_code, $_lang_code ); db_query("INSERT INTO ?:language_values " . "(SELECT ?s as lang_code, name, value FROM " . $prefix . "language_values WHERE lang_code = ?s) " . "ON DUPLICATE KEY UPDATE ?:language_values.name = " . $prefix . "language_values.name", $lang_code, $_lang_code ); } db_query("REPLACE INTO ?:original_values (SELECT * FROM " . $prefix . "original_values)"); */ $langs = db_get_fields("SELECT lang_code FROM ?:languages"); $po_path = Registry::get('config.dir.lang_packs'); $params = array('install_newly_added' => true, 'reinstall' => true); foreach ($langs as $lang_code) { $params['force_lang_code'] = $lang_code; $params['validate_lang_code'] = true; if (!is_dir($po_path . $lang_code)) { $params['validate_lang_code'] = false; if (is_dir($po_path . General::$default_language)) { $lang_code = General::$default_language; $params['force_lang_code'] = General::$default_language; } elseif (is_dir($po_path . 'en')) { $lang_code = 'en'; $params['force_lang_code'] = 'en'; } } $result = Languages::installCrowdinPack($po_path . $lang_code, $params); } return true; }
protected function installUpgradePackage($package_id, $request) { $result = true; $information_schema = $this->getSchema($package_id, false); $logger = Log::instance($package_id); $logger->drawHeader()->add(array(sprintf('Starting installation of the "%s" upgrade package', $package_id), sprintf('Upgrading version %s to %s', $information_schema['from_version'], $information_schema['to_version']), sprintf('Running as user "%s"', fn_get_process_owner_name()))); Output::steps(5); // Validators, Backups (database/files), Copying Files, Migrations, Languages Output::display(__('uc_title_validators'), __('uc_upgrade_progress'), false); $logger->add('Executing pre-upgrade validators'); $validators = $this->getValidators(); $schema = $this->getSchema($package_id, true); $package_validators = $this->getPackageValidators($package_id, $schema); $logger->add(sprintf('Found %u validators at package', sizeof($package_validators))); if (!empty($package_validators)) { $validators = array_merge($package_validators, $validators); } foreach ($validators as $validator) { $logger->add(sprintf('Executing "%s" validator', $validator->getName())); Output::display(__('uc_execute_validator', array('[validator]' => $validator->getName())), '', false); list($result, $data) = $validator->check($schema, $request); if (!$result) { break; } } if (!$result) { $logger->add(sprintf('Upgrade stopped: awaiting resolving "%s" validator errors', $validator->getName())); return array($result, array($validator->getName() => $data)); } else { $result = self::PACKAGE_INSTALL_RESULT_SUCCESS; $backup_filename = "upg_{$package_id}_{$information_schema['from_version']}-{$information_schema['to_version']}_" . date('dMY_His', TIME); $logger->add(sprintf('Backup filename is "%s"', $backup_filename)); // Prepare restore.php file. Paste necessary data and access information $restore_preparation_result = $this->prepareRestore($package_id, $schema, $information_schema, $backup_filename . '.zip'); if (!$restore_preparation_result) { $logger->add('Upgrade stopped: unable to prepare restore file.'); return array(false, array(__('restore') => __('upgrade_center.error_unable_to_prepare_restore'))); } list($restore_key, $restore_file_path, $restore_http_path) = $restore_preparation_result; $content_path = $this->getPackagesDir() . $package_id . '/content/'; // Run pre script if (!empty($schema['scripts']['pre'])) { $pre_script_file_path = $content_path . 'scripts/' . $schema['scripts']['pre']; $logger->add(sprintf('Executing pre-upgrade script "%s"', $pre_script_file_path)); include_once $pre_script_file_path; $logger->add('Pre-upgrade script executed successfully'); } $logger->add('Closing storefront'); $this->closeStore(); $logger->add('Backing up files and database'); Output::display(__('backup_data'), '', true); $backup_file = DataKeeper::backup(array('pack_name' => $backup_filename, 'compress' => 'zip', 'set_comet_steps' => false, 'move_progress' => false, 'extra_folders' => array('var/langs'))); if (empty($backup_file) || !file_exists($backup_file)) { $logger->add('Upgrade stopped: failed to backup DB/files'); return array(false, array(__('backup') => __('text_uc_failed_to_backup_tables'))); } $logger->add(sprintf('Backup created at "%s"', $backup_file)); // Send mail to admin e-mail with information about backup $email_recipients = array(); $user_data = fn_get_user_short_info($_SESSION['auth']['user_id']); if (!empty($user_data['email'])) { $email_recipients[] = $user_data['email']; } $user_is_root_admin = isset($_SESSION['auth']['is_root']) && $_SESSION['auth']['is_root'] == 'Y'; if (!$user_is_root_admin) { $root_admin_id = db_get_field("SELECT user_id FROM ?:users WHERE company_id = 0 AND is_root = 'Y' AND user_type = 'A'"); $root_admin_data = fn_get_user_short_info($root_admin_id); if (!empty($root_admin_data['email'])) { $email_recipients[] = $root_admin_data['email']; } } $logger->add(sprintf('Sending upgrade information e-mail to: %s', implode(', ', $email_recipients))); $mail_sent = Mailer::sendMail(array('to' => $email_recipients, 'from' => 'default_company_site_administrator', 'data' => array('backup_file' => $backup_file, 'settings_section_url' => fn_url('settings.manage'), 'restore_link' => "{$restore_http_path}?uak={$restore_key}"), 'tpl' => 'upgrade/backup_info.tpl'), 'A', Registry::get('settings.Appearance.backend_default_language')); if ($mail_sent) { $logger->add('E-mail was successfully sent'); } else { $logger->add('Failed to send e-mail'); return array(false, array()); } Output::display(__('uc_copy_files'), '', true); // Move files from package $logger->add('Copying package files'); $this->applyPackageFiles($content_path . 'package', $this->config['dir']['root']); $logger->add('Deleting files removed at new version'); $this->cleanupOldFiles($schema, $this->config['dir']['root']); // Copy files from themes_repository to design folder $logger->add('Processing themes files'); $this->processThemesFiles($schema); Output::display(__('uc_run_migrations'), '', true); // Run migrations if (empty($schema['migrations'])) { $logger->add('No migrations found at package'); } else { $logger->add(sprintf('Executing %u migrations found at package', sizeof($schema['migrations']))); $minimal_date = 0; foreach ($schema['migrations'] as $migration) { preg_match('/^[0-9]+/', $migration, $matches); if (!empty($matches[0])) { $date = $matches[0]; if ($date < $minimal_date || empty($minimal_date)) { $minimal_date = $date; } } } $config = array('migration_dir' => realpath($content_path . 'migrations/'), 'package_id' => $package_id); try { $migration_succeed = Migration::instance($config)->migrate($minimal_date); } catch (DatabaseException $e) { // Find out which migration caused an exception using its trace $failed_migration_file = null; // DatabaseException could be thrown as a replacement of original exception, // in this case we should look through original's exception trace $exception_with_trace = $e->getPrevious() ?: $e; foreach ($exception_with_trace->getTrace() as $trace) { if (isset($trace['file']) && strpos($trace['file'], $config['migration_dir']) === 0) { $failed_migration_file = basename($trace['file']); break; } } $this->setNotification('E', __('error'), __('uc_migration_failed', array('[migration]' => $failed_migration_file))); $migration_succeed = false; $logger->add((string) $e); } if ($migration_succeed) { $logger->add('Migrations were executed successfully'); } else { $result = self::PACKAGE_INSTALL_RESULT_WITH_ERRORS; $logger->add('Failed to execute migrations'); } } // Install languages Output::display(__('uc_install_languages'), '', true); // Install langs that are provided by package if (!empty($schema['languages'])) { $logger->add('Installing languages provided by package'); $logger->add(sprintf('Package languages: %s', implode(', ', $schema['languages']))); $avail_languages = Languages::getAvailable('A', true); $logger->add(sprintf('Already installed languages: %s', implode(', ', array_keys($avail_languages)))); foreach ($avail_languages as $lang_code => $language) { if (in_array($lang_code, $schema['languages'])) { $logger->add(sprintf('Installing "%s" language', $lang_code)); Output::display(__('install') . ': ' . $lang_code, '', false); Languages::installCrowdinPack($content_path . 'languages/' . $lang_code, array('install_newly_added' => true, 'validate_lang_code' => true, 'reinstall' => true)); } else { $pack_code = ''; if (in_array(CART_LANGUAGE, $schema['languages'])) { $pack_code = CART_LANGUAGE; } elseif (in_array('en', $schema['languages'])) { $pack_code = 'en'; } if (!empty($pack_code) && file_exists($content_path . 'languages/' . $pack_code)) { // Fill the unknown language by the Default/EN language variables Languages::installCrowdinPack($content_path . 'languages/' . $pack_code, array('reinstall' => true, 'force_lang_code' => $lang_code, 'install_newly_added' => true)); } } } } else { // Install languages using upgraded /var/langs/*/*.po files $logger->add('Installing languages using upgraded *.po files'); $langs_meta = Languages::getLangPacksMeta('', '', true); $lang_packs = array(); foreach ($langs_meta as $value) { $lang_packs[$value['lang_code']] = $value; } $logger->add(sprintf('Found language packs: %s', implode(', ', array_keys($lang_packs)))); $avail_languages = Languages::getAvailable('A', true); $logger->add(sprintf('Already installed languages: %s', implode(', ', array_keys($avail_languages)))); foreach ($avail_languages as $lang_code => $language) { if (isset($lang_packs[$lang_code])) { $logger->add(sprintf('Installing "%s" language', $lang_code)); Output::display(__('install') . ': ' . $lang_code, '', false); $pack_path = $this->config['dir']['lang_packs'] . $lang_code; Languages::installCrowdinPack($pack_path, array('install_newly_added' => true, 'validate_lang_code' => true, 'reinstall' => true)); } else { $pack_code = ''; if (isset($lang_packs[CART_LANGUAGE])) { $pack_code = CART_LANGUAGE; } elseif (isset($lang_packs['en'])) { $pack_code = 'en'; } $pack_path = $this->config['dir']['lang_packs'] . $pack_code; if (!empty($pack_code) && file_exists($pack_path)) { // Fill the unknown language by the Default/EN language variables Languages::installCrowdinPack($pack_path, array('reinstall' => true, 'force_lang_code' => $lang_code, 'install_newly_added' => true)); } } } } } $upgrade_schema = $this->getSchema($package_id); // Run post script if (!empty($schema['scripts']['post'])) { $post_script_file_path = $content_path . 'scripts/' . $schema['scripts']['post']; $logger->add(sprintf('Executing post-upgrade script "%s"', $post_script_file_path)); include_once $post_script_file_path; $logger->add('Post-upgrade script executed successfully'); } // Clear obsolete files $logger->add('Cleaning cache'); fn_clear_cache(); fn_rm(Registry::get('config.dir.cache_templates')); // Add information to "Installed upgrades section" $logger->add('Saving upgrade information to DB'); $this->storeInstalledUpgrade($upgrade_schema); // Collect statistic data $logger->add('Sending statistics'); Http::get(Registry::get('config.resources.updates_server') . '/index.php?dispatch=product_updates.updated', $this->getStatsData($package_id), array('timeout' => 10)); $this->onSuccessPackageInstall($package_id, $schema, $information_schema); $logger->add('Deleting package contents'); $this->deletePackage($package_id); Output::display(__('text_uc_upgrade_completed'), '', true); $logger->add('Upgrade completed!'); return array($result, array()); }
/** * @param array $package_content_schema Package content schema * @param Log $logger Logger instance * @param string $package_content_path Package content path * * @return array First element is a list of languages to be installed, second element is a list languages failed to install */ public function installLanguages($package_content_schema, Log $logger, $package_content_path) { $failed_to_install = array(); $installed_languages = array_keys(Languages::getAvailable('A', true)); if (empty($package_content_schema['languages'])) { $logger->add('Installing languages using upgraded *.po files'); $po_pack_basepath = $this->config['dir']['lang_packs']; $lang_codes_to_install = $this->getLangCodesToReinstallFromContentSchema($package_content_schema); } else { $logger->add('Installing languages provided by package'); $po_pack_basepath = $package_content_path . 'languages/'; $lang_codes_to_install = (array) $package_content_schema['languages']; } $logger->add(sprintf('Already installed languages: %s', implode(', ', $installed_languages))); $logger->add(sprintf('Languages to be installed: %s', implode(', ', $lang_codes_to_install))); if (in_array(CART_LANGUAGE, $lang_codes_to_install)) { $fallback_lang_code = CART_LANGUAGE; } elseif (in_array('en', $lang_codes_to_install)) { $fallback_lang_code = 'en'; } else { $fallback_lang_code = null; } foreach ($installed_languages as $lang_code) { $logger->lineStart(sprintf('Installing "%s" language... ', $lang_code)); if (in_array($lang_code, $lang_codes_to_install)) { Output::display(__('install') . ': ' . $lang_code, '', false); if (false === Languages::installCrowdinPack($po_pack_basepath . $lang_code, array('install_newly_added' => true, 'validate_lang_code' => $lang_code, 'reinstall' => true))) { $logger->lineEnd('FAILED'); $failed_to_install[] = $lang_code; } else { $logger->lineEnd('OK'); } } elseif ($fallback_lang_code !== null) { if (false === Languages::installCrowdinPack($po_pack_basepath . $fallback_lang_code, array('reinstall' => true, 'force_lang_code' => $lang_code, 'install_newly_added' => true))) { $logger->lineEnd('FAILED'); $failed_to_install[] = $lang_code; } else { $logger->lineEnd('OK'); } } else { $logger->lineEnd('SKIPPED'); } } return array($lang_codes_to_install, $failed_to_install); }