File Manager

Current Directory: /home/astoriaah/www/administrator/components/com_sh404sef
Viewing File: /home/astoriaah/www/administrator/components/com_sh404sef/installation.script.php
<?php /** * sh404SEF - SEO extension for Joomla! * * @package sh404SEF * @copyright (c) Yannick Gaultier - Weeblr llc - 2022 * @author Yannick Gaultier * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL * @version 4.24.1.4308 * @date 2022-05-31 */ // Security check to ensure this file is being included by a parent file. defined('_JEXEC') or die; /** * Installation/Uninstallation script * */ class Com_Sh404sefInstallerScript { const MIN_JOOMLA_VERSION = '3.9.0'; const MAX_JOOMLA_VERSION = '4.0'; const MIN_PHP_VERSION = '5.6.0'; const MAX_PHP_VERSION = ''; const MIN_SHLIB_VERSION = '0.4.0'; const MAX_SHLIB_VERSION = ''; private $_siteId = ''; private $_preserveConfigFolder = ''; private $_errorPageCatId = 0; private $_shlibVersion = ''; private $_skipInstall = array(); private $hasUtf8mb4Support = false; private $charset = 'utf8'; private $collation = 'utf8_general_ci'; public function preflight($route, $installer) { if ($route == 'install' || $route == 'update') { // check Joomla! version if (version_compare(JVERSION, self::MIN_JOOMLA_VERSION, '<') || version_compare(JVERSION, self::MAX_JOOMLA_VERSION, 'ge')) { JFactory::getApplication() ->enqueueMessage( sprintf( 'sh404SEF requires Joomla! version %s or above, and below %s (you are using %s). Aborting installation', self::MIN_JOOMLA_VERSION, self::MAX_JOOMLA_VERSION, JVERSION ), 'error' ); return false; } if ( version_compare(phpversion(), self::MIN_PHP_VERSION, '<') || ( !empty(self::MAX_PHP_VERSION) && version_compare( phpversion(), self::MAX_PHP_VERSION, 'ge' ) ) ) { JFactory::getApplication() ->enqueueMessage( sprintf( 'sh404SEF requires PHP version %s or above, and below %s (you are using %s). Aborting installation', self::MIN_PHP_VERSION, self::MAX_PHP_VERSION, phpversion() ), 'error' ); return false; } // make sure resource manager is available, we'll need it during plugins installs if (!class_exists('ShlSystem_Resourcemanager')) { require_once $installer->getParent()->getPath('source') . '/admin/plugins/system/shlib/shl_packages/system/resourcemanager.php'; } // check authorization to install for shared resources $newVersionFile = $installer->getParent()->getPath('source') . '/admin/plugins/system/shlib/shlib.xml'; $this->_shlibVersion = ShlSystem_Resourcemanager::getXmlFileVersion($newVersionFile); $installCheckResult = ShlSystem_Resourcemanager::canInstall('shlib', $this->_shlibVersion, $allowDowngrade = false, self::MIN_SHLIB_VERSION, self::MAX_SHLIB_VERSION); if ($installCheckResult->canInstall == 'no') { JFactory::getApplication() ->enqueueMessage( 'Cannot install sh404SEF: not allowed to install shLib version ' . $this->_shlibVersion . ': ' . $installCheckResult->reason, 'error' ); } if ($installCheckResult->canInstall == 'skip') { $this->_shlibVersion = ''; $this->_skipInstall[] = 'shlib'; JFactory::getApplication() ->enqueueMessage('shLib: skipping install of shLib version ' . $this->_shlibVersion . ': ' . $installCheckResult->reason); } $canInstall = $installCheckResult->canInstall != 'no'; return $canInstall; } } /** * Insert in the db the previously retrieved parameters for a plugin * including publication information. Also move files as required * * @param string $basePath , the base path to get original files from */ public function postflight($type, $parent) { if (function_exists('apc_clear_cache')) { apc_clear_cache(); } if (function_exists('opcache_reset')) { opcache_reset(); } $this->_doInstallUpdate($parent); // installed a shared resource? register it with version if (!in_array('shlib', $this->_skipInstall)) { ShlSystem_Resourcemanager::registerResource('shlib', $this->_shlibVersion); } // register that we are now using shLib ShlSystem_Resourcemanager::register(array('resource' => 'shlib', 'context' => 'com_sh404sef', 'min_version' => self::MIN_SHLIB_VERSION, 'max_version' => self::MAX_SHLIB_VERSION)); // J3.6.1+ need language filter to be before sh404SEF system plg, change in initialization code $this->fixPluginsOrder(); // make sure the update site is appropriate $this->_processUpdateSite($type, $parent); // clear caches, in case cache handling or remote config has been modified $caches = array('sh404sef_updates', 'sh404sef_rconfig', 'sh404sef_analytics_auth', 'sh404sef_analytics'); foreach ($caches as $cacheName) { $cache = JFactory::getCache($cacheName); $cache->clean(); } } public function install($parent) { } public function uninstall($parent) { // save configuration try { $this->_definePaths(); $db = JFactory::getDbo(); $query = $db->getQuery(true); $query->select('params') ->from('#__extensions') ->where($db->qn('type') . '=' . $db->q('component')) ->where($db->qn('element') . '=' . $db->q('com_sh404sef')); $db->setQuery($query); $sh404sef = $db->loadObject(); $saved = $this->_writeExtensionConfig('com_sh404sef', array('sh404sefConfig' => $sh404sef->params)); if (!$saved) { JFactory::getApplication()->enqueueMessage('Error saving sh404SEF configuration to disk, configuration may be lost upon reinstallation'); } } catch (\Exception $e) { JFactory::getApplication()->enqueueMessage('Error saving sh404SEF configuration to disk, configuration may be lost upon reinstallation'); } $this->_doUninstall($parent); } public function update($parent) { } private function _definePaths() { $this->_siteId = rtrim(str_replace('/administrator', '', JURI::base()), '/'); $this->_siteId = str_replace('/', '_', str_replace('http://', '', $this->_siteId)); $this->_preserveConfigFolder = JPATH_ROOT . '/media/sh404sef/'; } // Implementation of install/uninstall scripts /** * Writes an extension parameter to a disk file, located * in the /media directory * * @param string $extName the extension name * @param $params * * @return boolean, true if no error */ private function _writeExtensionConfig($extName, $params) { if (empty($params)) { return; } // calculate target file name $extPath = $this->_preserveConfigFolder . 'sh404_upgrade_conf'; // if it does not exists, lets create it first if (!JFolder::exists($extPath)) { JFolder::create($extPath); } // make sure we have an index.html file in that folder $target = JPath::clean($extPath . '/' . 'index.html'); if (!JFile::exists($target)) { // copy one Joomla's index.html file to the backup directory $source = JPath::clean(JPATH_ROOT . '/plugins/index.html'); $success = JFile::copy($source, $target); } // now build full path file name to save config $extFile = $extPath . '/' . $extName . '_' . $this->_siteId . '.php'; // remove previous if any if (JFile::exists($extFile)) { JFile::delete($extFile); } // prepare data for writing $data = '<?php // Extension params save file for sh404sef // if (!defined(\'_JEXEC\')) {die(\'Direct Access to this location is not allowed.\');}'; $data .= "\n"; if (!empty($params)) { foreach ($params as $key => $value) { $data .= '$' . $key . ' = ' . var_export($value, true) . ';'; $data .= "\n"; } } // write to disk $success = JFile::write($extFile, $data); return $success !== false; } /** * Performs pre-uninstall backup of configuration * * @param object $parent */ private function _doUninstall($parent) { $this->_definePaths(); $this->_includeLibs(); // Before uninstalling modules, save their settings, if told to do so $sef_config_class = JPATH_ADMINISTRATOR . '/components/com_sh404sef/sh404sef.class.php'; // Make sure class was loaded. if (!class_exists('shSEFConfig')) { if (is_readable($sef_config_class)) { require_once($sef_config_class); } else { JError::RaiseError(500, JText::_('COM_SH404SEF_NOREAD') . "( $sef_config_class )<br />" . JText::_('COM_SH404SEF_CHK_PERMS')); } } $sefConfig = new shSEFConfig(); if (!$sefConfig->shKeepStandardURLOnUpgrade && !$sefConfig->shKeepCustomURLOnUpgrade) { $this->_deletetable('sh404sef_urls'); $this->_deletetable('sh404sef_urls_src'); $this->_deletetable('sh404sef_hits_404s'); $this->_deletetable('sh404sef_aliases'); $this->_deletetable('sh404sef_hits_aliases'); $this->_deletetable('sh404sef_pageids'); $this->_deletetable('sh404sef_hits_shurls'); } elseif (!$sefConfig->shKeepStandardURLOnUpgrade) { $this->_deleteAllSEFUrl('Standard'); $this->_deletetable('sh404sef_urls_src'); $this->_deletetable('sh404sef_hits_404s'); } elseif (!$sefConfig->shKeepCustomURLOnUpgrade) { $this->_deleteAllSEFUrl('Custom'); $this->_deletetable('sh404sef_aliases'); $this->_deletetable('sh404sef_hits_aliases'); $this->_deletetable('sh404sef_pageids'); $this->_deletetable('sh404sef_hits_shurls'); } if (!$sefConfig->shKeepMetaDataOnUpgrade) { $this->_deletetable('sh404sef_metas'); } // delete key store, content (error pages) has been saved before $this->_deletetable('sh404sef_keystore'); // remove system plugins $this->_saveDeletePluginParams('sh404sef', 'system'); $this->_saveDeletePluginParams('shmobile', 'system'); // remove installer plugin $this->_saveDeletePluginParams('sh404sef', 'installer'); // unregister from shLib, then possibly uninstall it if (JFile::exists(JPATH_ROOT . '/plugins/system/shlib/shl_packages/system/resourcemanager.php')) { require_once JPATH_ROOT . '/plugins/system/shlib/shl_packages/system/resourcemanager.php'; ShlSystem_Resourcemanager::unregister('shlib', 'com_sh404sef'); if (ShlSystem_Resourcemanager::canUninstall('shlib')) { $this->_saveDeletePluginParams('shlib', 'system'); } } // remove core plugins $this->_saveDeletePluginGroup('sh404sefcore'); $this->_saveDeletePluginGroup('sh404sefextplugins'); // delete analytics cached data, to force update // in case this part of sh404sef has changed $cache = JFactory::getCache('sh404sef_analytics'); $cache->clean(); // preserve configuration or not ? if (!$sefConfig->shKeepConfigOnUpgrade) { // main config file $fileName = $this->_preserveConfigFolder . 'sh404_upgrade_conf_' . $this->_siteId . '.php'; if (JFile::exists($fileName)) { JFile::delete($fileName); } // user custom config file $fileName = $this->_preserveConfigFolder . 'sh404_upgrade_conf_' . $this->_siteId . '.custom.php'; if (JFile::exists($fileName)) { JFile::delete($fileName); } // related extensions (plugins) config files folder if (JFolder::exists($this->_preserveConfigFolder . 'sh404_upgrade_conf')) { JFolder::delete($this->_preserveConfigFolder . 'sh404_upgrade_conf'); } // log files folder if (JFolder::exists($this->_preserveConfigFolder . 'sh404_upgrade_conf_logs')) { JFolder::delete($this->_preserveConfigFolder . 'sh404_upgrade_conf_logs'); } // security log files folder if (JFolder::exists($this->_preserveConfigFolder . 'sh404_upgrade_conf_security')) { JFolder::delete($this->_preserveConfigFolder . 'sh404_upgrade_conf_security'); } } else { // if we keep config if (JFolder::exists(JPATH_ROOT . '/logs/sh404sef')) { JFolder::copy(JPATH_ROOT . '/logs/sh404sef', $this->_preserveConfigFolder . 'sh404_upgrade_conf_logs', $path = '', $force = true); } if (JFolder::exists(JPATH_ADMINISTRATOR . '/components/com_sh404sef/security')) { JFolder::copy( JPATH_ADMINISTRATOR . '/components/com_sh404sef/security', $this->_preserveConfigFolder . 'sh404_upgrade_conf_security', $path = '', $force = true ); } } // delete folder in /media // display results echo '<h3>sh404SEF has been succesfully uninstalled. </h3>'; echo '<br />'; if ($sefConfig->shKeepStandardURLOnUpgrade) { echo '- automatically generated SEF url have not been deleted (table #__sh404sef_urls)<br />'; } else { echo '- automatically generated SEF url have been deleted<br />'; } echo '<br />'; if ($sefConfig->shKeepCustomURLOnUpgrade) { echo '- custom SEF url, aliases and pageIds have not been deleted (tables #__sh404sef_urls, #__sh404sef_aliases and #__sh404sef_pageids)<br />'; } else { echo '- custom SEF url, aliases and pageIds have been deleted<br />'; } echo '<br />'; if ($sefConfig->shKeepMetaDataOnUpgrade) { echo '- Custom Title and META data have not been deleted (table #__sh404sef_metas)<br />'; } else { echo '- Custom Title and META data have been deleted<br />'; } echo '<br />'; } private function _includeLibs() { jimport('joomla.filesystem.file'); jimport('joomla.filesystem.folder'); jimport('joomla.filesystem.path'); jimport('joomla.html.parameter'); jimport('joomla.filter.filterinput'); jimport('joomla.utilities.string'); // we use require instead of require_once so that the NEW, just installed, version of the file is // reloaded. If any new define has been added in the new version, they will thus become available // This requires that defines in defines.php are protected again redefining the same constant require JPATH_ROOT . '/administrator/components/com_sh404sef/defines.php'; // if these files have been included already, we will use the old version of the file require_once JPATH_ROOT . '/administrator/components/com_sh404sef/exceptions/default.php'; require_once JPATH_ROOT . '/administrator/components/com_sh404sef/helpers/language.php'; } private function _deletetable($tableName) { try { $db = JFactory::getDbo(); $query = 'DROP TABLE IF EXISTS ' . $db->qn('#__' . $tableName); $db->setQuery($query)->query(); } catch (\Exception $e) { JFactory::getApplication()->enqueuemessage($e->getMessage(), 'error'); } } private function _deleteAllSEFUrl($kind) { try { $db = JFactory::getDbo(); if ($kind == 'Custom') { $where = $db->qn('dateadd') . ' > ' . $db->q('0000-00-00') . ' and ' . $db->qn('newurl') . ' != ' . $db->q(''); } else { $where = $db->qn('dateadd') . ' = ' . $db->q('0000-00-00'); } $db->setQuery('DELETE FROM ' . $db->qn('#__sh404sef_urls') . ' ' . $where); $db->query(); } catch (\Exception $e) { JFactory::getApplication()->enqueuemessage($e->getMessage(), 'error'); } } /** * Save parameters, then delete a module * Would not work on additional copies made by user * * @param string $moduleName , the module name, matching 'module' column in modules table * @param string $client (ie : site or administrator * * @return bool * @throws Exception */ private function _saveDeleteModuleParams($moduleName, $client) { // read plugin param from db try { $db = JFactory::getDbo(); //$result = ShlDbHelper::selectAssoc('#__extensions', array('*'), // array('type' => 'module', 'element' => $moduleName, 'client_id' => $client)); $query = $db->getQuery(true); $query->select('*') ->from('#__extensions') ->where($db->qn('type') . '=' . $db->q('module')) ->where($db->qn('element') . '=' . $db->q($moduleName)) ->where($db->qn('client_id') . '=' . $db->q($client)); $db->setQuery($query); $result = $db->loadAssoc(); if (empty($result)) { // invalid module name? return false; } // remove module db id unset($result['extension_id']); // write everything on disk $this->_writeExtensionConfig($moduleName . '_extension', array('shConfig' => $result)); // now remove plugin details from db //ShlDbHelper::delete('#__extensions', array('type' => 'module', 'element' => $moduleName, 'client_id' => $client)); $query = $db->getQuery(true); $query->delete('#__extensions') ->where($db->qn('type') . '=' . $db->q('module')) ->where($db->qn('element') . '=' . $db->q($moduleName)) ->where($db->qn('client_id') . '=' . $db->q($client)); $db->setQuery($query)->query(); // do the same for the module instance, in #__module table //$result = ShlDbHelper::selectAssoc('#__modules', array('*'), array('module' => $moduleName, 'client_id' => $client)); $query = $db->getQuery(true); $query->select('*') ->from('#__modules') ->where($db->qn('module') . '=' . $db->q($moduleName)) ->where($db->qn('client_id') . '=' . $db->q($client)); $db->setQuery($query); $result = $db->loadAssoc(); if (empty($result)) { // invalid module name? return false; } // save and remove module db id $moduleId = $result['id']; unset($result['id']); // write everything on disk $this->_writeExtensionConfig($moduleName . '_modules', array('shConfig' => $result)); // now remove plugin details from db //ShlDbHelper::delete('#__modules', array('module' => $moduleName, 'client_id' => $client)); $query = $db->getQuery(true); $query->delete('#__modules') ->where($db->qn('module') . '=' . $db->q($moduleName)) ->where($db->qn('client_id') . '=' . $db->q($client)); $db->setQuery($query)->query(); // remove module/menu affectation //$result = ShlDbHelper::selectAssoc('#__modules_menu', array('*'), array('moduleid' => $moduleId)); $query = $db->getQuery(true); $query->select('*') ->from('#__modules_menu') ->where($db->qn('moduleid') . '=' . $db->q($moduleId)); $db->setQuery($query); $result = $db->loadAssoc(); // remove module db id unset($result['moduleid']); // write everything on disk $this->_writeExtensionConfig($moduleName . '_modules_menu', array('shConfig' => $result)); // now remove plugin details from db //ShlDbHelper::delete('#__modules_menu', array('moduleid' => $moduleId)); $query = $db->getQuery(true); $query->delete('#__modules_menu') ->where($db->qn('moduleid') . '=' . $db->q($moduleId)); $db->setQuery($query)->query(); } catch (\Exception $e) { JFactory::getApplication()->enqueuemessage($e->getMessage(), 'error'); } // delete the module files $path = JPATH_ROOT . '/' . ($client ? 'administrator' . '/' : '') . 'modules/' . $moduleName; if (JFolder::exists($path)) { JFolder::delete($path); } } /** * Save parameters, then delete a plugin * * @param string $pluginName , the plugin name, mathcing 'element' column in plugins table * @param string $folder , the plugin folder (ie : 'content', 'search', 'system',... * @param null $folders * * @return bool * @throws Exception */ private function _saveDeletePluginParams($pluginName, $folder, $folders = null) { try { $db = JFactory::getDbo(); //$result = ShlDbHelper::selectAssoc('#__extensions', array('*'), array('type' => 'plugin', 'element' => $pluginName, 'folder' => $folder)); $query = $db->getQuery(true); $query->select('*') ->from('#__extensions') ->where($db->qn('type') . '=' . $db->q('plugin')) ->where($db->qn('element') . '=' . $db->q($pluginName)) ->where($db->qn('folder') . '=' . $db->q($folder)); $db->setQuery($query); $result = $db->loadAssoc(); if (empty($result)) { // invalid plugin name? return false; } // remove plugin db id $pluginId = $result['extension_id']; unset($result['extension_id']); // write everything on disk $this->_writeExtensionConfig($pluginName, array('shConfig' => $result)); // now uninstall $installer = new JInstaller; $result = $installer->uninstall('plugin', $pluginId); } catch (\Exception $e) { JFactory::getApplication()->enqueuemessage($e->getMessage(), 'error'); } } /** * Save params, then delete plugin, for all plugins * in a given group * * @param $group the group to be deleted * * @return bool * @throws Exception */ private function _saveDeletePluginGroup($group) { $unsafe = array('authentication', 'content', 'editors', 'editors-xtd', 'search', 'system', 'xmlrpc'); if (in_array($group, $unsafe)) { // safety net : we don't want to delete the whole system or content folder return false; } // read plugin param from db try { $db = JFactory::getDbo(); // $pluginList = ShlDbHelper::selectAssocList('#__extensions', array('*'), array('type' => 'plugin', 'folder' => $group)); $query = $db->getQuery(true); $query->select('*') ->from('#__extensions') ->where($db->qn('type') . '=' . $db->q('plugin')) ->where($db->qn('folder') . '=' . $db->q($group)); $db->setQuery($query); $pluginList = $db->loadAssocList(); if (empty($pluginList)) { return true; } // for each plugin foreach ($pluginList as $plugin) { // remove plugin db id unset($plugin['id']); // write everything on disk $this->_writeExtensionConfig($plugin['folder'] . '.' . $plugin['element'], array('shConfig' => $plugin)); // now remove plugin details from db //ShlDbHelper::delete('#__extensions', array('type' => 'plugin', 'element' => $plugin['element'], 'folder' => $plugin['folder'])); $query = $db->getQuery(true); $query->delete('#__extensions') ->where($db->qn('type') . '=' . $db->q('plugin')) ->where($db->qn('element') . '=' . $db->q($plugin['element'])) ->where($db->qn('folder') . '=' . $db->q($plugin['folder'])); $db->setQuery($query)->query(); } } catch (\Exception $e) { JFactory::getApplication()->enqueuemessage($e->getMessage(), 'error'); } // now delete the files for the whole group if (JFolder::exists(JPATH_ROOT . '/plugins/' . $group)) { JFolder::delete(JPATH_ROOT . '/plugins/' . $group); } } private function _doInstallUpdate($parent) { $this->_definePaths(); $this->_includeLibs(); $db = JFactory::getDbo(); // include default functions file $path = JPATH_ROOT . '/libraries/weeblr'; if (!JFolder::exists($path)) { JFolder::create($path); } if (!JFile::exists($path . '/sh404sef_functions.php')) { JFile::copy( JPATH_ADMINISTRATOR . '/components/com_sh404sef/sh404sef_functions.php', $path . '/sh404sef_functions.php' ); } // Copy existing config file from /media to current component. Used to recover configuration when upgrading // check if old file exists before deleting stub config file $oldConfigFile = $this->_preserveConfigFolder . 'sh404_upgrade_conf_' . $this->_siteId . '.php'; if (JFile::exists($oldConfigFile)) { // update old config files from VALID_MOS check to _JEXEC $config = JFile::read($oldConfigFile); if ($config && strpos($config, 'VALID_MOS') !== false) { $config = str_replace('VALID_MOS', '_JEXEC', $config); JFile::write($oldConfigFile, $config); // write it back } // now get back old config if (JFile::exists(JPATH_ADMINISTRATOR . '/components/com_sh404sef/config/config.sef.php')) { JFile::delete(JPATH_ADMINISTRATOR . '/components/com_sh404sef/config/config.sef.php'); } JFile::copy($oldConfigFile, JPATH_ADMINISTRATOR . '/components/com_sh404sef/config/config.sef.php'); } // restore black/white lists $folder = $this->_preserveConfigFolder . 'sh404_upgrade_conf_security'; if (JFolder::exists($folder)) { $fileList = JFolder::files($folder); if (!empty($fileList)) { foreach ($fileList as $file) { if (JFile::exists(JPATH_ADMINISTRATOR . '/components/com_sh404sef/security/' . $file)) { JFile::delete(JPATH_ADMINISTRATOR . '/components/com_sh404sef/security/' . $file); } JFile::copy( $this->_preserveConfigFolder . 'sh404_upgrade_conf_security/' . $file, JPATH_ADMINISTRATOR . '/components/com_sh404sef/security/' . $file ); } } } // if upgrading rather than installing from scratch, or after an uninstall // we must not copy back saved configuration files and log files // as this would overwrite up to date current ones // note that above we restored main config file and // security data files becomes blank files come // with the extension, so they'll be deleted in any case // and we have to restore them $shouldRestore = $this->_shouldRestore(); if ($shouldRestore) { // restore log files $folder = $this->_preserveConfigFolder . 'sh404_upgrade_conf_logs'; if (JFolder::exists($folder)) { JFolder::copy($folder, JPATH_ROOT . '/logs/sh404sef', $path = '', $force = true); } // restore customized default params $oldCustomConfigFile = $this->_preserveConfigFolder . 'sh404_upgrade_conf_' . $this->_siteId . '.custom.php'; if (is_readable($oldCustomConfigFile) && filesize($oldCustomConfigFile) > 1000) { // update old config files from VALID_MOS check to _JEXEC $config = JFile::read($oldCustomConfigFile); if ($config && strpos($config, 'VALID_MOS') !== false) { $config = str_replace('VALID_MOS', '_JEXEC', $config); JFile::write($oldCustomConfigFile, $config); // write it back } if (JFile::exists(JPATH_ADMINISTRATOR . '/components/com_sh404sef/custom.sef.php')) { JFile::delete(JPATH_ADMINISTRATOR . '/components/com_sh404sef/custom.sef.php'); } $result = JFile::copy($oldCustomConfigFile, JPATH_ADMINISTRATOR . '/components/com_sh404sef/custom.sef.php'); } // read saved config $extFile = $this->_preserveConfigFolder . 'sh404_upgrade_conf' . '/com_sh404sef_' . $this->_siteId . '.php'; // remove previous if any if (JFile::exists($extFile)) { include_once $extFile; if (!empty($sh404sefConfig)) { // write it back into sh404sef config field try { $query = 'update ' . $db->qn('#__extensions') . ' set ' . $db->qn('params') . ' = ' . $db->q($sh404sefConfig) . ' where ' . $db->qn('type') . ' = ' . $db->q('component') . ' and ' . $db->qn('element') . ' = ' . $db->q('com_sh404sef'); $db->setQuery($query)->query(); } catch (\Exception $e) { JFactory::getApplication() ->enqueuemessage('Database error while restoring saved configuration. Config may be lost: ' . $e->getMessage()); } } } } // install plugins if (defined('SHLIB_ROOT_PATH')) { // trick of the day: we must fetch an instance of the db using the db helper // before installing the newest version of shLib system plugin. This will // force a decorated db instance to be created and stored, using the shlib // db class version that matches that of the shlib db helper class // As there was interface changes betwen shLib 0.1.x and 0.2.x, this prevents // "method not existing" errors when installing a newer version over an old one // make sure resource manager is available, we'll need it during plugins installs $shlDb = ShlDbHelper::getInstance(); $status = $this->_installPluginGroup('system'); } else { $this->_installPluginGroup('system'); // shLib is not installed yet, let's make it available to us if (!JFile::exists(JPATH_ROOT . '/plugins/system/shlib/shlib.php')) { JFactory::getApplication() ->enqueuemessage('shLib was not installed properly, cannot continue. Please try uninstalling and installing again'); return false; } require_once JPATH_ROOT . '/plugins/system/shlib/shlib.php'; $config = array('type' => 'system', 'name' => 'shlib', 'params' => ''); if (version_compare(JVERSION, '3', 'ge')) { $dispatcher = JEventDispatcher::getInstance(); } else { $dispatcher = JDispatcher::getInstance(); } $shLibPlugin = new plgSystemShlib($dispatcher, $config); $shLibPlugin->onAfterInitialise(); $status = true; } if (!$status) { JFactory::getApplication() ->enqueuemessage('There was an error installing one or more system plugins. Please try uninstalling and installing again'); return; } $status = $this->_installPluginGroup('sh404sefcore'); if (!$status) { JFactory::getApplication() ->enqueuemessage('There was an error installing one or more sh404SEF core plugins. Please try uninstalling and installing again'); return; } $status = $this->_installPluginGroup('installer'); if (!$status) { JFactory::getApplication() ->enqueuemessage('There was an error installing one or more sh404SEF installer plugins. Please try uninstalling and installing again'); return; } $status = $this->_installPluginGroup('sh404sefextplugins'); if (!$status) { JFactory::getApplication() ->enqueuemessage('There was an error installing one or more sh404SEF extension plugins. Please try uninstalling and installing again'); return; } // remove cpicon module, not needed anymore that we use Joomla updater // remove admin quick icon module $this->_saveDeleteModuleParams('mod_sh404sef_cpicon', $client = 1); if (JFile::exists(JPATH_ROOT . '/plugins/sh404sefcore/sh404sefofflinecode/sh404sefofflinecode.xml')) { $this->_saveDeletePluginParams('sh404sefofflinecode', 'sh404sefcore'); } // apply various DB updates $this->_createDBStructure(); $this->_updateDBStructure(); // now we insert the 404 error page into the database // from version 1.5.5, the default content of 404 page has been largely modified // to make use of the similar urls plugin (and potentially others) // so we want to make sure people will have the new version of the 404 error page $status = $this->_updateErrorPage(); if (!$status) { JFactory::getApplication() ->enqueuemessage('There was an error updating the 404 error page. You may have to set it up manually in sh404SEF configuration.'); } $status = $this->_updateAnalyticsAccount(); if (!$status) { JFactory::getApplication() ->enqueuemessage('There was an error updating the Google Analytics Web property ID. You may have to set it up manually in sh404SEF configuration.'); } $status = $this->_fixInvalidShurl(); if (!$status) { JFactory::getApplication() ->enqueuemessage('There was an error fixing some invalid shURLs in the database. Please check that no shURL is identical to one of your language codes ie /en, /fr, /de.'); } $status = $this->_transferCanonical(); if (!$status) { JFactory::getApplication() ->enqueuemessage('There was an error tranfering canonical links from the meta data table to the aliases table (new in version 4.12.0). Please take note of the full error message, double-check your canonicals, or try installing again.'); } $status = $this->_reorderAliases(); if (!$status) { JFactory::getApplication() ->enqueuemessage('There was an error when re-ordering aliases in the database. This should not prevent normal operation, but please take note of the full error message and try installing again.'); } // make sur permissions record are set straight $query = $db->getQuery(true); $query->select('rules'); $query->from('#__assets'); $query->where($db->qn('name') . '=' . $db->q('com_sh404sef')); $db->setQuery($query); $existingRules = $db->loadResult(); if (empty($existingRules) || $existingRules == '{}' || $existingRules == '[]') { // write valid default value into assets record $defaultRule = '{"core.admin":[],"core.manage":[],"core.create":[],"core.delete":[],"core.edit":[],"core.edit.state":[],"core.edit.own":[]}'; $query->update($db->qn('#__assets'))->set($db->qn('rules') . '=' . $db->q($defaultRule)) ->where($db->qn('name') . '=' . $db->q('com_sh404sef')); $db->setQuery($query)->query(); } // 4.7.0+ now using Joomla url rewriting setting $status = $this->updateSettings(); if (!$status) { JFactory::getApplication() ->enqueuemessage('There was an error transferring or updating settings. You may have to update sh404SEF or Joomla configuration manually'); } // message // decide on help file language $languageCode = Sh404sefHelperLanguage::getFamily(); $basePath = JPATH_ROOT . '/administrator/components/com_sh404sef/language/%s.postinstall.php'; // fall back to english if language readme does not exist jimport('joomla.filesystem.file'); if (!JFile::exists(sprintf($basePath, $languageCode))) { $languageCode = 'en'; } ob_start(); include sprintf($basePath, $languageCode); $postInstallMessage = ob_get_clean(); JFactory::getApplication()->enqueueMessage($postInstallMessage); } private function _determineUtf8mb4Support() { $db = JFactory::getDbo(); if (is_callable(array($db, 'hasUTF8mb4Support'))) { if ($db->hasUTF8mb4Support()) { $this->hasUtf8mb4Support = true; $this->charset = 'utf8mb4'; $this->collation = 'utf8mb4_unicode_ci'; } } if (!$this->hasUtf8mb4Support) { JFactory::getApplication()->enqueueMessage( 'MYSQL server does not provide support for UTF8 MB4 character set. Database tables will not be using it.', 'warning' ); } } private function updateSettings() { $app = JFactory::getApplication(); $j3 = version_compare(JVERSION, '3.0', 'ge'); // get current (installed) sh404SEF settings try { if (!class_exists('Sh404sefFactory')) { // not previously installed, do nothing; return true; } // get the pre-existing config, the one instantiated before // installation started $sh404SEFConfig = Sh404sefFactory::getConfig(); if (version_compare($sh404SEFConfig->version, '4.7.0', 'ge') || !$sh404SEFConfig->Enabled) { // already done, or not running, do nothing return true; } // installed and running, check/update Joomla config accordingly $joomlaUrlRewriting = (bool)($j3 ? $app->get('sef_rewrite') : $app->getCfg('sef_rewrite')); $sh404SEFUrlRewriting = (bool)$sh404SEFConfig->shRewriteMode; // opposite storage convention between Joomla and sh404SEF // so if settings are equal, then config is different if ($sh404SEFUrlRewriting == $joomlaUrlRewriting) { // different settings. sh404SEF is running and enabled, so sh404SEF setting // must replace the Joomla one $jConfig = new JConfig(); $jConfig = JArrayHelper::fromObject($jConfig); $writeConfig = new JRegistry(); $writeConfig->loadArray($jConfig); // replace Joomla config setting with ours $writeConfig->set('sef_rewrite', $sh404SEFUrlRewriting ? 0 : 1); // Set the configuration file path. $file = JPATH_CONFIGURATION . '/configuration.php'; // Get the new FTP credentials. $ftp = JClientHelper::getCredentials('ftp', true); // Attempt to make the file writeable if using FTP. if (!$ftp['enabled'] && JPath::isOwner($file) && !JPath::setPermissions($file, '0644')) { $app->enqueueMessage('Error: Joomla! configuration.php file is not writable.', 'notice'); } // Attempt to write the configuration file as a PHP class named JConfig. $configuration = $writeConfig->toString('PHP', array('class' => 'JConfig', 'closingtag' => false)); if (!JFile::write($file, $configuration)) { throw new RuntimeException('Error writing to Joomla! configuration.php file, maybe not writeable?'); } } } catch (\Exception $e) { $app->enqueueMessage($e->getMessage()); return false; } return true; } /** * Decide whether backed up params should be restore (and * plugins reinstalled). * This should happen only when the extension is NOT already * installed. Most of times, as we are using updagre install * that should not happen and we jst overwrite * but if user uninstalled the extension, we must restore * data saved when he uninstalled * */ private function _shouldRestore() { // IMPORTANT: the check is done once, and only once // as for later calls, the system plugin will have been installed // and thus the test will not be valid anymore static $restore = null; if (is_null($restore)) { // search for base xml file to decide if already installed $restore = !JFile::exists(JPATH_ROOT . '/plugins/system/sh404sef/sh404sef.xml'); } return $restore; } /** * Install all sh404sef plugins available in a given * group * * @param string $group name of group * * @return boolean, true if success * @throws Exception */ private function _installPluginGroup($group) { $app = JFactory::getApplication(); $sourcePath = JPATH_ADMINISTRATOR . '/components/com_sh404sef/plugins/' . $group; if (!JFolder::exists($sourcePath)) { $app->enqueueMessage('Trying to install empty plugin group: ' . $group); return true; } // if each plugin resides in its own subDir, we must iterate over all sub dirs $folderList = JFolder::folders($sourcePath); if (empty($folderList)) { $app->enqueueMessage('Trying to install empty plugin group, folder is empty: ' . $sourcePath); return true; } // process each plugin $errors = false; foreach ($folderList as $folder) { // install the plugin itself $status = $this->_installPlugin($group, $folder, $sourcePath); // set flag if an error happened, but keep installing // other plugins $errors = $errors || !$status; // also display status if (!$status) { $app->enqueueMessage('Error installing sh404sef plugin from ' . $folder); } } // return true if no error at all return $errors == false; } // V 1.2.4.t improved upgrading /** * Insert in the db the previously retrieved parameters for a plugin * including publication information. Also move files as required * * @param string $pluginFolder * @param string $pluginElement * @param $sourcePath * * @return bool * @throws Exception */ private function _installPlugin($pluginFolder, $pluginElement, $sourcePath) { if ($pluginFolder == 'system' && $pluginElement == 'shlib') { if (in_array('shlib', $this->_skipInstall)) { return true; } } $status = true; $app = JFactory::getApplication(); // in case of upgrade, don't touch settings by user try { $db = JFactory::getDbo(); $query = $db->getQuery(true); $query->select('extension_id')->from('#__extensions')->where($db->qn('type') . '=' . $db->q('plugin')) ->where($db->qn('element') . '=' . $db->q($pluginElement)) ->where($db->qn('folder') . '=' . $db->q($pluginFolder)); $db->setQuery($query); $pluginId = $db->loadResult(); } catch (\Exception $e) { $status = false; $app->enqueueMessage('Error reading pre-existing plugin record from db: ' . $pluginFolder . ' / ' . $pluginElement); return $status; } $overrides = empty($pluginId) ? array('ordering' => 10, 'enabled' => 1) : array(); // make sure main library is loaded first if (empty($pluginId) && $pluginElement == 'shlib') { $overrides['ordering'] = -100; } // 4.19.0: new default option for sharing buttons plugin: use static buttons // must not change buttons type if already installed and setup if (!empty($pluginId) && $pluginElement == 'sh404sefsocial' && $pluginFolder == 'sh404sefcore') { $extension = JTable::getInstance('Extension'); $extension->load($pluginId); $paramsJson = $extension->params; // create params object $paramsObject = new JRegistry(); $paramsObject->loadString($paramsJson); // set buttonTypes param to "native" $currentButtonTypes = $paramsObject->get('buttonsType'); if (empty($currentButtonTypes)) { $paramsObject->set('buttonsType', 'native'); // write back $extension->bind( array( 'params' => $paramsObject->toString() ) ); $status = $extension->store(); if (!$status) { $app->enqueueMessage('Error updating social sharing buttons options: ' . $extension->getError() . ' for ' . $pluginFolder . ' / ' . $pluginElement); } } } // use J! installer to fully install the plugin $installer = new JInstaller; $result = $installer->install($sourcePath . '/' . $pluginElement); if ($result) { $shouldRestore = $this->_shouldRestore(); if ($shouldRestore) { // read stored params from disk $saved = array(); $this->_getExtensionSavedParams($pluginFolder . '.' . $pluginElement, $saved); unset($saved['extension_id']); $overrides = array_merge($overrides, $saved); } // overrides data in extension table, possibly overriding some columns from saved data if (!empty($overrides)) { try { $query = $db->getQuery(true); $query->select('extension_id')->from('#__extensions')->where($db->qn('type') . '=' . $db->q('plugin')) ->where($db->qn('element') . '=' . $db->q($pluginElement)) ->where($db->qn('folder') . '=' . $db->q($pluginFolder)); $db->setQuery($query); $pluginId = $db->loadResult(); $error = $db->getErrorNum(); if (!empty($error)) { throw new Exception($db->getErrorMsg()); } if (!empty($pluginId)) { jimport('joomla.database.table.extension'); $extension = JTable::getInstance('Extension'); $extension->load($pluginId); $extension->bind($overrides); $status = $extension->store(); if (!$status) { $app->enqueueMessage('Error writing updated extension record: ' . $extension->getError() . ' for ' . $pluginFolder . ' / ' . $pluginElement); } } else { $app->enqueueMessage('Error updating plugin DB record: ' . $pluginFolder . ' / ' . $pluginElement); } } catch (\Exception $e) { $status = false; $app->enqueueMessage('Error: ' . $e->getMessage()); } } } else { $app->enqueueMessage('Error installing sh404sef plugin: ' . $pluginFolder . ' / ' . $pluginElement); $status = false; } return $status; } /** * Makes sure the shLib, wbamp (and sh404SEF) system * plugin is correct */ private function fixPluginsOrder() { try { // then make sure realtive order $this->ensurePluginsOrder('languagefilter', 'sh404sef') ->ensurePluginsOrder('shlib', 'sh404sef'); } catch (\Exception $e) { $app = JFactory::getApplication(); $app->enqueueMessage('Error fixing plugin order in database: ' . $e->getMessage() . '. Please ensure the Language filter plugin is located before the sh404SEF system plugin.'); return false; } return true; } private function ensurePluginsOrder($plugin1, $plugin2) { $order = $plugin1 . $plugin2; // Read current ordering $db = JFactory::getDbo(); $query = $db->getQuery(true); $query->select('*')->from('#__extensions')->where($db->qn('type') . '=' . $db->q('plugin')) ->where($db->qn('folder') . '=' . $db->q('system')) ->where($db->qn('element') . " in ('" . $plugin1 . "','" . $plugin2 . "')") ->order('ordering asc'); $db->setQuery($query); $plugins = $db->loadObjectList('element'); // if one of the plugin is not there, don't go further if (empty($plugins[$plugin1]) || empty($plugins[$plugin2])) { return $this; } $signature = array_reduce( $plugins, function ($carry, $item) { return $carry . $item->element; } ); if ($signature != $order || $plugins[$plugin2]->ordering == $plugins[$plugin1]->ordering) { // special case, same ordering if ($plugins[$plugin2]->ordering == $plugins[$plugin1]->ordering) { $plugins[$plugin1]->ordering += 1; } $query = $db->getQuery(true); // not in the right order, swap them $query->update($db->qn('#__extensions')) ->set($db->qn('ordering') . '=' . $db->q($plugins[$plugin2]->ordering)) ->where($db->qn('extension_id') . '=' . $db->q($plugins[$plugin1]->extension_id)); $db->setQuery($query) ->query(); $query = $db->getQuery(true); $query->update($db->qn('#__extensions')) ->set($db->qn('ordering') . '=' . $db->q($plugins[$plugin1]->ordering)) ->where($db->qn('extension_id') . '=' . $db->q($plugins[$plugin2]->extension_id)); $db->setQuery($query) ->query(); } return $this; } /** * Retrieves stored params of a given extension (module or plugin) * (as saved upon uninstall) * * @param string $extName the module name, including mod_ if a module * @param array $shConfig an array holding the database columns of the extension * @param array $shPub , an array holding the publication information of the module (only for modules) * * @return boolean, true if any stored parameters were found for this extension */ private function _getExtensionSavedParams($extName, &$shConfig, &$shPub = null, $useId = false) { static $fileList = array(); // prepare default return value $status = false; // read all file names in /media/sh404_upgrade_conf dir, for easier processing $baseFolder = $this->_preserveConfigFolder . 'sh404_upgrade_conf'; if (JFolder::exists($baseFolder) && (empty($fileList) || !isset($fileList[$extName]))) { $baseName = $extName . ($useId ? '_[0-9]{1,10}' : '') . '_' . $this->_siteId . '.php'; $fileList[$extName] = JFolder::files($baseFolder, $baseName); } // extract filename from list we've established previously $extFile = isset($fileList[$extName]) && $fileList[$extName] !== false ? array_shift($fileList[$extName]) : ''; if (empty($fileList[$extName])) { // prevent infinite loop $fileList[$extName] = false; } if (!empty($extFile) && JFile::exists($baseFolder . '/' . $extFile)) { $status = true; // operation was successful include($baseFolder . '/' . $extFile); } return $status; } /** * * utility functions * */ private function _installModule($module, $source, $extensionConfig, $moduleConfig) { $app = JFactory::getApplication(); $path = $source . '/admin/modules/' . $module; $installer = new JInstaller; $result = $installer->install($path); if ($result) { // if files moved to destination, setup module in Joomla database $shouldRestore = $this->_shouldRestore(); if ($shouldRestore) { // read stored params from disk $this->_getExtensionSavedParams($module . '_extension', $extensionConfig); } // update elements in db, only if we need to restore past configuration try { $db = JFactory::getDbo(); if (!empty($extensionConfig)) { // load module details from extension table //$moduleDetails = ShlDbHelper::selectAssoc('#__extensions', array('*'), array('type' => 'module', 'element' => $module)); $query = $db->getQuery(true); $query->select('*') ->from('#__extensions') ->where($db->qn('type') . '=' . $db->q('module')) ->where($db->qn('element') . '=' . $db->q($module)); $db->setQuery($query); $moduleDetails = $db->loadAssoc(); // merge with saved details and write back to disk $details = array_merge($moduleDetails, $extensionConfig); //ShlDbHelper::update('#__extensions', $details, array('extension_id' => (int) $moduleDetails['extension_id'])); $query = $db->getQuery(true); $query->update('#__extensions') ->where($db->qn('extension_id') . '=' . (int)$moduleDetails['extension_id']); foreach ($details as $key => $value) { $query->set($db->qn($key) . ' = ' . $db->q($value)); } $db->setQuery($query)->query(); } } catch (\Exception $e) { $app->enqueueMessage('Error: ' . $e->getMessage()); } if ($shouldRestore) { // read stored params from disk $this->_getExtensionSavedParams($module . '_modules', $moduleConfig); } // update elements in db, if we need to restore past configuration try { //$instanceDetails = ShlDbHelper::selectAssoc('#__modules', array('*'), array('module' => $module)); $query = $db->getQuery(true); $query->select('*') ->from('#__modules') ->where($db->qn('module') . '=' . $db->q($module)); $db->setQuery($query); $instanceDetails = $db->loadAssoc(); // merge with saved details and write back to disk $details = array_merge($instanceDetails, $moduleConfig); //ShlDbHelper::update('#__modules', $details, array('id' => (int) $instanceDetails['id'])); $query = $db->getQuery(true); $query->update('#__modules') ->where($db->qn('id') . '=' . (int)$instanceDetails['id']); foreach ($details as $key => $value) { $query->set($db->qn($key) . ' = ' . $db->q($value)); } $db->setQuery($query)->query(); } catch (\Exception $e) { $app->enqueueMessage('Error: ' . $e->getMessage()); } // and finally we make sure there is a menu item associated with the module $details = array('menuid' => 0); if ($shouldRestore) { // read stored params from disk $this->_getExtensionSavedParams($module . '_modules_menu', $details); } $details = array_merge($details, array('moduleid' => (int)$instanceDetails['id'])); // insert or update elements in db, if we need to restore past configuration try { //ShlDbHelper::insertUpdate('#__modules_menu', $details, array('moduleid' => (int) $instanceDetails['id'])); $query = $db->getQuery(true); $query->select("count(*)") ->from('#__modules_menu') ->where($db->qn('moduleid') . '=' . (int)$instanceDetails['id']); $db->setQuery($query); $found = $db->loadResult(); $query->clear(); if (empty($found)) { // insert $query->insert('#__modules_menu'); } else { // update $query->update('#__modules_menu') ->where($db->qn('moduleid') . '=' . (int)$instanceDetails['id']); } foreach ($details as $key => $value) { $query->set($db->qn($key) . ' = ' . $db->q($value)); } $db->setQuery($query)->query(); } catch (\Exception $e) { $app->enqueueMessage('Error: ' . $e->getMessage()); } } else { $app->enqueueMessage('Error installing sh404sef module: ' . $module); } return $result; } /** * As of 4.7.0, Analytics classic is removed, we only use Universal * Transfer settings accordingly */ private function _updateAnalyticsAccount() { if (!class_exists('Sh404sefFactory')) { // sh404SEF not running, no copying over of // accounts. If user disabled sh404SEF system plugin // we can't really detect that, but then they can // manually copy over the analytics configuration return true; } $config = Sh404sefFactory::getConfig(); try { $updated = false; $params = Sh404sefHelperGeneral::getComponentParams(); // select Universal if classic (or bot) was selected if (!empty($config->analyticsEdition) && ($config->analyticsEdition == 'ga' || $config->analyticsEdition == 'ga_and_uga')) { $params->set('analyticsEdition', 'uga'); $updated = true; } // if we had a Classic web propery ID, move to UGA, unless we // already have such ID if (!empty($config->analyticsId) && empty($config->analyticsUgaId)) { $params->set('analyticsUgaId', $config->analyticsId); $updated = true; } // if an if ($updated) { Sh404sefHelperGeneral::saveComponentParams($params); } } catch (\Exception $e) { $app = JFactory::getApplication(); $app->enqueueMessage('Error: ' . $e->getMessage()); return false; } return true; } /** * In 4.7.1 and 4.7.2, it may happen that shURL collides with language codes * on ML sites. */ private function _fixInvalidShurl() { if (!class_exists('Sh404sefFactory')) { // sh404SEF not running, do nothing // If user disabled sh404SEF system plugin // we can't really detect that, but then they can // manually copy over the analytics configuration return true; } try { // read all content languages, if any $languages = Sh404sefHelperLanguage::getInstalledLanguagesList(); // adjust to require format $langCodes = array(); if (!empty($languages)) { foreach ($languages as $language) { $langCodes[] = $language->shortcode; } } // search for shURLs that match any of them if (!empty($langCodes)) { ShlDbHelper::deleteIn('#__sh404sef_pageids', 'pageid', $langCodes); } } catch (\Exception $e) { $app = JFactory::getApplication(); $app->enqueueMessage('Error: ' . $e->getMessage()); return false; } return true; } /** * In 4.12.0, canonical are now a type of aliases, instead of being managed as meta data. We must transfer existing * canonical. * * @return bool * @throws Exception */ private function _transferCanonical() { if (!class_exists('Sh404sefFactory')) { // sh404SEF not running, do nothing // If user disabled sh404SEF system plugin // we can't really detect that. return true; } // at this stage, needs to load table object ourselves include_once sh404SEF_ADMIN_ABS_PATH . 'tables/aliases.php'; // re-include php_shortcuts, in case of installing over an older version // that may not have the latest version. include SHLIB_ROOT_PATH . 'system/php_shortcuts.php'; try { // are there any canonical in the meta table? $canonicals = ShlDbHelper::selectObjectList( '#__sh404sef_metas', '*', 'canonical != ""' ); $db = JFactory::getDbo(); // process canonicals if (!empty($canonicals)) { $alias = array( 'target_type' => 1 ); $root = JUri::root(); foreach ($canonicals as $canonical) { // insert in aliases table $alias['newurl'] = $canonical->canonical; $alias['alias'] = Sh404sefHelperGeneral::getSefFromNonSef($canonical->newurl); $alias['alias'] = wbLTrim($alias['alias'], $root); $alias['alias'] = wbLTrim($alias['alias'], 'administrator/'); $alias['target_type'] = 1; $aliasObject = new Sh404sefTableAliases($db); $aliasObject->bind( $alias ); $aliasObject->store(); // delete original ShlDbHelper::update( '#__sh404sef_metas', array( 'canonical' => '' ), array( 'id' => $canonical->id ) ); } } } catch (\Exception $e) { $app = JFactory::getApplication(); $app->enqueueMessage('Error: ' . $e->getMessage()); return false; } return true; } private function _reorderAliases() { try { // are there any unordered aliases? $unorderedAliasesCount = ShlDbHelper::count( '#__sh404sef_aliases', 'id', array( 'ordering' => 0 ) ); // if so, reorder them if (!empty($unorderedAliasesCount)) { include_once sh404SEF_ADMIN_ABS_PATH . 'tables/aliases.php'; $db = JFactory::getDbo(); // make sure aliases are properly ordered $aliasesTable = new Sh404sefTableAliases($db); $aliasesTable->reorder(); } } catch (\Exception $e) { $app = JFactory::getApplication(); $app->enqueueMessage('Error: ' . $e->getMessage()); return false; } return true; } /** * Transfer to our keystore customized pages created by user, if any. * Prior to 4.7.0, error pages were stored in regular Joomla articles. * * @param string $pageTitle * * @return bool|void * @throws Exception */ private function _updateErrorPage($pageTitle = '__404__') { if (!class_exists('Sh404sefFactory')) { // sh404SEF not running, no copying over of // error page. If user disabled sh404SEF system plugin // we can't really detect that, but then they can // manually copy over the error page(s) return true; } // do we already have a __404__ article? $config = Sh404sefFactory::getConfig(); try { $db = JFactory::getDbo(); $catid = $this->_getErrorPageCatId(); $pages = array(); if (!empty($this->_errorPageCatId)) { // we have cat id, try to read article (only the published ones) // unpublished will be processed manually $query = $db->getQuery(true); $query->select('*') ->from('#__content') ->where($db->qn('catid') . '=' . $catid) ->where($db->qn('title') . '=' . $db->q($pageTitle)) ->where($db->qn('state') . '= 1'); $db->setQuery($query); $pages = $db->loadObjectList(); } // if no pages had been created, go away // user may have renamed them for instance // manual operation needed or just do nothing if (empty($pages)) { return true; } // there were some pages, copy them into keystore $defaultLanguageTag = JComponentHelper::getParams('com_languages')->get('site', 'en-GB'); foreach ($pages as $page) { // "All" language page goes to default language record $currentLanguageTag = $page->language == '*' ? $defaultLanguageTag : $page->language; $storageKey = 'com_sh404sef.errors.404.' . $currentLanguageTag; // is there already such an item? $query = $db->getQuery(true); $query->select('*') ->from('#__sh404sef_keystore') ->where($db->qn('key') . '=' . $db->q($storageKey)); $db->setQuery($query); $storedPage = $db->loadObject(); if (!empty($storedPage)) { return; } // if none, insert $query = $db->getQuery(true); $query->insert($db->qn('#__sh404sef_keystore')); $query->set($db->qn('value') . '=' . $db->q(serialize($page->introtext))) ->set($db->qn('key') . '=' . $db->q($storageKey)) ->set($db->qn('user_id') . '=' . JFactory::getUser()->id) ->set($db->qn('format') . '= 0') ->set($db->qn('modified_at') . '=' . $db->q(JFactory::getDate()->format('Y-m-d H:i:s'))); $db->setQuery($query)->query(); // lastly, trash the article $query = $db->getQuery(true); $query->update($db->qn('#__content')) ->where($db->qn('id') . '=' . $db->q($page->id)) ->set($db->qn('state') . '= -2'); $db->setQuery($query)->query(); // was there a specific Itemid set? if (!empty($config->shPageNotFoundItemid)) { $params = Sh404sefHelperGeneral::getComponentParams(); $fieldName = 'languages_' . $currentLanguageTag . '_notFoundItemid'; $params->set($fieldName, $config->shPageNotFoundItemid); Sh404sefHelperGeneral::saveComponentParams($params); } } // and then trash the category $query = $db->getQuery(true); $query->update($db->qn('#__categories')) ->where($db->qn('id') . '=' . $db->q($this->_errorPageCatId)) ->set($db->qn('published') . '= -2'); $db->setQuery($query)->query(); return true; } catch (\Exception $e) { $app = JFactory::getApplication(); $app->enqueueMessage('Error: ' . $e->getMessage()); return false; } } private function _getErrorPageCatId() { $db = JFactory::getDbo(); $query = $db->getQuery(true); $query->select('id') ->from('#__categories') ->where($db->qn('parent_id') . '= 1') ->where($db->qn('extension') . '=' . $db->q('com_content')) ->where($db->qn('path') . '=' . $db->q('sh404sef-custom-content')) ->where($db->qn('level') . '= 1'); $db->setQuery($query); $this->_errorPageCatId = $db->loadResult(); // we have a category, all good return $this->_errorPageCatId; } private function _createDBStructure() { // get a db instance $this->_determineUtf8mb4Support(); $db = JFactory::getDBO(); $sqlQueries = array( "CREATE TABLE IF NOT EXISTS `#__sh404sef_urls` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `cpt` INT(11) NOT NULL DEFAULT '0', `rank` INT(11) NOT NULL DEFAULT '0', `oldurl` VARCHAR(2048) NOT NULL DEFAULT '', `newurl` VARCHAR(2048) NOT NULL DEFAULT '', `option` VARCHAR(255) NOT NULL DEFAULT '', `referrer_type` TINYINT(3) NOT NULL DEFAULT '0' COMMENT 'Used for 404, 0 = not set, 1 = external, 2 = internal', `dateadd` DATE NOT NULL DEFAULT '0000-00-00', `last_hit` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`), KEY `newurl` (`newurl` (190)), KEY `rank` (`rank`), KEY `oldurl` (`oldurl` (190)), KEY `last_hit` (`last_hit`) ) DEFAULT CHARSET=utf8;", "CREATE TABLE IF NOT EXISTS `#__sh404sef_metas` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `newurl` VARCHAR(2048) NOT NULL DEFAULT '', `metadesc` VARCHAR(512) CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT '', `metakey` VARCHAR(255) CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT '', `metatitle` VARCHAR(255) CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT '', `metalang` VARCHAR(30) DEFAULT '', `metarobots` VARCHAR(30) DEFAULT '', `canonical` VARCHAR(2048) DEFAULT '', `og_enable` TINYINT(3) NOT NULL DEFAULT '2', `og_type` VARCHAR(30) DEFAULT '', `og_image` VARCHAR(255) DEFAULT '', `og_enable_description` TINYINT(3) NOT NULL DEFAULT '2', `og_enable_site_name` TINYINT(3) NOT NULL DEFAULT '2', `og_site_name` VARCHAR(255) DEFAULT '', `fb_admin_ids` VARCHAR(255) DEFAULT '', `og_enable_location` TINYINT(3) NOT NULL DEFAULT '2', `og_latitude` VARCHAR(30) DEFAULT '', `og_longitude` VARCHAR(30) DEFAULT '', `og_street_address` VARCHAR(255) DEFAULT '', `og_locality` VARCHAR(255) DEFAULT '', `og_postal_code` VARCHAR(30) DEFAULT '', `og_region` VARCHAR(255) DEFAULT '', `og_country_name` VARCHAR(255) DEFAULT '', `og_enable_contact` TINYINT(3) NOT NULL DEFAULT '2', `og_email` VARCHAR(255) DEFAULT '', `og_phone_number` VARCHAR(255) DEFAULT '', `og_fax_number` VARCHAR(255) DEFAULT '', `og_enable_fb_admin_ids` TINYINT(3) NOT NULL DEFAULT '2', `twittercards_enable` TINYINT(3) NOT NULL DEFAULT '2', `twittercards_site_account` VARCHAR(100) DEFAULT '', `twittercards_creator_account` VARCHAR(100) DEFAULT '', `google_authorship_enable` TINYINT(3) NOT NULL DEFAULT '2', `google_authorship_author_profile` VARCHAR(255) DEFAULT '', `google_authorship_author_name` VARCHAR(255) DEFAULT '', `google_publisher_enable` TINYINT(3) NOT NULL DEFAULT '2', `google_publisher_url` VARCHAR(255) DEFAULT '', `og_custom_description` VARCHAR(512) CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT '', `raw_content_head_top` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT '', `raw_content_head_bottom` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT '', `raw_content_body_top` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT '', `raw_content_body_bottom` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT '', PRIMARY KEY (`id`), KEY `newurl` (`newurl` (190)) ) DEFAULT CHARSET=utf8;", "CREATE TABLE IF NOT EXISTS `#__sh404sef_aliases` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `newurl` VARCHAR(2048) NOT NULL DEFAULT '', `alias` VARCHAR(2048) NOT NULL DEFAULT '', `type` TINYINT(3) NOT NULL DEFAULT '0', `target_type` TINYINT(3) NOT NULL DEFAULT '0', `hits` INT(11) NOT NULL DEFAULT '0', `state` TINYINT(3) NOT NULL DEFAULT 1, `ordering` INT(11) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), KEY `newurl` (`newurl` (190)), KEY `alias` (`alias` (190)), KEY `type` (`type`), KEY `state` (`state`) ) DEFAULT CHARSET=utf8;", "CREATE TABLE IF NOT EXISTS `#__sh404sef_pageids` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `newurl` VARCHAR(2048) NOT NULL DEFAULT '', `pageid` VARCHAR(255) NOT NULL DEFAULT '', `type` TINYINT(3) NOT NULL DEFAULT '0', `hits` INT(11) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `newurl` (`newurl` (190)), KEY `alias` (`pageid` (190)), KEY `type` (`type`) ) DEFAULT CHARSET=" . $this->charset . ";", "CREATE TABLE IF NOT EXISTS `#__sh404sef_hits_shurls` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `url` VARCHAR(2048) NOT NULL DEFAULT '', `target` VARCHAR(2048) NOT NULL DEFAULT '', `target_domain` VARCHAR(191) NOT NULL DEFAULT '', `referrer` VARCHAR(2048) NOT NULL DEFAULT '', `referrer_domain` VARCHAR(191) NOT NULL DEFAULT '', `user_agent` VARCHAR(191) NOT NULL DEFAULT '', `ip_address` VARCHAR(50) NOT NULL DEFAULT '', `datetime` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', `type` TINYINT(3) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `url` (`url` (190)), KEY `referrer` (`referrer` (190)), KEY `user_agent` (`user_agent`), KEY `ip_address` (`ip_address`), KEY `type` (`type`) ) DEFAULT CHARSET=" . $this->charset . ";", "CREATE TABLE IF NOT EXISTS `#__sh404sef_hits_aliases` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `url` VARCHAR(2048) NOT NULL DEFAULT '', `target` VARCHAR(2048) NOT NULL DEFAULT '', `target_domain` VARCHAR(191) NOT NULL DEFAULT '', `referrer` VARCHAR(2048) NOT NULL DEFAULT '', `referrer_domain` VARCHAR(191) NOT NULL DEFAULT '', `user_agent` VARCHAR(191) NOT NULL DEFAULT '', `ip_address` VARCHAR(50) NOT NULL DEFAULT '', `datetime` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', `type` TINYINT(3) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `url` (`url` (190)), KEY `referrer` (`referrer` (190)), KEY `user_agent` (`user_agent`), KEY `ip_address` (`ip_address`), KEY `type` (`type`) ) DEFAULT CHARSET=" . $this->charset . ";", "CREATE TABLE IF NOT EXISTS `#__sh404sef_hits_404s` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `url` VARCHAR(2048) NOT NULL DEFAULT '', `target` VARCHAR(2048) NOT NULL DEFAULT '', `target_domain` VARCHAR(191) NOT NULL DEFAULT '', `referrer` VARCHAR(2048) NOT NULL DEFAULT '', `referrer_domain` VARCHAR(191) NOT NULL DEFAULT '', `user_agent` VARCHAR(191) NOT NULL DEFAULT '', `ip_address` VARCHAR(50) NOT NULL DEFAULT '', `datetime` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', `type` TINYINT(3) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `url` (`url` (190)), KEY `referrer` (`referrer` (190)), KEY `user_agent` (`user_agent`), KEY `ip_address` (`ip_address`), KEY `type` (`type`) ) DEFAULT CHARSET=" . $this->charset . ";", "CREATE TABLE IF NOT EXISTS `#__sh404sef_urls_src` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `url` VARCHAR(2048) NOT NULL DEFAULT '', `routed_url` VARCHAR(2048) NOT NULL DEFAULT '', `rank` INT(11) NOT NULL DEFAULT '0', `source_url` VARCHAR(2048) NOT NULL DEFAULT '', `source_routed_url` VARCHAR(2048) NOT NULL DEFAULT '', `trace` VARCHAR(7000) NOT NULL DEFAULT '', `datetime` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`), KEY `url` (`url` (190)), KEY `rank` (`rank`), KEY `routed_url` (`routed_url` (190)), KEY `source_url` (`source_url` (190)) ) DEFAULT CHARSET=" . $this->charset . ";", "CREATE TABLE IF NOT EXISTS `#__sh404sef_keystore` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `scope` VARCHAR(50) NOT NULL DEFAULT 'default', `key` VARCHAR(191) NOT NULL DEFAULT '', `value` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " NOT NULL, `user_id` INT NOT NULL DEFAULT 0, `format` TINYINT(3) NOT NULL DEFAULT 1, `modified_at` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`), KEY `main` (`scope`,`key`) ) ENGINE = InnoDB DEFAULT CHARSET=" . $this->charset . ";" ); foreach ($sqlQueries as $query) { try { $db->setQuery($query); $db->query(); $error = $db->getErrorNum(); if (!empty($error)) { throw new Exception($db->getErrorMsg()); } } catch (\Exception $e) { $app = JFactory::getApplication(); $app ->enqueueMessage( 'Error while creating the database : ' . $e->getMessage() . '. Sh404SEF will probably not operate properly. Please uninstall it, then try again after checking your database server setup. Contact us in case this happens again.' ); } } } /** * Performs update to db stucture on existing setups */ private function _updateDBStructure() { $this->_determineUtf8mb4Support(); // get a db instance $db = JFactory::getDBO(); $subQueries = array(); // when upgrading from older version, these values could be missing at the time of install defined('SH404SEF_OPTION_VALUE_NO') or define('SH404SEF_OPTION_VALUE_NO', 0); defined('SH404SEF_OPTION_VALUE_YES') or define('SH404SEF_OPTION_VALUE_YES', 1); defined('SH404SEF_OPTION_VALUE_USE_DEFAULT') or define('SH404SEF_OPTION_VALUE_USE_DEFAULT', 2); // ------------------------------------------------------------------------------ // #__sh404sef_urls // ------------------------------------------------------------------------------ $subqueries['#__sh404sef_urls'] = array(); if (method_exists($db, 'getTableFields')) { $columns = $db->getTableFields('#__sh404sef_urls'); $columns = empty($columns['#__sh404sef_urls']) ? array() : $columns['#__sh404sef_urls']; } else { $columns = $db->getTableColumns('#__sh404sef_urls'); } // 4.7.0 new columns for URLs table if (empty($columns['option'])) { $subQueries['#__sh404sef_urls'][] = "add `option` varchar(255) NOT NULL DEFAULT ''"; } if (empty($columns['referrer_type'])) { $subQueries['#__sh404sef_urls'][] = "add `referrer_type` tinyint(3) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_NO . "'"; } // upgrading to 4.7.0, we reset the hit counter of regular URLs. // previous counts may/will be wrong because they are the result of 404s // (for which hits were counted) turned into valid SEF (for which, up to now) // hits were not counted. // Thus we set to 0 all `cpt` fields for non-404 URLS (ie: automatic and custom). // of course, we must do this only once. We detect this condition by looking for // the referrer_type column in the table, which was introduced at the same time // as the hit counting feature if (empty($columns['referrer_type'])) { try { $query = 'update ' . $db->qn('#__sh404sef_urls') . ' set ' . $db->qn('cpt') . ' = 0' . ' where ' . $db->qn('newurl') . " <> ''"; $db->setQuery($query); $db->query(); $error = $db->getErrorNum(); if (!empty($error)) { throw new Exception($db->getErrorMsg()); } } catch (\Exception $e) { JFactory::getApplication() ->enqueueMessage( 'Error while upgrading the database : ' . $e->getMessage() . '. Sh404SEF will probably not operate properly. Please uninstall it, then try again after checking your database server setup. Contact us in case this happens again.' ); } } // 4.8.0 added last_hit column if (empty($columns['last_hit'])) { $subQueries['#__sh404sef_urls'][] = "add `last_hit` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00'"; $subQueries['#__sh404sef_urls'][] = "add index `last_hit` (`last_hit`)"; } // 4.13.3 - extend all URL fields to 2048 chars $subQueries['#__sh404sef_urls'][] = 'modify `oldurl` varchar(2048)'; $subQueries['#__sh404sef_urls'][] = 'DROP INDEX `oldurl`'; $subQueries['#__sh404sef_urls'][] = 'add index `oldurl` (`oldurl`(190))'; $subQueries['#__sh404sef_urls'][] = 'modify `newurl` varchar(2048)'; $subQueries['#__sh404sef_urls'][] = 'DROP INDEX `newurl`'; $subQueries['#__sh404sef_urls'][] = 'add index `newurl` (`newurl`(190))'; // ------------------------------------------------------------------------------ // #__sh404sef_metas // ------------------------------------------------------------------------------ // get list of columns // platform 12.1 if (method_exists($db, 'getTableFields')) { $columns = $db->getTableFields('#__sh404sef_metas'); $columns = empty($columns['#__sh404sef_metas']) ? array() : $columns['#__sh404sef_metas']; } else { $columns = $db->getTableColumns('#__sh404sef_metas'); } $subqueries['#__sh404sef_metas'] = array(); if (empty($columns['canonical'])) { $subQueries['#__sh404sef_metas'][] = "add `canonical` varchar(2048) default ''"; } if (empty($columns['og_enable'])) { $subQueries['#__sh404sef_metas'][] = "add `og_enable` tinyint(3) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_USE_DEFAULT . "'"; } if (empty($columns['og_type'])) { $subQueries['#__sh404sef_metas'][] = "add `og_type` varchar(30) default ''"; } if (empty($columns['og_image'])) { $subQueries['#__sh404sef_metas'][] = "add `og_image` varchar(255) default ''"; } if (empty($columns['og_enable_description'])) { $subQueries['#__sh404sef_metas'][] = "add `og_enable_description` tinyint(3) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_USE_DEFAULT . "'"; } if (empty($columns['og_enable_site_name'])) { $subQueries['#__sh404sef_metas'][] = "add `og_enable_site_name` tinyint(3) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_USE_DEFAULT . "'"; } if (empty($columns['og_site_name'])) { $subQueries['#__sh404sef_metas'][] = "add `og_site_name` varchar(255) default ''"; } if (empty($columns['fb_admin_ids'])) { $subQueries['#__sh404sef_metas'][] = "add `fb_admin_ids` varchar(255) default ''"; } if (empty($columns['og_enable_location'])) { $subQueries['#__sh404sef_metas'][] = "add `og_enable_location` tinyint(3) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_USE_DEFAULT . "'"; } if (empty($columns['og_latitude'])) { $subQueries['#__sh404sef_metas'][] = "add `og_latitude` varchar(30) default ''"; } if (empty($columns['og_longitude'])) { $subQueries['#__sh404sef_metas'][] = "add `og_longitude` varchar(30) default ''"; } if (empty($columns['og_street_address'])) { $subQueries['#__sh404sef_metas'][] = "add `og_street_address` varchar(255) default ''"; } if (empty($columns['og_locality'])) { $subQueries['#__sh404sef_metas'][] = "add `og_locality` varchar(255) default ''"; } if (empty($columns['og_postal_code'])) { $subQueries['#__sh404sef_metas'][] = "add `og_postal_code` varchar(30) default ''"; } if (empty($columns['og_region'])) { $subQueries['#__sh404sef_metas'][] = "add `og_region` varchar(255) default ''"; } if (empty($columns['og_country_name'])) { $subQueries['#__sh404sef_metas'][] = "add `og_country_name` varchar(255) default ''"; } if (empty($columns['og_enable_contact'])) { $subQueries['#__sh404sef_metas'][] = "add `og_enable_contact` tinyint(3) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_USE_DEFAULT . "'"; } if (empty($columns['og_email'])) { $subQueries['#__sh404sef_metas'][] = "add `og_email` varchar(255) default ''"; } if (empty($columns['og_phone_number'])) { $subQueries['#__sh404sef_metas'][] = "add `og_phone_number` varchar(255) default ''"; } if (empty($columns['og_fax_number'])) { $subQueries['#__sh404sef_metas'][] = "add `og_fax_number` varchar(255) default ''"; } if (empty($columns['og_enable_fb_admin_ids'])) { $subQueries['#__sh404sef_metas'][] = "add `og_enable_fb_admin_ids` tinyint(3) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_USE_DEFAULT . "'"; } // twitter cards if (empty($columns['twittercards_enable'])) { $subQueries['#__sh404sef_metas'][] = "add `twittercards_enable` tinyint(3) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_USE_DEFAULT . "'"; } if (empty($columns['twittercards_site_account'])) { $subQueries['#__sh404sef_metas'][] = "add `twittercards_site_account` varchar(100) default ''"; } if (empty($columns['twittercards_creator_account'])) { $subQueries['#__sh404sef_metas'][] = "add `twittercards_creator_account` varchar(100) default ''"; } // google authorship if (empty($columns['google_authorship_enable'])) { $subQueries['#__sh404sef_metas'][] = "add `google_authorship_enable` tinyint(3) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_USE_DEFAULT . "'"; } if (empty($columns['google_authorship_author_profile'])) { $subQueries['#__sh404sef_metas'][] = "add `google_authorship_author_profile` varchar(255) default ''"; } if (empty($columns['google_authorship_author_name'])) { $subQueries['#__sh404sef_metas'][] = "add `google_authorship_author_name` varchar(255) default ''"; } // google publisher if (empty($columns['google_publisher_enable'])) { $subQueries['#__sh404sef_metas'][] = "add `google_publisher_enable` tinyint(3) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_USE_DEFAULT . "'"; } if (empty($columns['google_publisher_url'])) { $subQueries['#__sh404sef_metas'][] = "add `google_publisher_url` varchar(255) default ''"; } // 4.10.1 allow utf8mb4 if ($this->hasUtf8mb4Support && class_exists('Sh404sefFactory') && version_compare(Sh404sefFactory::getConfig()->version, '4.10.1', 'lt')) { // updating $subQueries['#__sh404sef_metas'][] = 'modify `metatitle` varchar(255) CHARACTER SET ' . $this->charset . ' collate ' . $this->collation . ''; $subQueries['#__sh404sef_metas'][] = 'modify `metakey` varchar(255) CHARACTER SET ' . $this->charset . ' collate ' . $this->collation . ''; } // 4.13.0: expanded max meta description length from 255 to 512 chars $subQueries['#__sh404sef_metas'][] = 'modify `metadesc` varchar(512) CHARACTER SET ' . $this->charset . ' collate ' . $this->collation . ''; // 4.13.3 - extend all URL fields to 2048 chars $subQueries['#__sh404sef_metas'][] = 'modify `newurl` varchar(2048)'; $subQueries['#__sh404sef_metas'][] = 'DROP INDEX `newurl`'; $subQueries['#__sh404sef_metas'][] = 'add index `newurl` (`newurl`(190))'; // 4.17.1 - add custom OGP description if (empty($columns['og_custom_description'])) { $subQueries['#__sh404sef_metas'][] = "add `og_custom_description` varchar(512) CHARACTER SET " . $this->charset . " collate " . $this->collation . " default ''"; } else { $subQueries['#__sh404sef_metas'][] = "modify `og_custom_description` varchar(512) CHARACTER SET " . $this->charset . " collate " . $this->collation; } // add custom head/body raw content per URL if (empty($columns['raw_content_head_top'])) { $subQueries['#__sh404sef_metas'][] = "add `raw_content_head_top` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT ''"; $subQueries['#__sh404sef_metas'][] = "add `raw_content_head_bottom` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT ''"; $subQueries['#__sh404sef_metas'][] = "add `raw_content_body_top` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT ''"; $subQueries['#__sh404sef_metas'][] = "add `raw_content_body_bottom` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT ''"; } else { $subQueries['#__sh404sef_metas'][] = "modify `raw_content_head_top` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT ''"; $subQueries['#__sh404sef_metas'][] = "modify `raw_content_head_bottom` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT ''"; $subQueries['#__sh404sef_metas'][] = "modify `raw_content_body_top` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT ''"; $subQueries['#__sh404sef_metas'][] = "modify `raw_content_body_bottom` MEDIUMTEXT CHARACTER SET " . $this->charset . " COLLATE " . $this->collation . " DEFAULT ''"; } // ------------------------------------------------------------------------------ // #__sh404sef_aliases // ------------------------------------------------------------------------------ $subqueries['#__sh404sef_aliases'] = array(); if (method_exists($db, 'getTableFields')) { $columns = $db->getTableFields('#__sh404sef_aliases'); $columns = empty($columns['#__sh404sef_aliases']) ? array() : $columns['#__sh404sef_aliases']; } else { $columns = $db->getTableColumns('#__sh404sef_aliases'); } // some very old install don't have the 'type' or 'hits' columns in aliases table if (empty($columns['type'])) { $subQueries['#__sh404sef_aliases'][] = "add `type` tinyint(3) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_NO . "'"; $subQueries['#__sh404sef_aliases'][] = "add index `type` (`type`)"; } // hits type if (empty($columns['hits'])) { $subQueries['#__sh404sef_aliases'][] = "add `hits` int(11) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_NO . "'"; } // 4.12 if (empty($columns['target_type'])) { $subQueries['#__sh404sef_aliases'][] = "add `target_type` tinyint(3) NOT NULL DEFAULT '" . SH404SEF_OPTION_VALUE_NO . "'"; $subQueries['#__sh404sef_aliases'][] = "add index `target_type` (`target_type`)"; } if (empty($columns['state'])) { $subQueries['#__sh404sef_aliases'][] = "add `state` tinyint(3) NOT NULL DEFAULT 1"; $subQueries['#__sh404sef_aliases'][] = "add index `state` (`state`)"; } if (empty($columns['ordering'])) { $subQueries['#__sh404sef_aliases'][] = "add `ordering` int(11) NOT NULL DEFAULT 0"; } // 4.13.3 - extend all URL fields to 2048 chars $subQueries['#__sh404sef_aliases'][] = 'modify `newurl` varchar(2048)'; $subQueries['#__sh404sef_aliases'][] = 'DROP INDEX `newurl`'; $subQueries['#__sh404sef_aliases'][] = 'add index `newurl` (`newurl`(190))'; $subQueries['#__sh404sef_aliases'][] = 'modify `alias` varchar(2048)'; $subQueries['#__sh404sef_aliases'][] = 'DROP INDEX `alias`'; $subQueries['#__sh404sef_aliases'][] = 'add index `alias` (`alias`(190))'; // ------------------------------------------------------------------------------ // #__sh404sef_pageids // ------------------------------------------------------------------------------ $subQueries['#__sh404sef_pageids'] = array(); // 4.12.0 pageids/shurl allow external target, expand target URL column, but limit index if ($this->hasUtf8mb4Support && class_exists('Sh404sefFactory') && version_compare(Sh404sefFactory::getConfig()->version, '4.12.0', 'lt')) { $subQueries['#__sh404sef_pageids'][] = 'DROP INDEX `alias`'; $subQueries['#__sh404sef_pageids'][] = 'add index `alias` (`pageid`(190))'; } // 4.13.3 - extend all URL fields to 2048 chars $subQueries['#__sh404sef_pageids'][] = 'modify `newurl` varchar(2048)'; $subQueries['#__sh404sef_pageids'][] = 'DROP INDEX `newurl`'; $subQueries['#__sh404sef_pageids'][] = 'add index `newurl` (`newurl`(190))'; // ------------------------------------------------------------------------------ // #__sh404sef_hits_shurls // ------------------------------------------------------------------------------ $subQueries['#__sh404sef_hits_shurls'] = array(); // 4.13.3 - extend all URL fields to 2048 chars $subQueries['#__sh404sef_hits_shurls'] = array(); $subQueries['#__sh404sef_hits_shurls'][] = 'modify `url` varchar(2048)'; $subQueries['#__sh404sef_hits_shurls'][] = 'DROP INDEX `url`'; $subQueries['#__sh404sef_hits_shurls'][] = 'add index `url` (`url`(190))'; $subQueries['#__sh404sef_hits_shurls'][] = 'modify `target` varchar(2048)'; $subQueries['#__sh404sef_hits_shurls'][] = 'modify `referrer` varchar(2048)'; $subQueries['#__sh404sef_hits_shurls'][] = 'DROP INDEX `referrer`'; $subQueries['#__sh404sef_hits_shurls'][] = 'add index `referrer` (`referrer`(190))'; // ------------------------------------------------------------------------------ // #__sh404sef_hits_aliases // ------------------------------------------------------------------------------ $subQueries['#__sh404sef_hits_aliases'] = array(); // 4.13.3 - extend all URL fields to 2048 chars $subQueries['#__sh404sef_hits_aliases'] = array(); $subQueries['#__sh404sef_hits_aliases'][] = 'modify `url` varchar(2048)'; $subQueries['#__sh404sef_hits_aliases'][] = 'DROP INDEX `url`'; $subQueries['#__sh404sef_hits_aliases'][] = 'add index `url` (`url`(190))'; $subQueries['#__sh404sef_hits_aliases'][] = 'modify `target` varchar(2048)'; $subQueries['#__sh404sef_hits_aliases'][] = 'modify `referrer` varchar(2048)'; $subQueries['#__sh404sef_hits_aliases'][] = 'DROP INDEX `referrer`'; $subQueries['#__sh404sef_hits_aliases'][] = 'add index `referrer` (`referrer`(190))'; // ------------------------------------------------------------------------------ // #__sh404sef_hits_404s // ------------------------------------------------------------------------------ $subQueries['#__sh404sef_hits_404s'] = array(); // 4.13.3 - extend all URL fields to 2048 chars $subQueries['#__sh404sef_hits_404s'] = array(); $subQueries['#__sh404sef_hits_404s'][] = 'modify `url` varchar(2048)'; $subQueries['#__sh404sef_hits_404s'][] = 'DROP INDEX `url`'; $subQueries['#__sh404sef_hits_404s'][] = 'add index `url` (`url`(190))'; $subQueries['#__sh404sef_hits_404s'][] = 'modify `target` varchar(2048)'; $subQueries['#__sh404sef_hits_404s'][] = 'modify `referrer` varchar(2048)'; $subQueries['#__sh404sef_hits_404s'][] = 'DROP INDEX `referrer`'; $subQueries['#__sh404sef_hits_404s'][] = 'add index `referrer` (`referrer`(190))'; // ------------------------------------------------------------------------------ // #__sh404sef_urls_src // ------------------------------------------------------------------------------ if (method_exists($db, 'getTableFields')) { $columns = $db->getTableFields('#__sh404sef_urls_src'); $columns = empty($columns['#__sh404sef_urls_src']) ? array() : $columns['#__sh404sef_urls_src']; } else { $columns = $db->getTableColumns('#__sh404sef_urls_src'); } // 4.13.2 URL src also stores URL rank $subqueries['#__sh404sef_urls_src'] = array(); if (empty($columns['rank'])) { $subQueries['#__sh404sef_urls_src'][] = "add `rank` INT(11) NOT NULL DEFAULT '0'"; $subQueries['#__sh404sef_urls_src'][] = 'add index `rank` (`rank`)'; } // 4.13.3 - extend all URL fields to 2048 chars $subQueries['#__sh404sef_urls_src'][] = 'modify `url` varchar(2048)'; $subQueries['#__sh404sef_urls_src'][] = 'DROP INDEX `url`'; $subQueries['#__sh404sef_urls_src'][] = 'add index `url` (`url`(190))'; $subQueries['#__sh404sef_urls_src'][] = 'modify `routed_url` varchar(2048)'; $subQueries['#__sh404sef_urls_src'][] = 'DROP INDEX `routed_url`'; $subQueries['#__sh404sef_urls_src'][] = 'add index `routed_url` (`routed_url`(190))'; $subQueries['#__sh404sef_urls_src'][] = 'modify `source_url` varchar(2048)'; $subQueries['#__sh404sef_urls_src'][] = 'DROP INDEX `source_url`'; $subQueries['#__sh404sef_urls_src'][] = 'add index `source_url` (`source_url`(190))'; $subQueries['#__sh404sef_urls_src'][] = 'modify `source_routed_url` varchar(2048)'; $subQueries['#__sh404sef_urls_src'][] = 'modify `trace` varchar(7000)'; // ------------------------------------------------------------------------------ // apply changes // ------------------------------------------------------------------------------ if (!empty($subQueries)) { try { foreach ($subQueries as $table => $queries) { // aggregate sub-queries $queries = implode(', ', $queries); // prepend query $query = 'ALTER TABLE ' . $db->qn($table) . ' ' . $queries; // run query $db->setQuery($query); $db->query(); $error = $db->getErrorNum(); if (!empty($error)) { throw new Exception($db->getErrorMsg()); } } } catch (\Exception $e) { JFactory::getApplication() ->enqueueMessage( 'Error while upgrading the database : ' . $e->getMessage() . '. Sh404SEF will probably not operate properly. Please uninstall it, then try again after checking your database server setup. Contact us in case this happens again.' ); } } } /** * Make sure the update site is correct when switching from * one edition to another. * Specifically, wipe out update site when going from an * edition that does auto-update to one that does not * (ie community to full or lite) * * @param unknown $type * @param unknown $parent * * @return boolean */ private function _processUpdateSite($type, $parent) { // figure out the extension id try { //$extensionId = (int) ShlDbHelper::selectResult('#__extensions', array('extension_id'), // array('type' => 'component', 'element' => 'com_sh404sef')); $db = JFactory::getDbo(); $query = $db->getQuery(true); $query->select('extension_id') ->from('#__extensions') ->where($db->qn('type') . ' = ' . $db->q('component')) ->where($db->qn('element') . ' = ' . $db->q('com_sh404sef')); $db->setQuery($query); $extensionId = $db->loadResult(); } catch (\Exception $e) { $extensionId = 0; } // no update site. We must make sure we wipe out // any existing update site. We use Joomla code for that if (!empty($extensionId)) { JPluginHelper::importPlugin('extension'); if (version_compare(JVERSION, '3', 'ge')) { $dispatcher = JEventDispatcher::getInstance(); } else { $dispatcher = JDispatcher::getInstance(); } // Fire the onExtensionAfterInstall $result = null; $dispatcher->trigger('onExtensionAfterUninstall', array('installer' => clone $parent, 'eid' => $extensionId, 'result' => $result)); } return true; } }