Файловый менеджер - Редактировать - /var/www/html/libraries/kunena/src/Install/KunenaModelInstall.php
Ðазад
<?php /** * Kunena Component * * @package Kunena.Installer * * @copyright Copyright (C) 2008 - @currentyear@ Kunena Team. All rights reserved. * @license https://www.gnu.org/copyleft/gpl.html GNU/GPL * @link https://www.kunena.org **/ namespace Kunena\Forum\Libraries\Install; \defined('_JEXEC') or die(); use Exception; use Joomla\Archive\Archive; use Joomla\CMS\Cache\Cache; use Joomla\CMS\Cache\CacheController; use Joomla\CMS\Cache\CacheControllerFactoryInterface; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\Filesystem\File; use Joomla\Filesystem\Folder; use Joomla\Filesystem\Path; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Language\LanguageHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Menu\AbstractMenu; use Joomla\CMS\MVC\Model\BaseDatabaseModel; use Joomla\CMS\Session\Session; use Joomla\CMS\Table\Extension; use Joomla\CMS\Table\MenuType; use Joomla\CMS\Table\Menu; use Joomla\CMS\Uri\Uri; use Joomla\Database\DatabaseDriver; use Joomla\Database\DatabaseInterface; use Joomla\Registry\Registry; use Joomla\String\StringHelper; use Kunena\Forum\Libraries\Factory\KunenaFactory; use Kunena\Forum\Libraries\Forum\Category\KunenaCategoryHelper; use Kunena\Forum\Libraries\Forum\KunenaForum; use Kunena\Forum\Libraries\Forum\Message\Thankyou\KunenaMessageThankyouHelper; use Kunena\Forum\Libraries\Forum\Topic\KunenaTopicHelper; use Kunena\Forum\Libraries\Forum\Topic\User\KunenaTopicUserHelper; use Kunena\Forum\Libraries\Menu\KunenaMenuFix; use Kunena\Forum\Libraries\Menu\KunenaMenuHelper; use Kunena\Forum\Libraries\Path\KunenaPath; use Kunena\Forum\Libraries\Route\KunenaRoute; use Kunena\Forum\Libraries\User\KunenaUserHelper; use stdClass; use const KPATH_ADMIN; /** * */ \define('KUNENA_INSTALLER_PATH', __DIR__); /** * */ \define('KUNENA_INSTALLER_ADMINPATH', \dirname(KUNENA_INSTALLER_PATH)); /** * */ \define('KUNENA_INSTALLER_SITEPATH', JPATH_SITE . '/components/' . basename(KUNENA_INSTALLER_ADMINPATH)); /** * */ \define('KUNENA_INSTALLER_MEDIAPATH', JPATH_SITE . '/media/kunena'); /** * Install Model for Kunena * * @since Kunena 6.0 */ class KunenaModelInstall extends BaseDatabaseModel { /** * @var array|null * @since Kunena 6.0 */ public $steps = null; /** * @var boolean * @since Kunena 6.0 */ protected $_versionprefix = false; /** * @var array * @since Kunena 6.0 */ protected $_installed = []; /** * @var array * @since Kunena 6.0 */ protected $_versions = []; /** * @var boolean * @since Kunena 6.0 */ protected $_action = false; /** * @var null * @since Kunena 6.0 */ protected $_errormsg = null; /** * @var array|null * @since Kunena 6.0 */ protected $_versiontablearray = null; /** * @var null * @since Kunena 6.0 */ protected $_versionarray = null; private $tables; /** * @var DatabaseDriver|null * @since version */ private $db; /** * @var array * @since version */ private $_sbVersions; /** * @var array * @since version */ private $_fbVersions; /** * @var \null[][] * @since version */ private $_kVersions; /** * @throws Exception * @since Kunena 6.0 */ public function __construct() { // Load installer language file only from the component $lang = Factory::getApplication()->getLanguage(); $lang->load('com_kunena.install', KUNENA_INSTALLER_ADMINPATH, 'en-GB'); $lang->load('com_kunena.install', KUNENA_INSTALLER_ADMINPATH); $lang->load('com_kunena.libraries', KUNENA_INSTALLER_ADMINPATH, 'en-GB'); $lang->load('com_kunena.libraries', KUNENA_INSTALLER_ADMINPATH); parent::__construct(); $this->db = Factory::getContainer()->get('DatabaseDriver'); if (\function_exists('ignore_user_abort')) { ignore_user_abort(true); } $this->setState('default_max_time', @\ini_get('max_execution_time')); @set_time_limit(300); $this->setState('max_time', @\ini_get('max_execution_time')); // TODO: move to migration $this->_versiontablearray = [['prefix' => 'kunena_', 'table' => 'kunena_version'], ['prefix' => 'fb_', 'table' => 'fb_version']]; // TODO: move to migration $this->_kVersions = [ ['component' => null, 'prefix' => null, 'version' => null, 'date' => null], ]; // TODO: move to migration $this->_fbVersions = [ [ 'component' => 'FireBoard', 'prefix' => 'fb_', 'version' => '1.0.4', 'date' => '2007-12-23', 'table' => 'fb_sessions', 'column' => 'currvisit', ], [ 'component' => 'FireBoard', 'prefix' => 'fb_', 'version' => '1.0.3', 'date' => '2007-09-04', 'table' => 'fb_categories', 'column' => 'headerdesc', ], [ 'component' => 'FireBoard', 'prefix' => 'fb_', 'version' => '1.0.2', 'date' => '2007-08-03', 'table' => 'fb_users', 'column' => 'rank', ], [ 'component' => 'FireBoard', 'prefix' => 'fb_', 'version' => '1.0.1', 'date' => '2007-05-20', 'table' => 'fb_users', 'column' => 'uhits', ], [ 'component' => 'FireBoard', 'prefix' => 'fb_', 'version' => '1.0.0', 'date' => '2007-04-15', 'table' => 'fb_messages', ], ['component' => null, 'prefix' => null, 'version' => null, 'date' => null], ]; // TODO: move to migration $this->_sbVersions = [ [ 'component' => 'JoomlaBoard', 'prefix' => 'sb_', 'version' => 'v1.0.5', 'date' => '1000-01-01', 'table' => 'sb_messages', ], ['component' => null, 'prefix' => null, 'version' => null, 'date' => null], ]; $this->steps = [ ['step' => '', 'menu' => Text::_('COM_KUNENA_INSTALL_STEP_INSTALL')], ['step' => 'Prepare', 'menu' => Text::_('COM_KUNENA_INSTALL_STEP_PREPARE')], ['step' => 'Plugins', 'menu' => Text::_('COM_KUNENA_INSTALL_STEP_PLUGINS')], ['step' => 'Database', 'menu' => Text::_('COM_KUNENA_INSTALL_STEP_DATABASE')], ['step' => 'Finish', 'menu' => Text::_('COM_KUNENA_INSTALL_STEP_FINISH')], ['step' => '', 'menu' => Text::_('COM_KUNENA_INSTALL_STEP_COMPLETE')], ]; } /** * Initialise Kunena, run from Joomla installer. * * @return void * * @throws Exception * @since Kunena 6.0 */ public function install(): void { // Make sure that we are using the latest English language files $this->installLanguage('en-GB'); $this->setStep(0); } /** * @param string $tag tag * @param string $name name * * @return boolean * * @throws Exception * @since Kunena 6.0 */ public function installLanguage(string $tag, $name = ''): bool { $exists = false; $success = true; $destinations = [ 'site' => JPATH_SITE . '/components/com_kunena', 'admin' => JPATH_ADMINISTRATOR . '/components/com_kunena', ]; foreach ($destinations as $dest) { if ($success != true) { continue; } $installdir = "{$dest}/language/{$tag}"; // Install language from dest/language/xx-XX if (is_dir($installdir)) { $exists = $success; // Older versions installed language files into main folders // Those files need to be removed to bring language up to date! $files = Folder::files($installdir, '\.ini$'); foreach ($files as $filename) { if (is_file(JPATH_SITE . "/language/{$tag}/{$filename}")) { File::delete(JPATH_SITE . "/language/{$tag}/{$filename}"); } if (is_file(JPATH_ADMINISTRATOR . "/language/{$tag}/{$filename}")) { File::delete(JPATH_ADMINISTRATOR . "/language/{$tag}/{$filename}"); } } } } if ($exists && $name) { $this->addStatus(Text::sprintf('COM_KUNENA_INSTALL_LANGUAGE', $name), $success); } return $success; } /** * @param string $task task * @param bool $result result * @param string $msg message * @param null $id id * * @return void * * @throws Exception * @since Kunena 6.0 */ public function addStatus(string $task, $result = false, $msg = '', $id = null): void { $status = $this->getState('status'); $step = $this->getStep(); if ($id === null) { $status[] = ['step' => $step, 'task' => $task, 'success' => $result, 'msg' => $msg]; } else { unset($status[$id]); $status[$id] = ['step' => $step, 'task' => $task, 'success' => $result, 'msg' => $msg]; } $this->setState('status', $status); $app = Factory::getApplication(); $app->setUserState('com_kunena.install.status', $status); } /** * Overridden method to get model state variables. * * @param string $property Optional parameter name. * @param mixed $default The default value to use if no state property exists by name. * * @return object The property where specified, the state object where omitted. * * @throws Exception * @since 1.6 */ public function getState($property = null, $default = null): object { // If the model state is uninitialized lets set some values we will need from the request. if ($this->__state_set === false) { $app = Factory::getApplication(); $this->setState('action', $app->getUserState('com_kunena.install.action', null)); $this->setState('step', $step = $app->getUserState('com_kunena.install.step', 0)); $this->setState('task', $app->getUserState('com_kunena.install.task', 0)); $this->setState('version', $app->getUserState('com_kunena.install.version', null)); if ($step == 0) { $app->setUserState('com_kunena.install.status', []); } $this->setState('status', $app->getUserState('com_kunena.install.status')); $this->__state_set = true; } $value = parent::getState($property); return \is_null($value) ? $default : $value; } /** * @return object * * @throws Exception * @since Kunena 6.0 */ public function getStep(): object { return $this->getState('step', 0); } /** * @param string $step step * * @return void * * @throws Exception * @since Kunena 6.0 */ public function setStep(string $step): void { $this->setState('step', (int) $step); $app = Factory::getApplication(); $app->setUserState('com_kunena.install.step', (int) $step); $this->setTask(0); } /** * @param string $task task * * @return void * * @throws Exception * @since Kunena 6.0 */ public function setTask(string $task): void { $this->setState('task', (int) $task); $app = Factory::getApplication(); $app->setUserState('com_kunena.install.task', (int) $task); } /** * Uninstall Kunena, run from Joomla installer. * * @return boolean * * @throws Exception * @since Kunena 6.0 */ public function uninstall(): bool { // Put back file that was removed during installation. $contents = ''; File::write(KPATH_ADMIN . '/install.php', $contents); // Uninstall all plugins. $this->uninstallPlugin('kunena', 'community'); $this->uninstallPlugin('kunena', 'comprofiler'); $this->uninstallPlugin('kunena', 'easysocial'); $this->uninstallPlugin('kunena', 'gravatar'); $this->uninstallPlugin('kunena', 'joomla'); $this->uninstallPlugin('kunena', 'kunena'); $this->uninstallPlugin('kunena', 'finder'); $this->uninstallPlugin('sampleData', 'kunena'); $this->uninstallPlugin('finder', 'kunena'); $this->uninstallPlugin('quickicon', 'kunena'); $this->uninstallPlugin('content', 'kunena'); $this->uninstallPlugin('privacy', 'kunena'); // Uninstall menu module. $this->uninstallModule('mod_kunenamenu'); // Remove all Kunena related menu items, including aliases if (class_exists('KunenaMenuFix')) { $items = KunenaMenuFix::getAll(); foreach ($items as $item) { KunenaMenuFix::delete($item->id); } } $this->deleteMenu(); // Uninstall Kunena library $this->uninstallLibrary(); // Uninstall Kunena media $this->uninstallMedia(); // Uninstall Kunena system plugin $this->uninstallPlugin('system', 'kunena'); return true; } /** * @param string $folder folder * @param string $name name * * @return void * * @since Kunena 6.0 */ public function uninstallPlugin(string $folder, string $name): void { $db = Factory::getContainer()->get('DatabaseDriver'); $query = $db->createQuery(); $query->select('extension_id') ->from($db->quoteName('#__extensions')) ->where($db->quoteName('type') . ' =' . $db->quote('plugin') . ' AND ' . $db->quoteName('folder') . '=' . $db->quote($folder) . ' AND ' . $db->quoteName('element') . '=' . $db->quote($name)); $db->setQuery($query); $pluginid = $db->loadResult(); if ($pluginid) { $installer = new Installer(); $installer->setDatabase($db); $installer->uninstall('plugin', $pluginid); } } /** * @param string $name name * * @return void * * @since Kunena 6.0 */ public function uninstallModule(string $name): void { $db = Factory::getContainer()->get('DatabaseDriver'); $query = $db->createQuery(); $query->select('extension_id') ->from($db->quoteName('#__extensions')) ->where($db->quoteName('type') . '=' . $db->quote('module') . ' AND' . $db->quoteName('element') . '=' . $db->quote($name)); $db->setQuery($query); $moduleid = $db->loadResult(); if ($moduleid) { $installer = new Installer(); $installer->uninstall('module', $moduleid); } } /** * @return void * * @throws Exception * @since Kunena 6.0 */ public function deleteMenu(): void { $db = Factory::getContainer()->get(DatabaseInterface::class); $table = new MenuType($db); $table->load(['menutype' => 'kunenamenu']); if ($table->id) { try { $table->delete(); } catch (Exception $e) { Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); } } /** @var Cache|CacheController $cache */ $cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class)->createCacheController(); $cache->clean('mod_menu'); } /** * Method to uninstall the Kunena library during uninstall process * * @return void * * @since Kunena 6.0 */ public function uninstallLibrary(): void { $libraryid = $this->uninstallMediaLibraryQuery('library', 'kunena'); if ($libraryid) { $installer = new Installer(); $installer->uninstall('library', $libraryid); } } /** * Method to uninstall the Kunena media during uninstall process * * @param string $type type * @param string $element Name of the package or of the component * * @return integer * * @since Kunena 6.0 */ private function uninstallMediaLibraryQuery(string $type, string $element): int { $query = $this->db->createQuery(); $query->select($this->db->quoteName('extension_id')); $query->from($this->db->quoteName('#__extensions')); $query->where($this->db->quoteName('type') . ' = ' . $this->db->quote($type)); $query->where($this->db->quoteName('element') . ' = ' . $this->db->quote($element)); $this->db->setQuery($query); return $this->db->loadResult(); } /** * Method to uninstall the Kunena media during uninstall process * * @return void * * @since Kunena 6.0 */ public function uninstallMedia(): void { $mediaid = $this->uninstallMediaLibraryQuery('file', 'kunena_media'); if ($mediaid) { $installer = new Installer(); $installer->uninstall('file', $mediaid); } } /** * Get model * * @return $this * @since Kunena 6.0 */ public function getModel(): KunenaModelInstall { return $this; } /** * Get Status * * @return object * * @throws Exception * @since Kunena 6.0 */ public function getStatus(): object { return $this->getState('status', []); } /** * @return array|null * * @since Kunena 6.0 */ public function getSteps(): ?array { return $this->steps; } // TODO: move to migration (exists in 2.0) /** * @param string $path path * @param string $name name * * @return bool|null * * @since Kunena 6.0 * @throws \Exception */ public function installModule(string $path, string $name): ?bool { $success = false; $dest = KunenaPath::tmpdir() . "/kinstall_mod_{$name}"; if (is_dir($dest)) { Folder::delete($dest); } if (is_dir(KUNENA_INSTALLER_ADMINPATH . '/' . $path)) { // Copy path $success = Folder::copy(KUNENA_INSTALLER_ADMINPATH . '/' . $path, $dest); } elseif (is_file(KUNENA_INSTALLER_ADMINPATH . '/' . $path)) { // Extract file $success = $this->extract(KUNENA_INSTALLER_ADMINPATH, $path, $dest); } if ($success) { $success = Folder::create($dest . '/language/en-GB'); } if ($success && is_file(KUNENA_INSTALLER_SITEPATH . "/language/en-GB/en-GB.mod_{$name}.ini")) { $success = File::copy(KUNENA_INSTALLER_SITEPATH . "/language/en-GB/en-GB.mod_{$name}.ini", "{$dest}/language/en-GB/en-GB.mod_{$name}.ini"); } if ($success && is_file(KUNENA_INSTALLER_SITEPATH . "/language/en-GB/en-GB.mod_{$name}.sys.ini")) { $success = File::copy(KUNENA_INSTALLER_SITEPATH . "/language/en-GB/en-GB.mod_{$name}.sys.ini", "{$dest}/language/en-GB/en-GB.mod_{$name}.sys.ini"); } // Only install module if it can be used in current Joomla version (manifest exists) if ($success && is_file("{$dest}/mod_{$name}.xml")) { $installer = new Installer(); $success = $installer->install($dest); $this->addStatus(Text::sprintf('COM_KUNENA_INSTALL_MODULE_STATUS', ucfirst($name)), $success); } elseif (!$success) { $this->addStatus(Text::sprintf('COM_KUNENA_INSTALL_MODULE_STATUS', ucfirst($name)), $success); } Folder::delete($dest); return $success; } /** * @param string $path path * @param string $filename filename * @param null $dest dest * @param bool $silent silent * * @return bool|null * * @throws \Exception * @since Kunena 6.0 */ public function extract(string $path, string $filename, $dest = null, bool $silent = false): ?bool { $success = null; if (!$dest) { $dest = $path; } $file = "{$path}/{$filename}"; $text = ''; if (is_file($file)) { $success = true; if (!is_dir($dest)) { $success = Folder::create($dest); } if ($success) { $archive = new Archive(); $success = $archive->extract($file, $dest); } if (!$success) { $text .= Text::sprintf('COM_KUNENA_INSTALL_EXTRACT_FAILED', $file); } } else { $success = true; $text .= Text::sprintf('COM_KUNENA_INSTALL_EXTRACT_MISSING', $file); } if ($success !== null && !$silent) { $this->addStatus(Text::sprintf('COM_KUNENA_INSTALL_EXTRACT_STATUS', $filename), $success, $text); } return $success; } /** * @param string $path path * @param string $group group * @param string $name name * @param boolean $publish publish * @param integer $ordering ordering * * @return boolean|null * * @throws Exception * @since Kunena 6.0 */ public function installPlugin(string $path, string $group, string $name, bool $publish, $ordering = 0): ?bool { $success = false; $dest = KunenaPath::tmpdir() . "/kinstall_plg_{$group}_{$name}"; if (is_dir($dest)) { Folder::delete($dest); } if (is_dir(KUNENA_INSTALLER_PATH . '/' . $path)) { // Copy path $success = Folder::copy(KUNENA_INSTALLER_PATH . '/' . $path, $dest); } elseif (is_file(KUNENA_INSTALLER_PATH . '/' . $path)) { // Extract file $success = $this->extract(KUNENA_INSTALLER_PATH, $path, $dest); } if ($success) { $success = Folder::create($dest . '/language/en-GB'); } if ($success && is_file(KUNENA_INSTALLER_ADMINPATH . "/language/en-GB/en-GB.plg_{$group}_{$name}.ini")) { $success = File::copy(KUNENA_INSTALLER_ADMINPATH . "/language/en-GB/en-GB.plg_{$group}_{$name}.ini", "{$dest}/language/en-GB/en-GB.plg_{$group}_{$name}.ini"); } if ($success && is_file(KUNENA_INSTALLER_ADMINPATH . "/language/en-GB/en-GB.plg_{$group}_{$name}.sys.ini")) { $success = File::copy(KUNENA_INSTALLER_ADMINPATH . "/language/en-GB/en-GB.plg_{$group}_{$name}.sys.ini", "{$dest}/language/en-GB/en-GB.plg_{$group}_{$name}.sys.ini"); } // Only install plugin if it can be used in current Joomla version (manifest exists) if ($success && is_file("{$dest}/{$name}.xml")) { $installer = new Installer(); $success = $installer->install($dest); if ($success) { // First change plugin ordering $plugin = $this->loadPlugin((array) $group, $name); if ($ordering && !$plugin->ordering) { $plugin->ordering = $ordering; } if ($publish) { $plugin->enabled = $publish; } $success = $plugin->store(); } $this->addStatus(Text::sprintf('COM_KUNENA_INSTALL_PLUGIN_STATUS', ucfirst($group) . ' - ' . ucfirst($name)), $success); } elseif (!$success) { $this->addStatus(Text::sprintf('COM_KUNENA_INSTALL_PLUGIN_STATUS', ucfirst($group) . ' - ' . ucfirst($name)), $success); } Folder::delete($dest); return $success; } /** * @param array $group group * @param string $element element * * @return boolean|\Joomla\CMS\Table\Table * * @since Kunena 6.0 */ public function loadPlugin(array $group, string $element) { $db = Factory::getContainer()->get(DatabaseInterface::class); $plugin = new Extension($db); $plugin->load(['type' => 'plugin', 'folder' => $group, 'element' => $element]); return $plugin; } /** * @return void * * @throws KunenaInstallerException * @throws KunenaSchemaException * @throws Exception * @since Kunena 6.0 */ public function stepPrepare(): void { $results = []; $this->setVersion(0); $this->setAvatarStatus(); $this->setAttachmentStatus(); $this->addStatus(Text::_('COM_KUNENA_INSTALL_STEP_PREPARE'), true); $cache = Cache::getInstance(); $cache->clean('kunena'); $action = $this->getAction(); if ($action == 'install' || $action == 'migrate') { // Let's start from clean database $this->deleteTables('kunena_'); $this->deleteMenu(); } $installed = $this->getDetectVersions(); if ($action == 'migrate' && $installed['fb']->component) { $version = $installed['fb']; $results[] = $this->migrateTable($version->prefix, $version->prefix . 'version', 'kunena_version'); } else { $version = $installed['kunena']; } $this->setVersion($version); // Always enable the System - Kunena plugin $query = $this->db->createQuery(); $query->clear() ->update($this->db->quoteName('#__extensions')) ->set($this->db->quoteName('enabled') . ' = 1') ->where($this->db->quoteName('type') . ' = ' . $this->db->quote('plugin')) ->where($this->db->quoteName('folder') . ' = ' . $this->db->quote('system')) ->where($this->db->quoteName('element') . ' = ' . $this->db->quote('kunena')); $this->db->setQuery($query); $this->db->execute(); $schema = new KunenaModelSchema(); $results[] = $schema->updateSchemaTable('kunena_version'); // Insert data from the old version, if it does not exist in the version table if ($version->id == 0 && $version->component) { $this->insertVersionData($version->version, $version->versiondate, $version->versionname, null); } /* foreach ( $results as $result ) if (!empty($result['action']) && empty($result['success'])) $this->addStatus ( Text::_('COM_KUNENA_INSTALL_'.strtoupper($result['action'])) . ' ' . $result ['name'], $result ['success'] ); */ $this->insertVersion('migrateDatabase'); if (!$this->getInstallError()) { $this->setStep($this->getStep() + 1); } $this->checkTimeout(true); } /** * @param integer $version version * * @return void * * @throws Exception * @since Kunena 6.0 */ public function setVersion(int $version): void { $this->setState('version', $version); $app = Factory::getApplication(); $app->setUserState('com_kunena.install.version', $version); } /** * @param null $stats stats * * @return void * * @throws Exception * @since Kunena 6.0 */ protected function setAvatarStatus($stats = null): void { if (!$stats) { $stats = new stdClass(); $stats->current = $stats->migrated = $stats->failed = $stats->missing = 0; } $app = Factory::getApplication(); $app->setUserState('com_kunena.install.avatars', $stats); } /** * @param null $stats stats * * @return void * * @throws Exception * @since Kunena 6.0 */ protected function setAttachmentStatus($stats = null): void { if (!$stats) { $stats = new stdClass(); $stats->current = $stats->migrated = $stats->failed = $stats->missing = 0; } $app = Factory::getApplication(); $app->setUserState('com_kunena.install.attachments', $stats); } /** * Get Action * * @return object * * @throws Exception * @since Kunena 6.0 */ public function getAction(): object { return $this->getState('action', null); } /** * Set Action * * @param string $action action * * @return void * * @throws Exception * @since Kunena 6.0 */ public function setAction(string $action): void { $this->setState('action', $action); $app = Factory::getApplication(); $app->setUserState('com_kunena.install.action', $action); } /** * @param string $prefix prefix * * @return void * @throws KunenaInstallerException * @since Kunena 6.0 */ public function deleteTables(string $prefix): void { $tables = $this->listTables($prefix); foreach ($tables as $table) { $this->db->setQuery("DROP TABLE IF EXISTS " . $this->db->quoteName($this->db->getPrefix() . $table)); try { $this->db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } } unset($this->tables[$prefix]); } /** * @param string $prefix prefix * * @return void * @throws KunenaInstallerException * @since Kunena 6.0 */ public function cleanMailTemplates() { $query = $this->db->createQuery(); $conditions = array( $this->db->quoteName('template_id') . ' = ' . $this->db->quote('com_kunena.reply'), ); $query->delete($this->db->quoteName('#__mail_templates')); $query->where($conditions); $this->db->setQuery($query); try { $this->db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } $query = $this->db->createQuery(); $conditions = array( $this->db->quoteName('template_id') . ' = ' . $this->db->quote('com_kunena.replymoderator'), ); $query->delete($this->db->quoteName('#__mail_templates')); $query->where($conditions); $this->db->setQuery($query); try { $this->db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } $query = $this->db->createQuery(); $conditions = array( $this->db->quoteName('template_id') . ' = ' . $this->db->quote('com_kunena.report'), ); $query->delete($this->db->quoteName('#__mail_templates')); $query->where($conditions); $this->db->setQuery($query); try { $this->db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } } /** * @param string $prefix prefix * @param bool $reload reload * * @return mixed * * @throws KunenaInstallerException * @since Kunena 6.0 */ protected function listTables(string $prefix, $reload = false): array { if (isset($this->tables[$prefix]) && !$reload) { return $this->tables[$prefix]; } $this->db->setQuery("SHOW TABLES LIKE " . $this->db->quote($this->db->getPrefix() . $prefix . '%')); try { $list = (array) $this->db->loadColumn(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } $this->tables[$prefix] = []; foreach ($list as $table) { $table = preg_replace('/^' . $this->db->getPrefix() . '/', '', $table); $this->tables[$prefix][$table] = $table; } return $this->tables[$prefix]; } /** * @return array * * @throws KunenaInstallerException * @since Kunena 6.0 */ public function getDetectVersions(): array { if (!empty($this->_versions)) { return $this->_versions; } $kunena = $this->getInstalledVersion('kunena_', $this->_kVersions); $fireboard = $this->getInstalledVersion('fb_', $this->_fbVersions); if (!empty($kunena->state)) { $this->_versions['failed'] = $kunena; $kunena = $this->getInstalledVersion('kunena_', $this->_kVersions, true); if (version_compare($kunena->version, '1.6.0-ALPHA', "<")) { $kunena->ignore = true; } } if ($kunena->component && empty($kunena->ignore)) { $this->_versions['kunena'] = $kunena; $migrate = false; } else { $migrate = $this->isMigration($kunena, $fireboard); } if (!empty($fireboard->component) && $migrate) { $this->_versions['fb'] = $fireboard; } if (empty($kunena->component)) { $this->_versions['kunena'] = $kunena; } else { if (!empty($fireboard->component)) { $uninstall = clone $fireboard; $uninstall->action = 'RESTORE'; $this->_versions['uninstall'] = $uninstall; } else { $uninstall = clone $kunena; $uninstall->action = 'UNINSTALL'; $this->_versions['uninstall'] = $uninstall; } } foreach ($this->_versions as $version) { $version->label = $this->getActionText($version); $version->description = $this->getActionText($version, 'desc'); $version->hint = $this->getActionText($version, 'hint'); $version->warning = $this->getActionText($version, 'warn'); $version->link = Uri::base(true) . '/index.php?option=com_kunena&view=install&task=' . strtolower($version->action) . '&' . Session::getFormToken() . '=1'; } if ($migrate) { $kunena->warning = $this->getActionText((string) $fireboard, 'warn', 'upgrade'); } else { $kunena->warning = ''; } return $this->_versions; } /** * @param string $prefix prefix * @param array $versionlist versionlist * @param boolean $state state * * @return \stdClass|null * * @throws \Kunena\Forum\Libraries\Install\KunenaInstallerException * @since Kunena 6.0 */ public function getInstalledVersion(string $prefix, array $versionlist, $state = false): ?stdClass { if (!$state && isset($this->_installed[$prefix])) { return $this->_installed[$prefix]; } if ($prefix === null) { $versionprefix = $this->getVersionPrefix(); } else { $test = [$prefix . 'version']; if ($this->detectTable($test)) { $versionprefix = $prefix; } else { $versionprefix = null; } } if ($versionprefix) { // Version table exists, try to get installed version $state = $state ? " WHERE state=''" : ""; $this->db->setQuery("SELECT * FROM " . $this->db->quoteName($this->db->getPrefix() . $versionprefix . 'version') . $state . " ORDER BY `id` DESC", 0, 1); try { $version = $this->db->loadObject(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } if ($version) { $version->version = strtolower($version->version); $version->prefix = $versionprefix; if (version_compare($version->version, '1.0.5', ">")) { $version->component = 'Kunena'; } else { $version->component = 'FireBoard'; } $version->version = strtoupper($version->version); // Version table may contain dummy version.. Ignore it if (!$version || version_compare($version->version, '0.1.0', "<")) { unset($version); } } } if (!isset($version)) { // No version found -- try to detect version by searching some missing fields $match = $this->detectTable($versionlist); // Clean install if (empty($match)) { return $this->_installed = null; } // Create version object $version = new stdClass(); $version->id = 0; $version->component = $match['component']; $version->version = strtoupper($match['version']); $version->versiondate = $match['date']; $version->installdate = ''; $version->versionname = ''; $version->prefix = $match['prefix']; } $version->action = $this->getInstallAction($version); return $this->_installed[$prefix] = $version; } /** * @return boolean * * @throws KunenaInstallerException * @since Kunena 6.0 */ public function getVersionPrefix() { if ($this->_versionprefix !== false) { return $this->_versionprefix; } $match = $this->detectTable($this->_versiontablearray); if (isset($match['prefix'])) { $this->_versionprefix = $match['prefix']; } else { $this->_versionprefix = null; } return $this->_versionprefix; } /** * @param array $detectlist detect list * * @return array * * @throws KunenaInstallerException * @since Kunena 6.0 */ protected function detectTable(array $detectlist) { // Cache static $tables = []; static $fields = []; $found = 0; if (\is_string($detectlist)) { $detectlist = [['table' => $detectlist]]; } foreach ($detectlist as $detect) { // If no detection is needed, return current item if (!isset($detect['table'])) { return $detect; } $table = $this->db->getPrefix() . $detect['table']; // Match if table exists if (!isset($tables[$table])) { // Not cached $this->db->setQuery("SHOW TABLES LIKE " . $this->db->quote($table)); try { $result = $this->db->loadResult(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } $tables[$table] = $result; } if (!empty($tables[$table])) { $found = 1; } // Match if column in a table exists if ($found && isset($detect['column'])) { if (!isset($fields[$table])) { // Not cached $this->db->setQuery("SHOW COLUMNS FROM " . $this->db->quoteName($table)); try { $result = $this->db->loadObjectList('Field'); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } $fields[$table] = $result; } if (!isset($fields[$table][$detect['column']])) { $found = 0; } } if ($found) { return $detect; } } return []; } /** * @param object $version version * * @return boolean|string * * @since Kunena 6.0 */ public function getInstallAction($version = null) { if ($version->component === null) { $this->_action = 'INSTALL'; } else { if ($version->prefix != 'kunena_') { $this->_action = 'MIGRATE'; } else { if (version_compare(strtolower(KunenaForum::version()), strtolower($version->version), '>')) { $this->_action = 'UPGRADE'; } else { if (version_compare(strtolower(KunenaForum::version()), strtolower($version->version), '<')) { $this->_action = 'DOWNGRADE'; } else { $this->_action = 'REINSTALL'; } } } } return $this->_action; } /** * @param object $new new * @param object $old new * * @return boolean * * @throws KunenaInstallerException * @since Kunena 6.0 */ public function isMigration(object $new, object $old): bool { // If K1.6 not installed: migrate if (!$new->component || !$this->detectTable([$new->prefix . 'messages'])) { return true; } // If old not installed: upgrade if (!$old->component || !$this->detectTable([$old->prefix . 'messages'])) { return false; } // If K1.6 is installed and old is not Kunena: upgrade if ($old->component != 'Kunena') { return false; } // User is currently using K1.6: upgrade if (strtotime($new->installdate) > strtotime($old->installdate)) { return false; } // User is currently using K1.0/K1.5: migrate if (strtotime($new->installdate) < strtotime($old->installdate)) { return true; } // Both K1.5 and K1.6 were installed during the same day.. Not going to be easy choice.. // Let's assume that this could be migration return true; } // TODO: move to migration /** * @param object $version version * @param string $type type * @param null $action action * * @return string * * @since Kunena 6.0 */ public function getActionText(object $version, $type = '', $action = null): string { /* Translations generated: Installation types: COM_KUNENA_INSTALL_UPGRADE, COM_KUNENA_INSTALL_DOWNGRADE, COM_KUNENA_INSTALL_REINSTALL, COM_KUNENA_INSTALL_MIGRATE, COM_KUNENA_INSTALL_INSTALL, COM_KUNENA_INSTALL_UNINSTALL, COM_KUNENA_INSTALL_RESTORE Installation descriptions: COM_KUNENA_INSTALL_UPGRADE_DESC, COM_KUNENA_INSTALL_DOWNGRADE_DESC, COM_KUNENA_INSTALL_REINSTALL_DESC, COM_KUNENA_INSTALL_MIGRATE_DESC, COM_KUNENA_INSTALL_INSTALL_DESC, COM_KUNENA_INSTALL_UNINSTALL_DESC, COM_KUNENA_INSTALL_RESTORE_DESC Installation hints: COM_KUNENA_INSTALL_UPGRADE_HINT, COM_KUNENA_INSTALL_DOWNGRADE_HINT, COM_KUNENA_INSTALL_REINSTALL_HINT, COM_KUNENA_INSTALL_MIGRATE_HINT, COM_KUNENA_INSTALL_INSTALL_HINT, COM_KUNENA_INSTALL_UNINSTALL_HINT, COM_KUNENA_INSTALL_RESTORE_HINT Installation warnings: COM_KUNENA_INSTALL_UPGRADE_WARN, COM_KUNENA_INSTALL_DOWNGRADE_WARN, COM_KUNENA_INSTALL_MIGRATE_WARN, COM_KUNENA_INSTALL_UNINSTALL_WARN, COM_KUNENA_INSTALL_RESTORE_WARN */ static $search = ['#COMPONENT_OLD#', '#VERSION_OLD#', '#VERSION#']; $replace = [$version->component, $version->version, KunenaForum::version()]; if (!$action) { $action = $version->action; } if ($type == 'warn' && ($action == 'INSTALL' || $action == 'REINSTALL')) { return ''; } $str = ''; if ($type == 'hint' || $type == 'warn') { $str .= '<strong class="k' . $type . '">' . Text::_('COM_KUNENA_INSTALL_' . $type) . '</strong> '; } if ($action && $type) { $type = '_' . $type; } $str .= str_replace($search, $replace, Text::_('COM_KUNENA_INSTALL_' . $action . $type)); return $str; } /** * @param string $oldprefix old prefix * @param string $oldtable old table * @param string $newtable newtable * * @return array * * @throws \Kunena\Forum\Libraries\Install\KunenaInstallerException * @since Kunena 6.0 */ protected function migrateTable(string $oldprefix, string $oldtable, string $newtable): array { $tables = $this->listTables('kunena_'); $oldtables = $this->listTables($oldprefix); if ($oldtable == $newtable || !isset($oldtables[$oldtable]) || isset($tables[$newtable])) { return false; } // Make identical copy from the table with new name $create = $this->db->getTableCreate($this->db->getPrefix() . $oldtable); $create = implode(' ', $create); $collation = $this->db->getCollation(); if (!strstr($collation, 'utf8') && !strstr($collation, 'utf8mb4')) { $collation = 'utf8_general_ci'; } if (strstr($collation, 'utf8mb4')) { $str = 'utf8mb4'; } else { $str = 'utf8'; } if (!$create) { return false; } $create = preg_replace('/(DEFAULT )?CHARACTER SET [\w\d]+/', '', $create); $create = preg_replace('/(DEFAULT )?CHARSET=[\w\d]+/', '', $create); if (strstr($collation, 'utf8mb4')) { $create .= ' ENGINE=InnoDB'; } else { $create = preg_replace('/TYPE\s*=?/', 'ENGINE=', $create); } $create .= " DEFAULT CHARACTER SET {$str} COLLATE {$collation}"; $query = preg_replace('/' . $this->db->getPrefix() . $oldtable . '/', $this->db->getPrefix() . $newtable, $create); $this->db->setQuery($query); try { $this->db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } $this->tables['kunena_'][$newtable] = $newtable; // And copy data into it $sql = $this->db->createQuery(); $sql->insert($this->db->quoteName($this->db->getPrefix() . $newtable) . ' ' . $this->selectWithStripslashes($this->db->getPrefix() . $oldtable)); $this->db->setQuery($sql); try { $this->db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } return ['name' => $oldtable, 'action' => 'migrate', 'sql' => $sql]; } // TODO: move to migration /** * @param string $table table * * @return string * * @since Kunena 6.0 */ public function selectWithStripslashes(string $table): string { $fields = $this->db->getTableColumns($table); $select = []; foreach ($fields as $field => $type) { $isString = preg_match('/text|char/', $type); $select[] = ($isString ? "REPLACE(REPLACE(REPLACE({$this->db->quoteName($field)}, {$this->db->Quote('\\\\')}, {$this->db->Quote('\\')}),{$this->db->Quote('\\\'')} ,{$this->db->Quote('\'')}),{$this->db->Quote('\"')} ,{$this->db->Quote('"')}) AS " : '') . $this->db->quoteName($field); } $select = implode(', ', $select); return "SELECT {$select} FROM {$table}"; } /** * @param integer $version version * @param integer $versiondate version date * @param integer $versionname version name * @param string $state state * * @return void * * @throws KunenaInstallerException * @since Kunena 6.0 */ protected function insertVersionData(int $version, int $versiondate, int $versionname, $state = ''): void { $query = $this->db->createQuery(); // Insert columns. $columns = ['version', 'versiondate', 'installdate', 'versionname', 'build', 'state']; // Insert values. $values = [$this->db->quote($version), $this->db->quote($versiondate), $this->db->quote(Factory::getDate('now')->toSql()), $this->db->quote($versionname), $this->db->quote($version), $this->db->quote($state)]; // Prepare the insert query. $query ->insert($this->db->quoteName($this->db->getPrefix() . 'kunena_version')) ->columns($this->db->quoteName($columns)) ->values(implode(',', $values)); // Set the query using our newly populated query object and execute it. $this->db->setQuery($query); try { $this->db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } } /** * @param string $state state * * @return void * * @throws KunenaInstallerException * @since Kunena 6.0 */ protected function insertVersion($state = 'beginInstall'): void { // Insert data from the new version $this->insertVersionData(KunenaForum::version(), KunenaForum::versionDate(), KunenaForum::versionName(), $state); } /** * @return boolean * * @throws Exception * @since Kunena 6.0 */ public function getInstallError() { $status = $this->getState('status', []); foreach ($status as $cur) { $error = !$cur['success']; if ($error) { return $cur['task'] . ' ... ' . ($cur['success'] > 0 ? 'SUCCESS' : 'FAILED'); } } return false; } // TODO: move to migration /** * @param bool $stop stop * @param int $timeout timeout * * @return boolean * * @since Kunena 6.0 */ public function checkTimeout($stop = false, $timeout = 1): bool { static $start = null; if ($stop) { $start = 0; } $time = microtime(true); if ($start === null) { $start = $time; return false; } if ($time - $start < $timeout) { return false; } return true; } // TODO: move to migration /** * @return void * * @throws Exception * @since Kunena 6.0 */ public function stepExtract(): void { $path = JPATH_ADMINISTRATOR . '/components/com_kunena/archive'; if (KunenaForum::isDev() || !is_file("{$path}/fileformat")) { // Git install $dir = JPATH_ADMINISTRATOR . '/components/com_kunena/media/kunena'; if (is_dir($dir)) { Folder::copy($dir, KUNENA_INSTALLER_MEDIAPATH, false, true); } $this->setStep($this->getStep() + 1); return; } $ext = file_get_contents("{$path}/fileformat"); static $files = [ ['name' => 'com_kunena-admin', 'dest' => KUNENA_INSTALLER_ADMINPATH], ['name' => 'com_kunena-site', 'dest' => KUNENA_INSTALLER_SITEPATH], ['name' => 'com_kunena-media', 'dest' => KUNENA_INSTALLER_MEDIAPATH], ]; static $ignore = [ KUNENA_INSTALLER_ADMINPATH => ['index.html', 'kunena.xml', 'kunena.j25.xml', 'kunena.php', 'api.php', 'archive', 'install', 'language'], KUNENA_INSTALLER_SITEPATH => ['index.html', 'kunena.php', 'router.php', 'COPYRIGHT.php', 'template', 'language'], ]; $task = $this->getTask(); // Extract archive files if (isset($files[$task])) { $file = $files[$task]; if (is_file("{$path}/{$file['name']}{$ext}")) { $dest = $file['dest']; if (!empty($ignore[$dest])) { // Delete all files and folders (cleanup) $this->deleteFolder($dest, $ignore[$dest]); if ($dest == KUNENA_INSTALLER_SITEPATH) { $this->deleteFolder("$dest/template/aurelia", ['params.ini']); } } // Copy new files into folder $this->extract($path, $file['name'] . $ext, $dest, KunenaForum::isDev()); } $this->setTask($task + 1); } else { if (\function_exists('apc_clear_cache')) { @apc_clear_cache('system'); } // Force page reload to avoid MySQL timeouts after extracting $this->checkTimeout(true); if (!$this->getInstallError()) { $this->setStep($this->getStep() + 1); } } } // TODO: move to migration /** * @return object * * @throws Exception * @since Kunena 6.0 */ public function getTask(): object { return $this->getState('task', 0); } // TODO: move to migration /** * @param string $path path * @param array $ignore ignore * * @return void * * @since Kunena 6.0 */ public function deleteFolder(string $path, $ignore = []): void { $this->deleteFiles($path, $ignore); $this->deleteFolders($path, $ignore); } // TODO: move to migration /** * @param string $path path * @param array $ignore ignore * * @return void * * @since Kunena 6.0 */ public function deleteFiles(string $path, $ignore = []): void { $ignore = array_merge($ignore, ['.git', '.svn', 'CVS', '.DS_Store', '__MACOSX']); if (is_dir($path)) { foreach (Folder::files($path, '.', false, true, $ignore) as $file) { if (is_file($file)) { File::delete($file); } } } } // TODO: move to migration /** * @param string $path path * @param array $ignore ignore * * @return void * * @since Kunena 6.0 */ public function deleteFolders(string $path, $ignore = []): void { $ignore = array_merge($ignore, ['.git', '.svn', 'CVS', '.DS_Store', '__MACOSX']); if (is_dir($path)) { foreach (Folder::folders($path, '.', false, true, $ignore) as $folder) { if (is_dir($folder)) { Folder::delete($folder); } } } } // TODO: move to migration /** * @return void * * @throws Exception * @since Kunena 6.0 */ public function stepPlugins(): void { $this->enablePlugin('kunena', 'kunena'); $this->enablePlugin('kunena', 'joomla'); if (is_file(JPATH_ROOT . '/plugins/kunena/alphauserpoints/avatar.php')) { $this->uninstallPlugin('kunena', 'alphauserpoints'); } if (\function_exists('apc_clear_cache')) { @apc_clear_cache('system'); } if (!$this->getInstallError()) { $this->setStep($this->getStep() + 1); } } // TODO: move to migration /** * @param string $group group * @param string $element element * * @return boolean * * @since Kunena 6.0 */ public function enablePlugin(string $group, string $element): bool { $db = Factory::getContainer()->get(DatabaseInterface::class); $plugin = new Extension($db); if (!$plugin->load(['type' => 'plugin', 'folder' => $group, 'element' => $element])) { return false; } $plugin->enabled = 1; return $plugin->store(); } /** * @return void * * @throws KunenaInstallerException * @throws KunenaSchemaException * @throws Exception * @since Kunena 6.0 */ public function stepDatabase(): void { $task = $this->getTask(); switch ($task) { case 0: if ($this->migrateDatabase()) { $this->setTask($task + 1); } break; case 1: if ($this->installDatabase()) { $this->setTask($task + 1); } break; case 2: if ($this->upgradeDatabase()) { $this->setTask($task + 1); } break; case 3: if ($this->installSampleData()) { $this->setTask($task + 1); } break; case 4: if ($this->migrateCategoryImages()) { $this->setTask($task + 1); } break; case 5: if ($this->migrateAvatars()) { $this->setTask($task + 1); } break; case 6: if ($this->migrateAvatarGalleries()) { $this->setTask($task + 1); } break; case 7: if ($this->migrateAttachments()) { $this->setTask($task + 1); } break; default: if (!$this->getInstallError()) { $this->setStep($this->getStep() + 1); } } } /** * @return boolean * * @throws KunenaInstallerException * @throws Exception * @since Kunena 6.0 */ public function migrateDatabase(): bool { $version = $this->getVersion(); if (!empty($version->prefix)) { // Migrate all tables from old installation $app = Factory::getApplication(); $state = $app->getUserState('com_kunena.install.dbstate', null); // First run: find tables that potentially need migration if ($state === null) { $state = $this->listTables($version->prefix); } // Handle only first table in the list $oldtable = array_shift($state); if ($oldtable) { $newtable = preg_replace('/^' . $version->prefix . '/i', 'kunena_', $oldtable); $result = $this->migrateTable($version->prefix, $oldtable, $newtable); if ($result) { $this->addStatus(ucfirst($result['action']) . ' ' . $result['name'], true); } // Save user state with remaining tables $app->setUserState('com_kunena.install.dbstate', $state); // Database migration continues return false; } else { // Reset user state $this->updateVersionState('installDatabase'); $app->setUserState('com_kunena.install.dbstate', null); } } // Database migration complete return true; } // TODO: move to migration /** * Get version * * @return object * * @throws Exception * @since Kunena 6.0 */ public function getVersion(): object { return $this->getState('version', null); } /** * @param string $state state * * @return void * * @throws KunenaInstallerException * @since Kunena 6.0 */ protected function updateVersionState(string $state): void { // Insert data from the new version $this->db->setQuery("UPDATE " . $this->db->quoteName($this->db->getPrefix() . 'kunena_version') . " SET state = " . $this->db->Quote($state) . " ORDER BY id DESC LIMIT 1"); try { $this->db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } } // TODO: move to migration /** * @return boolean * * @throws KunenaInstallerException * @throws KunenaSchemaException * @throws Exception * @since Kunena 6.0 */ public function installDatabase(): bool { static $schema = null; static $create = null; static $tables = null; if ($schema === null) { // Run only once: get table creation SQL and existing tables $schema = new KunenaModelSchema(); $create = $schema->getCreateSQL(); $tables = $this->listTables('kunena_', true); } $app = Factory::getApplication(); $state = $app->getUserState('com_kunena.install.dbstate', null); // First run: get all tables if ($state === null) { $state = array_keys($create); } // Handle only first table in the list $table = array_shift($state); if ($table) { if (!isset($tables[$table])) { $result = $schema->updateSchemaTable($table); if ($result) { $this->addStatus(Text::_('COM_KUNENA_INSTALL_CREATE') . ' ' . $result['name'], $result['success']); } } // Save user state with remaining tables $app->setUserState('com_kunena.install.dbstate', $state); // Database install continues return false; } else { // Reset user state $this->updateVersionState('upgradeDatabase'); $app->setUserState('com_kunena.install.dbstate', null); } // Database install complete return true; } /** * @return boolean * * @throws KunenaInstallerException * @throws Exception * @since Kunena 6.0 */ public function upgradeDatabase(): bool { static $xml = null; // If there's no version installed, there's nothing to do $curversion = $this->getVersion(); if (!$curversion->component) { return true; } if ($xml === null) { // Run only once: Get migration SQL from our XML file $xml = simplexml_load_file(KUNENA_INSTALLER_PATH . '/kunena.install.upgrade.xml'); } if ($xml === false) { $this->addStatus(Text::_('COM_KUNENA_INSTALL_DB_UPGRADE_FAILED_XML'), false, '', 'upgrade'); } $app = Factory::getApplication(); $state = $app->getUserState('com_kunena.install.dbstate', null); // First run: initialize state and migrate configuration if ($state === null) { $state = []; // Migrate configuration from FB <1.0.5, otherwise update it $this->migrateConfig(); } // Allow queries to fail // $this->db->setDebug(false); foreach ($xml->upgrade[0] as $version) { // If we have already upgraded to this version, continue to the next one $vernum = (string) $version['version']; if (!empty($state[$vernum])) { continue; } // Update state $state[$vernum] = 1; if ($version['version'] == '@' . 'kunenaversion' . '@') { $git = 1; $vernum = KunenaForum::version(); } if (isset($git) || version_compare(strtolower($version['version']), strtolower($curversion->version), '>')) { foreach ($version as $action) { $result = $this->processUpgradeXMLNode($action); if ($result) { $this->addStatus($result['action'] . ' ' . $result['name'], $result['success']); } } $this->addStatus(Text::sprintf('COM_KUNENA_INSTALL_VERSION_UPGRADED', $vernum), true, '', 'upgrade'); // Save user state with remaining tables $app->setUserState('com_kunena.install.dbstate', $state); // Database install continues return false; } } // Reset user state $this->updateVersionState('InstallSampleData'); $app->setUserState('com_kunena.install.dbstate', null); // Database install complete return true; } /** * @return void * * @throws KunenaInstallerException * @throws Exception * @since Kunena 6.0 */ public function migrateConfig(): void { $config = KunenaFactory::getConfig(); $version = $this->getVersion(); // Migrate configuration from FB < 1.0.5 if (version_compare($version->version, '1.0.4', "<=")) { $file = JPATH_ADMINISTRATOR . '/components/com_fireboard/fireboard_config.php'; if (is_file($file)) { require_once $file; if (isset($fbConfig)) { $fbConfig = (array) $fbConfig; $config->bind($fbConfig); $config->id = 1; } } } // Migrate configuration from FB 1.0.5 and Kunena 1.0-1.7 if (!$config->id && !empty($version->prefix)) { $tables = $this->listTables($version->prefix); $cfgtable = "{$version->prefix}config"; if (isset($tables[$cfgtable])) { $this->db->setQuery("SELECT * FROM #__{$cfgtable}"); $config->bind((array) $this->db->loadAssoc()); $config->id = 1; } } $config->save(); } /** * @param object $action action * * @return array|null * * @since Kunena 6.0 */ public function processUpgradeXMLNode(object $action): ?array { $result = null; $nodeName = $action->getName(); $mode = strtolower((string) $action['mode']); $success = false; switch ($nodeName) { case 'phpfile': $filename = $action['name']; $include = JPATH_ADMINISTRATOR . "/components/com_kunena/install/sql/updates/php/{$filename}.php"; $function = 'kunena_' . strtr($filename, ['.' => '', '-' => '_']); if (is_file($include)) { require $include; if (\is_callable($function)) { $result = \call_user_func($function, $this); if (\is_array($result)) { $success = $result['success']; } else { $success = true; } } } if (!$success && !$result) { $result = ['action' => Text::_('COM_KUNENA_INSTALL_INCLUDE_STATUS'), 'name' => $filename . '.php', 'success' => $success]; } break; case 'query': $query = (string) $action; $this->db->setQuery($query); $success = true; try { $this->db->execute(); } catch (Exception $e) { $success = false; } if ($action['mode'] == 'silenterror' || !$this->db->getAffectedRows() || $success) { $result = null; } else { $result = ['action' => 'SQL Query: ' . $query, 'name' => '', 'success' => $success]; } break; default: $result = ['action' => 'fail', 'name' => $nodeName, 'success' => false]; } return $result; } /** * @return boolean * * @throws Exception * @since Kunena 6.0 */ public function installSampleData(): bool { require_once KUNENA_INSTALLER_PATH . '/sql/install/php/sampleData.php'; if (installSampleData()) { $this->addStatus(Text::_('COM_KUNENA_INSTALL_SAMPLEDATA'), true); } return true; } /** * @return boolean * * @throws Exception * @since Kunena 6.0 */ public function migrateCategoryImages(): bool { $action = $this->getAction(); if ($action != 'migrate') { return true; } $srcpath = JPATH_ROOT . '/images/fbfiles/category_images'; $dstpath = KUNENA_INSTALLER_MEDIAPATH . '/category_images'; if (is_dir($srcpath)) { if (!Folder::delete($dstpath) || !Folder::copy($srcpath, $dstpath)) { $this->addStatus("Could not copy category images from $srcpath to $dstpath", true); } else { $this->addStatus(Text::_('COM_KUNENA_MIGRATE_CATEGORY_IMAGES'), true); } } return true; } // Helper function to migrate table // TODO: move to migration /** * @return boolean * * @throws KunenaInstallerException * @throws Exception * @since Kunena 6.0 */ public function migrateAvatars(): bool { $stats = $this->getAvatarStatus(); static $dirs = [ 'media/kunena/avatars', 'images/fbfiles/avatars', 'components/com_fireboard/avatars', ]; $query = "SELECT COUNT(*) FROM `#__kunena_users` WHERE userid>{$this->db->quote($stats->current)} AND avatar != '' AND avatar NOT LIKE 'gallery/%' AND avatar NOT LIKE 'users/%'"; $this->db->setQuery($query); try { $count = $this->db->loadResult(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } if (!$stats->current && !$count) { return true; } $query = "SELECT userid, avatar FROM `#__kunena_users` WHERE userid>{$this->db->quote($stats->current)} AND avatar != '' AND avatar NOT LIKE 'gallery/%' AND avatar NOT LIKE 'users/%'"; $query->setLimit(1023); $this->db->setQuery($query); try { $users = $this->db->loadObjectList(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } foreach ($users as $user) { $userid = $stats->current = $user->userid; $avatar = $user->avatar; $count--; $file = $newfile = ''; foreach ($dirs as $dir) { if (!is_file(JPATH_ROOT . "/$dir/$avatar")) { continue; } $file = JPATH_ROOT . "/$dir/$avatar"; break; } if ($file) { $file = Path::clean($file, '/'); // Make sure to copy only supported fileformats $match = preg_match('/\.(gif|jpg|jpeg|png)$/ui', $file, $matches); if ($match) { $ext = StringHelper::strtolower($matches[1]); // Use new format: users/avatar62.jpg $newfile = "users/avatar{$userid}.{$ext}"; $destpath = (KUNENA_INSTALLER_MEDIAPATH . "/avatars/{$newfile}"); if (is_file($destpath)) { $success = true; } else { @chmod($file, 0644); $success = File::copy($file, $destpath); } if ($success) { $stats->migrated++; } else { $this->addStatus("User: {$userid}, Avatar copy failed: {$file} to {$destpath}", true); $stats->failed++; } } else { $this->addStatus("User: {$userid}, Avatar type not supported: {$file}", true); $stats->failed++; $success = true; } } else { // $this->addStatus ( "User: {$userid}, Avatar file was not found: {$avatar}", true ); $stats->missing++; $success = true; } if ($success) { $query = "UPDATE `#__kunena_users` SET avatar={$this->db->quote($newfile)} WHERE userid={$this->db->quote($userid)}"; $this->db->setQuery($query); try { $this->db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } } if ($this->checkTimeout()) { break; } } $this->setAvatarStatus($stats); if ($count) { $this->addStatus(Text::sprintf('COM_KUNENA_MIGRATE_AVATARS', $count), true, '', 'avatar'); } else { $this->addStatus(Text::sprintf('COM_KUNENA_MIGRATE_AVATARS_DONE', $stats->migrated, $stats->missing, $stats->failed), true, '', 'avatar'); } return !$count; } // TODO: move to migration /** * @return \stdClass * * @throws \Exception * @since Kunena 6.0 */ protected function getAvatarStatus(): stdClass { $app = Factory::getApplication(); $stats = new stdClass(); $stats->current = $stats->migrated = $stats->failed = $stats->missing = 0; $stats = $app->getUserState('com_kunena.install.avatars', $stats); return $stats; } /** * @return boolean * * @throws Exception * @since Kunena 6.0 */ public function migrateAvatarGalleries(): bool { $action = $this->getAction(); if ($action != 'migrate') { return true; } $srcpath = JPATH_ROOT . '/images/fbfiles/avatars/gallery'; $dstpath = KUNENA_INSTALLER_MEDIAPATH . '/avatars/gallery'; if (is_dir($srcpath)) { if (!Folder::delete($dstpath) || !Folder::copy($srcpath, $dstpath)) { $this->addStatus("Could not copy avatar galleries from $srcpath to $dstpath", true); } else { $this->addStatus(Text::_('COM_KUNENA_MIGRATE_AVATAR_GALLERY'), true); } } return true; } // Also insert old version if not in the table /** * @return boolean * * @throws KunenaInstallerException * @throws Exception * @since Kunena 6.0 */ public function migrateAttachments(): bool { // Only perform this stage if we are upgrading from older version $version = $this->getVersion(); if (version_compare($version->version, '1.7.0', ">")) { return true; } $stats = $this->getAttachmentStatus(); static $dirs = [ 'images/fbfiles/attachments', 'components/com_fireboard/uploaded', 'media/kunena/attachments/legacy', ]; $query = $this->db->createQuery(); $query->select('COUNT(*)') ->from($this->db->quoteName('#__kunena_attachments')) ->where('id > ' . $this->db->quote($stats->current) . ' AND hash IS NULL'); $this->db->setQuery($query); try { $count = $this->db->loadResult(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } if (!$stats->current && !$count) { return true; } $destpath = KUNENA_INSTALLER_MEDIAPATH . '/attachments/legacy'; if (!is_dir($destpath . '/images')) { if (!Folder::create($destpath . '/images')) { $this->addStatus("Could not create directory for legacy attachments in {$destpath}/images", true); return true; } } if (!is_dir($destpath . '/files')) { if (!Folder::create($destpath . '/files')) { $this->addStatus("Could not create directory for legacy attachments in {$destpath}/files", true); return true; } } $query = $this->db->createQuery(); $query->select('COUNT(*)') ->from($this->db->quoteName('#__kunena_attachments')) ->where('id > ' . $this->db->quote($stats->current) . ' AND hash IS NULL'); $query->setLimit(251); $this->db->setQuery($query); try { $attachments = $this->db->loadObjectList(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } foreach ($attachments as $attachment) { $stats->current = $attachment->id; $count--; if (preg_match('|/images$|', $attachment->folder)) { $lastpath = 'images'; $attachment->filetype = 'image/' . strtolower($attachment->filetype); } else { if (preg_match('|/files$|', $attachment->folder)) { $lastpath = 'files'; } else { // Only process files in legacy locations, either in original folders or manually copied into /media/kunena/attachments/legacy continue; } } $file = ''; if (is_file(JPATH_ROOT . "/{$attachment->folder}/{$attachment->filename}")) { $file = JPATH_ROOT . "/{$attachment->folder}/{$attachment->filename}"; } else { foreach ($dirs as $dir) { if (is_file(JPATH_ROOT . "/{$dir}/{$lastpath}/{$attachment->filename}")) { $file = JPATH_ROOT . "/{$dir}/{$lastpath}/{$attachment->filename}"; break; } } } $success = false; $destfile = null; if ($file) { $file = Path::clean($file, '/'); $destfile = "{$destpath}/{$lastpath}/{$attachment->filename}"; if (is_file($destfile)) { $success = true; } else { @chmod($file, 0644); $success = File::copy($file, $destfile); } if ($success) { $stats->migrated++; } else { $this->addStatus("Attachment copy failed: {$file} to {$destfile}", true); $stats->failed++; } } else { // $this->addStatus ( "Attachment file was not found: {$file}", true ); $stats->missing++; } if ($success && $destfile) { clearstatcache(); $stat = stat($destfile); $size = (int) $stat['size']; $hash = md5_file($destfile); $query = $this->db->createQuery(); $query->update($this->db->quoteName('#__kunena_attachments')) ->set( 'folder=\'media/kunena/attachments/legacy/' . $lastpath . '\', size=' . $this->db->quote($size) . ', hash=' . $this->db->quote($hash) . ', filetype=' . $this->db->quote($attachment->filetype) ) ->where('id=' . $this->db->quote($attachment->id)); $this->db->setQuery($query); try { $this->db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } } if ($this->checkTimeout()) { break; } } $this->setAttachmentStatus($stats); if ($count) { $this->addStatus(Text::sprintf('COM_KUNENA_MIGRATE_ATTACHMENTS', $count), true, '', 'attach'); } else { // Note: com_fireboard has been replaced by com_kunena during 1.0.8 upgrade, use it instead $query = "UPDATE `#__kunena_messages_text` SET message = REPLACE(REPLACE(message, '/images/fbfiles', '/media/kunena/attachments/legacy'), '/components/com_kunena/uploaded', '/media/kunena/attachments/legacy');"; $this->db->setQuery($query); try { $this->db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } $this->addStatus(Text::sprintf('COM_KUNENA_MIGRATE_ATTACHMENTS_DONE', $stats->migrated, $stats->missing, $stats->failed), true, '', 'attach'); } return !$count; } /** * @return \stdClass * * @throws \Exception * @since Kunena 6.0 */ protected function getAttachmentStatus(): stdClass { $app = Factory::getApplication(); $stats = new stdClass(); $stats->current = $stats->migrated = $stats->failed = $stats->missing = 0; $stats = $app->getUserState('com_kunena.install.attachments', $stats); return $stats; } /** * @return void * * @throws KunenaInstallerException * @throws Exception * @since Kunena 6.0 */ public function stepFinish(): void { KunenaForum::setup(); $lang = Factory::getApplication()->getLanguage(); $lang->load('com_kunena', JPATH_SITE) || $lang->load('com_kunena', KUNENA_INSTALLER_SITEPATH); $this->createMenu(); // Fix broken category aliases (workaround for < 2.0-DEV12 bug) KunenaCategoryHelper::fixAliases(); // Clean cache, just in case KunenaMenuHelper::cleanCache(); $cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class)->createCacheController(); $cache->clean('com_kunena'); /* // Resync bbcode plugins $editor = KunenaBbcodeEditor::getInstance(); $editor->initializeHMVC();*/ // Delete the tmp install directory foreach (glob(KunenaPath::tmpdir() . '/install_*') as $dir) { if (is_dir($dir)) { Folder::delete($dir); } } $version = ''; $date = ''; $file = JPATH_MANIFESTS . '/packages/pkg_kunena.xml'; if (file_exists($file)) { $manifest = simplexml_load_file($file); $version = (string) $manifest->version; $date = (string) $manifest->creationDate; } else { $db = Factory::getContainer()->get('DatabaseDriver'); $query = $db->createQuery(); $query->select('version')->from('#__kunena_version')->order('id'); $query->setLimit(1); $db->setQuery($query); $version = $db->loadResult(); $date = (string) $version->versiondate; } $tmpfile = KunenaPath::tmpdir() . '/pkg_kunena_v' . $version . '_' . $date . '.zip'; if (is_file($tmpfile)) { File::delete(KunenaPath::tmpdir() . '/pkg_kunena_v' . $version . '_' . $date . '.zip'); } } /** * Create a Joomla menu for the main * navigation tab and publish it in the Kunena module position kunena_menu. * In addition it checks if there is a link to Kunena in any of the menus * and if not, adds a forum link in the mainmenu. * * @return void * * @throws Exception * @throws KunenaInstallerException * @since Kunena 6.0 */ public function createMenu(): void { KunenaFactory::loadLanguage('com_kunena.install', 'admin'); $menu = [ 'name' => Text::_('COM_KUNENA_MENU_ITEM_FORUM'), 'alias' => KunenaRoute::stringURLSafe(Text::_('COM_KUNENA_MENU_FORUM_ALIAS'), 'forum'), 'link' => 'index.php?option=com_kunena&view=home', 'access' => 1, 'params' => ['catids' => 0], ]; $this->buildMenu($menu); KunenaMenuHelper::cleanCache(); } /** * Build the Kunena menu * * @param array $menu menu * * @return boolean * * @throws KunenaInstallerException * @throws Exception * @since Kunena 6.0 */ public function buildMenu(array $menu) { $config = KunenaFactory::getConfig(); $component_id = (int) ComponentHelper::getComponent('com_kunena')->id; KunenaFactory::loadLanguage('com_kunena.install', 'admin'); $languages = LanguageHelper::getLanguages('default'); $langCode = $languages[0]->lang_code; // First fix all broken menu items $db = Factory::getContainer()->get('DatabaseDriver'); $query = $db->createQuery() ->update($db->quoteName('#__menu')) ->set($db->quoteName('component_id') . ' = ' . $component_id) ->where("link LIKE '%option=com_kunena%'") ->andWhere('type = "component"'); $db->setQuery($query); try { $db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } $db = Factory::getContainer()->get(DatabaseInterface::class); $table = new MenuType($db); $data = [ 'menutype' => 'kunenamenu', 'title' => Text::_('COM_KUNENA_MENU_TITLE'), 'description' => Text::_('COM_KUNENA_MENU_TITLE_DESC'), ]; if (!$table->bind($data) || !$table->check()) { // Menu already exists, do nothing return true; } try { $table->store(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } $db = Factory::getContainer()->get(DatabaseInterface::class); $table = new Menu($db); $table->load(['menutype' => 'kunenamenu', 'link' => $menu['link']]); $paramdata = [ 'menu-anchor_title' => '', 'menu-anchor_css' => '', 'menu_image' => '', 'menu_text' => 1, 'page_title' => '', 'show_page_heading' => 0, 'page_heading' => '', 'pageclass_sfx' => '', 'menu-meta_description' => '', 'robots' => '', 'secure' => 0, ]; $gparams = new Registry($paramdata); $params = clone $gparams; $params->loadArray($menu['params']); $data = [ 'menutype' => 'kunenamenu', 'title' => $menu['name'], 'alias' => $menu['alias'], 'link' => $menu['link'], 'type' => 'component', 'published' => 1, 'parentid' => 1, 'component_id' => $component_id, 'access' => $menu['access'], 'params' => (string) $params, 'home' => 0, 'language' => '*', 'client_id' => 0, ]; $table->setLocation(1, 'last-child'); if (!$table->bind($data) || !$table->check() || !$table->store()) { $table->alias = 'kunena'; if (!$table->check() || !$table->store()) { // Menu already exists, do nothing return true; } } $parent = $table; $defaultmenu = 0; /*foreach ($languages as $langCode => $language) {*/ $lang = Factory::getApplication()->getLanguage(); $lang->load('com_kunena.install', JPATH_ADMINISTRATOR . '/components/com_kunena', $langCode); $submenu = [ 'index' => [ 'name' => Text::_('COM_KUNENA_MENU_ITEM_INDEX'), 'alias' => KunenaRoute::stringURLSafe(Text::_('COM_KUNENA_MENU_INDEX_ALIAS'), 'index'), 'link' => 'index.php?option=com_kunena&view=category&layout=list', 'access' => 1, 'default' => 'categories', 'params' => [], ], 'recent' => [ 'name' => Text::_('COM_KUNENA_MENU_ITEM_RECENT'), 'alias' => KunenaRoute::stringURLSafe(Text::_('COM_KUNENA_MENU_RECENT_ALIAS'), 'recent'), 'link' => 'index.php?option=com_kunena&view=topics&mode=replies', 'access' => 1, 'default' => 'recent', 'params' => ['topics_catselection' => '', 'topics_categories' => '', 'topics_time' => ''], ], 'unread' => [ 'name' => Text::_('COM_KUNENA_MENU_ITEM_UNREAD'), 'alias' => KunenaRoute::stringURLSafe(Text::_('COM_KUNENA_MENU_UNREAD_ALIAS'), 'unread'), 'link' => 'index.php?option=com_kunena&view=topics&layout=unread', 'access' => 2, 'params' => [], ], 'newtopic' => [ 'name' => Text::_('COM_KUNENA_MENU_ITEM_NEWTOPIC'), 'alias' => KunenaRoute::stringURLSafe(Text::_('COM_KUNENA_MENU_NEWTOPIC_ALIAS'), 'newtopic'), 'link' => 'index.php?option=com_kunena&view=topic&layout=create', 'access' => 2, 'params' => [], ], 'noreplies' => [ 'name' => Text::_('COM_KUNENA_MENU_ITEM_NOREPLIES'), 'alias' => KunenaRoute::stringURLSafe(Text::_('COM_KUNENA_MENU_NOREPLIES_ALIAS'), 'noreplies'), 'link' => 'index.php?option=com_kunena&view=topics&mode=noreplies', 'access' => 2, 'params' => ['topics_catselection' => '', 'topics_categories' => '', 'topics_time' => ''], ], 'mylatest' => [ 'name' => Text::_('COM_KUNENA_MENU_ITEM_MYLATEST'), 'alias' => KunenaRoute::stringURLSafe(Text::_('COM_KUNENA_MENU_MYLATEST_ALIAS'), 'mylatest'), 'link' => 'index.php?option=com_kunena&view=topics&layout=user&mode=default', 'access' => 2, 'default' => 'my', 'params' => ['topics_catselection' => '2', 'topics_categories' => '0', 'topics_time' => ''], ], 'profile' => [ 'name' => Text::_('COM_KUNENA_MENU_ITEM_PROFILE'), 'alias' => KunenaRoute::stringURLSafe(Text::_('COM_KUNENA_MENU_PROFILE_ALIAS'), 'profile'), 'link' => 'index.php?option=com_kunena&view=user', 'access' => 2, 'params' => ['integration' => 1], ], 'help' => [ 'name' => Text::_('COM_KUNENA_MENU_ITEM_HELP'), 'alias' => KunenaRoute::stringURLSafe(Text::_('COM_KUNENA_MENU_HELP_ALIAS'), 'help'), 'link' => 'index.php?option=com_kunena&view=misc', 'access' => 3, 'params' => ['body' => Text::_('COM_KUNENA_MENU_HELP_BODY'), 'body_format' => 'bbcode'], ], 'search' => [ 'name' => Text::_('COM_KUNENA_MENU_ITEM_SEARCH'), 'alias' => KunenaRoute::stringURLSafe(Text::_('COM_KUNENA_MENU_SEARCH_ALIAS'), 'search'), 'link' => 'index.php?option=com_kunena&view=search', 'access' => 1, 'params' => [], ], ]; foreach ($submenu as $menuitem) { $params = clone $gparams; $params->loadArray($menuitem['params']); $db = Factory::getContainer()->get(DatabaseInterface::class); $table = new Menu($db); $table->load(['menutype' => 'kunenamenu', 'link' => $menuitem['link'], 'language' => $langCode]); $data = [ 'menutype' => 'kunenamenu', 'title' => $menuitem['name'], 'alias' => $menuitem['alias'], 'link' => $menuitem['link'], 'type' => 'component', 'published' => 1, 'parentid' => $parent->id, 'component_id' => $component_id, 'access' => $menuitem['access'], 'params' => (string) $params, 'home' => 0, 'language' => $langCode, 'client_id' => 0, ]; $table->setLocation($parent->id, 'last-child'); if (!$table->bind($data) || !$table->check() || !$table->store()) { throw new KunenaInstallerException($table->getError()); } if (!$defaultmenu || (isset($menuitem['default']) && $config->defaultPage == $menuitem['default'])) { $defaultmenu = $table->id; } } //} // Update forum menuitem to point into default page $parent->link .= "&defaultmenu={$defaultmenu}"; if (!$parent->check() || !$parent->store()) { throw new KunenaInstallerException($table->getError()); } // Finally create alias $defaultmenu = AbstractMenu::getInstance('site')->getDefault(); if (!$defaultmenu) { return true; } $db = Factory::getContainer()->get(DatabaseInterface::class); $table = new Menu($db); $table->load(['menutype' => $defaultmenu->menutype, 'type' => 'alias', 'title' => Text::_('COM_KUNENA_MENU_ITEM_FORUM'), 'language' => $langCode]); if (!$table->id) { $data = [ 'menutype' => $defaultmenu->menutype, 'title' => Text::_('COM_KUNENA_MENU_ITEM_FORUM'), 'alias' => 'kunena-' . Factory::getDate()->format('Y-m-d'), 'note' => '', 'link' => 'index.php?Itemid=' . $parent->id, 'type' => 'alias', 'published' => 0, 'parent_id' => 1, 'component_id' => 0, 'checked_out' => null, 'checked_out_time' => null, 'browserNav' => 0, 'access' => 1, 'img' => '', 'template_style_id' => 0, 'params' => '{"aliasoptions":"' . (int) $parent->id . '","menu-anchor_title":"","menu-anchor_css":"","menu_image":""}', 'home' => 0, 'language' => '*', 'client_id' => 0, ]; $table->setLocation(1, 'last-child'); } else { $data = [ 'alias' => 'kunena-' . Factory::getDate()->format('Y-m-d'), 'link' => 'index.php?Itemid=' . $parent->id, 'params' => '{"aliasoptions":"' . (int) $parent->id . '","menu-anchor_title":"","menu-anchor_css":"","menu_image":""}', ]; } try { $table->bind($data); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } if (!$table->check() || !$table->store()) { // Menu already exists, do nothing return true; } } /** * @return boolean * * @throws Exception * @since Kunena 6.0 */ public function recountCategories(): bool { $app = Factory::getApplication(); $state = $app->getUserState('com_kunena.install.recount', null); // Only perform this stage if database needs recounting (upgrade from older version) $version = $this->getVersion(); if (version_compare($version->version, '2.0.0-DEV', ">")) { return true; } if ($state === null) { // First run $db = Factory::getContainer()->get('DatabaseDriver'); $query = $db->createQuery(); $query->select('MAX(id)')->from('#__kunena_messages'); $db->setQuery($query); $state = new stdClass(); $state->step = 0; $state->maxId = (int) $db->loadResult(); $state->start = 0; } while (1) { $count = mt_rand(4500, 5500); switch ($state->step) { case 0: // Update topic statistics KunenaTopicHelper::recount(false, $state->start, $state->start + $count); $state->start += $count; $this->addStatus(Text::sprintf('COM_KUNENA_MIGRATE_RECOUNT_TOPICS', min($state->start, $state->maxId), $state->maxId), true, '', 'recount'); break; case 1: // Update usertopic statistics KunenaTopicUserHelper::recount(false, $state->start, $state->start + $count); $state->start += $count; $this->addStatus(Text::sprintf('COM_KUNENA_MIGRATE_RECOUNT_USERTOPICS', min($state->start, $state->maxId), $state->maxId), true, '', 'recount'); break; case 2: // Update user statistics KunenaUserHelper::recount(); $this->addStatus(Text::sprintf('COM_KUNENA_MIGRATE_RECOUNT_USER'), true, '', 'recount'); break; case 3: // Update category statistics KunenaCategoryHelper::recount(); $this->addStatus(Text::sprintf('COM_KUNENA_MIGRATE_RECOUNT_CATEGORY'), true, '', 'recount'); break; default: $app->setUserState('com_kunena.install.recount', null); $this->addStatus(Text::_('COM_KUNENA_MIGRATE_RECOUNT_DONE'), true, '', 'recount'); return true; } if (!$state->start || $state->start > $state->maxId) { $state->step++; $state->start = 0; } if ($this->checkTimeout(false, 14)) { break; } } $app->setUserState('com_kunena.install.recount', $state); return false; } /** * @return array|null * * @throws \Kunena\Forum\Libraries\Install\KunenaInstallerException * @since Kunena 6.0 */ public function createVersionTable(): ?array { $tables = $this->listTables('kunena_'); if (isset($tables['kunena_version'])) { // Nothing to migrate return false; } $collation = $this->db->getCollation(); if (!strstr($collation, 'utf8') && !strstr($collation, 'utf8mb4')) { $collation = 'utf8_general_ci'; } if (strstr($collation, 'utf8mb4')) { $str = 'utf8mb4'; } else { $str = 'utf8'; } $query = "CREATE TABLE IF NOT EXISTS `" . $this->db->getPrefix() . "kunena_version` ( `id` int(11) NOT NULL AUTO_INCREMENT, `version` varchar(20) NOT NULL, `versiondate` date NOT NULL, `installdate` date NOT NULL, `build` varchar(20) DEFAULT NULL, `versionname` varchar(40) DEFAULT NULL, `state` text DEFAULT NULL, PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET {$str} COLLATE {$collation};"; $this->db->setQuery($query); try { $this->db->execute(); } catch (Exception $e) { throw new KunenaInstallerException($e->getMessage(), $e->getCode()); } $this->tables['kunena_']['kunena_version'] = 'kunena_version'; return ['action' => Text::_('COM_KUNENA_INSTALL_CREATE'), 'name' => 'kunena_version', 'sql' => $query]; } /** * @return boolean * * @throws Exception * @since Kunena 6.0 */ public function recountThankyou(): bool { // Only perform this action if upgrading form previous version $version = $this->getVersion(); if (version_compare($version->version, '2.0.0-BETA2', ">")) { return true; } // If the migration is from previous version thant 1.6.0 doesn't need to recount if (version_compare($version->version, '1.6.0', "<")) { return true; } KunenaMessageThankyouHelper::recount(); return true; } } /** * Class KunenaInstallerException * * @since Kunena 6.0 */ class KunenaInstallerException extends Exception {}
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0.01 |
proxy
|
phpinfo
|
ÐаÑтройка