File manager - Edit - /home/jardides/www/Jardi-design/images/administrator/osmylicensesmanager.tar
Back
library/Free/PluginHelper.php 0000644 00000007633 15247143460 0012217 0 ustar 00 <?php /** * @package ShackExtensionSupport * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2022 Joomlashack.com. All rights reserved * @license http://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackExtensionSupport. * * ShackExtensionSupport is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackExtensionSupport is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackExtensionSupport. If not, see <http://www.gnu.org/licenses/>. */ namespace Alledia\OSMyLicensesManager\Free; use Alledia\Framework\Joomla\Extension\Licensed; defined('_JEXEC') or die(); /** * PluginHelper class */ abstract class PluginHelper { /** * @var string */ protected static $downloadBaseURL = 'https://deploy.ostraining.com/client/download/'; /** * Update the license key on the plugin params * * @param ?string $licenseKeys * * @return bool */ public static function updateLicenseKeys(?string $licenseKeys = ''): bool { $licenseKeys = PluginHelper::sanitizeKey($licenseKeys); // Update the extension params $extension = new Licensed('osmylicensesmanager', 'plugin', 'system'); $extension->params->set('license-keys', $licenseKeys); $extension->storeParams(); return true; } /** * Detects if the passed URL is our download URL, returning a boolean value. * * @param string $url * * @return bool */ public static function isOurDownloadURL(string $url): bool { return preg_match('#^' . static::$downloadBaseURL . '#', $url) === 1; } /** * Removes the license key from the URL and returns it. * * @param string $url * * @return string */ public static function getURLWithoutLicenseKey(string $url): string { if (static::isOurDownloadURL($url)) { $url = preg_replace('#^(' . static::$downloadBaseURL . '(free|pro|paid)/[^/]+/[^/]+).*$#i', '$1', $url); $url .= '/'; } return $url; } /** * Sanitizes the license key, making sure we have only valid chars. * * @param string $key * * @return string */ public static function sanitizeKey(string $key): string { return preg_replace('/[^a-z0-9,]/i', '', $key); } /** * Appends the license key to the URL and returns it. We recognize the url * for designated generic extensions using a default license key to allow * legacy customers to download updates. * * @param string $url * @param string $keys * * @return string */ public static function appendLicenseKeyToURL(string $url, string $keys): string { if (static::isOurDownloadURL($url)) { $url = PluginHelper::getURLWithoutLicenseKey($url); $sanitizedKeys = static::sanitizeKey($keys); if ($keys) { $encodedKeys = base64_encode($sanitizedKeys); $url .= $encodedKeys; } } return $url; } /** * Detects the license type based on the URL. If no license is detected, * returns false * * @param string $url * * @return ?string */ public static function getLicenseTypeFromURL(string $url): ?string { if (preg_match('#^' . static::$downloadBaseURL . '(free|pro)/#', $url, $matches)) { return $matches[1]; } return null; } } library/Installer/include.php 0000644 00000002470 15247143460 0012312 0 ustar 00 <?php /** * @package ShackInstaller * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2023 Joomlashack.com. All rights reserved * @license https://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackInstaller. * * ShackInstaller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackInstaller is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>. */ use Alledia\Installer\AutoLoader; defined('_JEXEC') or die(); if (!defined('SHACK_INSTALLER_BASE')) { define('SHACK_INSTALLER_BASE', __DIR__); require_once SHACK_INSTALLER_BASE . '/AutoLoader.php'; } AutoLoader::register('Alledia\\Installer', __DIR__, true); if (!defined('SHACK_INSTALLER_VERSION')) { define('SHACK_INSTALLER_VERSION', '2.2.7'); define('SHACK_INSTALLER_COMPATIBLE', '2.2.7'); } library/Installer/Extension/Licensed.php 0000644 00000007223 15247143460 0014372 0 ustar 00 <?php /** * @package ShackInstaller * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2023 Joomlashack.com. All rights reserved * @license https://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackInstaller. * * ShackInstaller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackInstaller is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>. */ namespace Alledia\Installer\Extension; defined('_JEXEC') or die(); use Alledia\Installer\AutoLoader; /** * Licensed class, for extensions with Free and Pro versions */ class Licensed extends Generic { /** * License type: free or pro * * @var string */ protected $license = null; /** * The path for the pro library * * @var string */ protected $proLibraryPath = null; /** * The path for the free library * * @var string */ protected $libraryPath = null; /** * @inheritDoc */ public function __construct(string $namespace, string $type, ?string $folder = '', string $basePath = JPATH_SITE) { parent::__construct($namespace, $type, $folder, $basePath); $this->license = $this->manifest ? strtolower($this->manifest->alledia->license) : 'free'; $this->getLibraryPath(); $this->getProLibraryPath(); } /** * Check if the license is pro * * @return bool True for pro license */ public function isPro(): bool { return $this->license === 'pro'; } /** * Check if the license is free * * @return bool */ public function isFree(): bool { return !$this->isPro(); } /** * Get the path for the free library, based on the extension type * * @return string The path for pro */ public function getLibraryPath(): string { if (empty($this->libraryPath)) { $basePath = $this->getExtensionPath(); $this->libraryPath = $basePath . '/library'; } return $this->libraryPath; } /** * Get path for the pro library, based on the extension type * * @return string The path for pro */ public function getProLibraryPath(): string { if ($this->proLibraryPath === null) { $basePath = $this->getLibraryPath(); $this->proLibraryPath = $basePath . '/Pro'; } return $this->proLibraryPath; } /** * Loads the library, if existent (including the Pro Library) * * @return bool * @throws \Exception */ public function loadLibrary(): bool { $libraryPath = $this->getLibraryPath(); // If we have a library path, lets load it if (is_dir($libraryPath)) { if ($this->isPro()) { // Check if the pro library exists if (!is_dir($this->getProLibraryPath())) { throw new \Exception("Pro library not found: {$this->type}, {$this->element}"); } } AutoLoader::register('Alledia\\' . $this->namespace, $libraryPath); return true; } return false; } } library/Installer/Extension/Generic.php 0000644 00000025645 15247143460 0014230 0 ustar 00 <?php /** * @package ShackInstaller * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2023 Joomlashack.com. All rights reserved * @license https://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackInstaller. * * ShackInstaller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackInstaller is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>. */ namespace Alledia\Installer\Extension; defined('_JEXEC') or die(); use Joomla\CMS\Factory; use Joomla\Registry\Registry; /** * Generic extension class */ class Generic { /** * The extension namespace * * @var string */ protected $namespace = null; /** * The extension type * * @var string */ protected $type = null; /** * The extension id * * @var int */ protected $id = null; /** * The extension name * * @var string */ protected $name = null; /** * The extension params * * @var Registry */ public $params = null; /** * The extension enable state * * @var bool */ protected $enabled = null; /** * The element of the extension * * @var string */ protected $element = null; /** * @var string */ protected $folder = null; /** * Base path * * @var string */ protected $basePath = null; /** * The manifest information * * @var \SimpleXMLElement */ public $manifest = null; /** * The config.xml information * * @var \SimpleXMLElement */ public $config = null; /** * Class constructor, set the extension type. * * @param string $namespace The element of the extension * @param string $type The type of extension * @param ?string $folder The folder for plugins (only) * @param string $basePath * * @return void */ public function __construct(string $namespace, string $type, ?string $folder = '', string $basePath = JPATH_SITE) { $this->type = $type; $this->element = strtolower($namespace); $this->folder = $folder; $this->basePath = $basePath; $this->namespace = $namespace; $this->getManifest(); $this->getDataFromDatabase(); } /** * Get information about this extension from the database * NOTE: This is duplicated code from the corresponding class in * \Alledia\Framework\Joomla\Extension\Generic */ protected function getDataFromDatabase() { $element = $this->getElementToDb(); // Load the extension info from database $db = Factory::getDbo(); $query = $db->getQuery(true) ->select([ $db->quoteName('extension_id'), $db->quoteName('name'), $db->quoteName('enabled'), $db->quoteName('params') ]) ->from('#__extensions') ->where($db->quoteName('type') . ' = ' . $db->quote($this->type)) ->where($db->quoteName('element') . ' = ' . $db->quote($element)); if ($this->type === 'plugin') { $query->where($db->quoteName('folder') . ' = ' . $db->quote($this->folder)); } $db->setQuery($query); $row = $db->loadObject(); if (is_object($row)) { $this->id = $row->extension_id; $this->name = $row->name; $this->enabled = (bool)$row->enabled; $this->params = new Registry($row->params); } else { $this->id = null; $this->name = null; $this->enabled = false; $this->params = new Registry(); } } /** * Check if the extension is enabled * * @return bool */ public function isEnabled(): bool { return (bool)$this->enabled; } /** * Get the path for the extension * * @return string The path */ public function getExtensionPath(): string { $folders = [ 'component' => 'administrator/components/', 'plugin' => 'plugins/', 'template' => 'templates/', 'library' => 'libraries/', 'cli' => 'cli/', 'module' => 'modules/' ]; $basePath = $this->basePath . '/' . $folders[$this->type]; switch ($this->type) { case 'plugin': $basePath .= $this->folder . '/'; break; case 'module': if (!preg_match('/^mod_/', $this->element)) { $basePath .= 'mod_'; } break; case 'component': if (!preg_match('/^com_/', $this->element)) { $basePath .= 'com_'; } break; } $basePath .= $this->element; return $basePath; } /** * Get the full element * * @return string */ public function getFullElement(): string { $prefixes = [ 'component' => 'com', 'plugin' => 'plg', 'template' => 'tpl', 'library' => 'lib', 'cli' => 'cli', 'module' => 'mod' ]; $fullElement = $prefixes[$this->type]; if ($this->type === 'plugin') { $fullElement .= '_' . $this->folder; } $fullElement .= '_' . $this->element; return $fullElement; } /** * Get the element to match the database records. * Only components and modules have the prefix. * * @return string The element */ public function getElementToDb(): string { $prefixes = [ 'component' => 'com_', 'module' => 'mod_' ]; $fullElement = ''; if (array_key_exists($this->type, $prefixes)) { if (!preg_match('/^' . $prefixes[$this->type] . '/', $this->element)) { $fullElement = $prefixes[$this->type]; } } $fullElement .= $this->element; return $fullElement; } /** * Get manifest path for this extension * * @return string */ public function getManifestPath(): string { $extensionPath = $this->getExtensionPath(); switch ($this->type) { case 'template': $fileName = 'templateDetails.xml'; break; case 'library': $fileName = $this->element . '.xml'; if (!is_file($extensionPath . '/' . $fileName)) { $extensionPath = JPATH_MANIFESTS . '/libraries'; } break; case 'module': $fileName = 'mod_' . $this->element . '.xml'; break; case 'pkg': $extensionPath = JPATH_MANIFESTS . '/packages'; $fileName = 'pkg_' . $this->element . '.xml'; break; case 'file': $extensionPath = JPATH_MANIFESTS . '/files'; $fileName = 'file_' . $this->element . '.xml'; break; default: $fileName = $this->element . '.xml'; break; } return $extensionPath . '/' . $fileName; } /** * Get extension information * * @param bool $force If true, force to load the manifest, ignoring the cached one * * @return ?\SimpleXMLElement */ public function getManifest(bool $force = false): ?\SimpleXMLElement { if ($this->manifest === null || $force) { $this->manifest = false; $path = $this->getManifestPath(); if (is_file($path)) { $this->manifest = simplexml_load_file($path); } } return $this->manifest ?: null; } /** * Get extension config file * * @param bool $force Force to reload the config file * * @return \SimpleXMLElement */ public function getConfig(bool $force = false) { if ($this->config === null || $force) { $path = $this->getExtensionPath() . '/config.xml'; $this->config = is_file($path) ? simplexml_load_file($path) : false; } return $this->config; } /** * Returns the update URL from database * * @return string */ public function getUpdateURL(): string { $db = Factory::getDbo(); $query = $db->getQuery(true) ->select('sites.location') ->from('#__update_sites AS sites') ->leftJoin('#__update_sites_extensions AS extensions ON (sites.update_site_id = extensions.update_site_id)') ->where('extensions.extension_id = ' . $this->id); return $db->setQuery($query)->loadResult(); } /** * Set the update URL * * @param string $url */ public function setUpdateURL(string $url) { $db = Factory::getDbo(); // Get the update site id $join = $db->quoteName('#__update_sites_extensions') . ' AS extensions ' . 'ON (sites.update_site_id = extensions.update_site_id)'; $query = $db->getQuery(true) ->select('sites.update_site_id') ->from($db->quoteName('#__update_sites') . ' AS sites') ->leftJoin($join) ->where('extensions.extension_id = ' . $this->id); $db->setQuery($query); $siteId = (int)$db->loadResult(); if (!empty($siteId)) { $query = $db->getQuery(true) ->update($db->quoteName('#__update_sites')) ->set($db->quoteName('location') . ' = ' . $db->quote($url)) ->where($db->quoteName('update_site_id') . ' = ' . $siteId); $db->setQuery($query); $db->execute(); } } /** * Store the params on the database * * @return void */ public function storeParams() { $db = Factory::getDbo(); $params = $db->quote($this->params->toString()); $id = $db->quote($this->id); $query = "UPDATE `#__extensions` SET params = {$params} WHERE extension_id = {$id}"; $db->setQuery($query); $db->execute(); } /** * Get extension name * * @return string */ public function getName(): string { return $this->name; } } library/Installer/Loader.php 0000644 00000006127 15247143460 0012100 0 ustar 00 <?php /** * @package ShackInstaller * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2023 Joomlashack.com. All rights reserved * @license https://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackInstaller. * * ShackInstaller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackInstaller is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>. */ namespace Alledia\Installer; use Alledia\Framework\Factory; use Joomla\CMS\Log\Log; defined('_JEXEC') or die(); abstract class Loader { protected static $logRegistered = false; /** * Safely include a PHP file, making sure it exists before import. * * This method will register a log message and display a warning for admins * in case the file is missed. * * @param string $path The file path you want to include * * @return bool * @throws \Exception */ public static function includeFile(string $path): bool { if (!static::$logRegistered) { Log::addLogger( ['text_file' => 'shackframework.loader.errors.php'], Log::ALL, ['allediaframework'] ); static::$logRegistered = true; } // Check if the file doesn't exist if (!is_file($path)) { $logMsg = 'Required file is missed: ' . $path; // Generate a backtrace to know from where the request cames if (version_compare(phpversion(), '5.4', '<')) { $backtrace = debug_backtrace(); } else { $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); } if (!empty($backtrace)) { $logMsg .= sprintf( ' (%s:%s)', $backtrace[0]['file'], $backtrace[0]['line'] ); } // Register the log Log::add($logMsg, Log::ERROR, 'allediaframework'); // Warn admin users $app = Factory::getApplication(); if ($app->getName() == 'administrator') { $app->enqueueMessage( 'ShackInstaller Loader detected that a required file was not found! Please, check the logs.', 'error' ); } // Stand up a flag to warn a required file is missed if (!defined('SHACK_INSTALLER_MISSED_FILE')) { define('SHACK_INSTALLER_MISSED_FILE', true); } return false; } include_once $path; return true; } } library/Installer/AbstractScript.php 0000644 00000222465 15247143460 0013627 0 ustar 00 <?php /** * @package ShackInstaller * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2023 Joomlashack.com. All rights reserved * @license https://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackInstaller. * * ShackInstaller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackInstaller is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>. */ namespace Alledia\Installer; // phpcs:disable PSR1.Files.SideEffects defined('_JEXEC') or die(); use Alledia\Installer\Extension\Licensed; use JDatabaseDriver; use JEventDispatcher; use JFormFieldCustomFooter; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Application\CMSApplicationInterface; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\File; use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Installer\InstallerAdapter; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\BaseDatabaseModel; use Joomla\CMS\Table\Extension; use Joomla\CMS\Table\Table; use Joomla\CMS\Uri\Uri; use Joomla\CMS\Version; use Joomla\Component\Plugins\Administrator\Model\PluginModel; use Joomla\Event\DispatcherInterface; use Joomla\Registry\Registry; use SimpleXMLElement; use Throwable; require_once 'include.php'; // phpcs:enable PSR1.Files.SideEffects abstract class AbstractScript { public const VERSION = '2.2.7'; /** * Recognized installation types */ protected const TYPE_INSTALL = 'install'; protected const TYPE_DISCOVER_INSTALL = 'discover_install'; protected const TYPE_UPDATE = 'update'; protected const TYPE_UNINSTALL = 'uninstall'; /** * @var bool */ protected $outputAllowed = true; /** * @var CMSApplication */ protected $app = null; /** * @var JDatabaseDriver */ protected $dbo = null; /** * @var string */ protected $schemaVersion = null; /** * @var JEventDispatcher|DispatcherInterface */ protected $dispatcher = null; /** * @var Installer */ protected $installer = null; /** * @var SimpleXMLElement */ protected $manifest = null; /** * @var SimpleXMLElement */ protected $previousManifest = null; /** * @var string */ protected $mediaFolder = null; /** * @var string */ protected $element = null; /** * @var string[] */ protected $systemExtensions = [ 'library..allediaframework', 'plugin.system.osmylicensesmanager' ]; /** * @var bool */ protected $isLicensesManagerInstalled = false; /** * @var Licensed */ protected $license = null; /** * @var string */ protected $licenseKey = null; /** * @var string */ protected $footer = null; /** * @var string */ protected $mediaURL = null; /** * @var string[] * @deprecated v2.0.0 */ protected $messages = []; /** * @var string */ protected $type = null; /** * @var string */ protected $group = null; /** * List of tables and respective columns * * @var array */ protected $columns = null; /** * List of tables and respective indexes * * @var array * @deprecated v2.1.0 */ protected $indexes = null; /** * @var object[] */ protected $tableColumns = []; /** * @var object[] */ protected $tableIndexes = []; /** * @var object[] */ protected $tableConstraints = []; /** * @var array */ protected $tables = null; /** * Flag to cancel the installation * * @var bool */ protected $cancelInstallation = false; /** * Feedback of the install by related extension * * @var array */ protected $relatedExtensionFeedback = []; /** * @var string */ protected $welcomeMessage = null; /** * @var bool */ protected $debug = false; /** * @param InstallerAdapter $parent * * @return void * @throws \Exception */ public function __construct($parent) { $this->sendDebugMessage('ShackInstaller v' . static::VERSION); $this->sendDebugMessage('Base v' . SHACK_INSTALLER_VERSION); $this->sendDebugMessage(__METHOD__); $this->initProperties($parent); } /** * @param InstallerAdapter $parent * * @return bool * @throws \Exception */ protected function checkInheritance(InstallerAdapter $parent): bool { $parentClasses = class_parents($this); $scriptClassName = array_pop($parentClasses); $scriptClass = new \ReflectionClass($scriptClassName); $sourcePath = dirname($scriptClass->getFileName()); $sourceBase = strpos($sourcePath, JPATH_PLUGINS) === 0 ? 3 : 2; $sourceVersion = AbstractScript::VERSION ?? '0.0.0'; $sourcePath = $this->cleanPath($sourcePath); $targetPath = $this->cleanPath(SHACK_INSTALLER_BASE); if ($sourcePath != $targetPath && version_compare($sourceVersion, SHACK_INSTALLER_COMPATIBLE, 'lt')) { $source = join('/', array_slice(explode('/', $sourcePath), 0, $sourceBase)); $errorMessage = 'LIB_SHACKINSTALLER_ABORT_' . ($parent->getRoute() == 'uninstall' ? 'UNINSTALL' : 'INSTALL'); Factory::getApplication()->enqueueMessage(Text::sprintf($errorMessage, $source), 'error'); $this->cancelInstallation = true; return false; } return true; } /** * @param string $path * * @return string */ protected function cleanPath(string $path): string { return str_replace(DIRECTORY_SEPARATOR, '/', str_replace(JPATH_ROOT . '/', '', $path)); } /** * @param InstallerAdapter $parent * * @return void * @throws \Exception */ protected function initProperties($parent) { $this->sendDebugMessage(__METHOD__); $this->app = Factory::getApplication(); $this->outputAllowed = JPATH_BASE == JPATH_ADMINISTRATOR; $language = Factory::getLanguage(); $language->load('lib_shackinstaller.sys', realpath(__DIR__ . '/../..')); if ($this->checkInheritance($parent) == false) { return; } try { $this->dbo = Factory::getDbo(); $this->installer = $parent->getParent(); $this->manifest = $this->installer->getManifest(); $this->schemaVersion = $this->getSchemaVersion(); if ($media = $this->manifest->media) { $this->mediaFolder = JPATH_SITE . '/' . $media['folder'] . '/' . $media['destination']; } $attributes = $this->manifest->attributes(); $this->type = (string)$attributes['type']; $this->group = (string)$attributes['group']; // Get the previous manifest for use in upgrades $targetPath = $this->installer->getPath('extension_administrator') ?: $this->installer->getPath('extension_root'); $manifestPath = $targetPath . '/' . basename($this->installer->getPath('manifest')); if (is_file($manifestPath)) { $this->previousManifest = simplexml_load_file($manifestPath); } // Determine basepath for localized files $basePath = $this->installer->getPath('source'); if (is_dir($basePath)) { if ($this->type == 'component' && $basePath != $targetPath) { // For components sourced by manifest, need to find the admin folder if ($files = $this->manifest->administration->files) { if ($files = (string)$files['folder']) { $basePath .= '/' . $files; } } } } else { $basePath = $this->getExtensionPath( $this->type, (string)$this->manifest->alledia->element, $this->group ); } // All the files we want to load $languageFiles = [ $this->getFullElement() ]; // Load from localized or core language folder foreach ($languageFiles as $languageFile) { $language->load($languageFile, $basePath) || $language->load($languageFile, JPATH_ADMINISTRATOR); } } catch (Throwable $error) { $this->cancelInstallation = true; $this->sendErrorMessage($error); } } /** * @return JEventDispatcher|DispatcherInterface */ protected function getDispatcher() { if ($this->dispatcher === null) { if (Version::MAJOR_VERSION < 4) { $this->dispatcher = JEventDispatcher::getInstance(); } else { $this->dispatcher = $this->app->getDispatcher(); } } return $this->dispatcher; } /** * @param InstallerAdapter $parent * * @return bool */ public function install($parent) { try { return $this->customInstall($parent); } catch (Throwable $error) { $this->sendErrorMessage($error); } return false; } /** * @param InstallerAdapter $parent * * @return bool */ public function discover_install($parent) { try { if ($this->install($parent)) { return $this->customDiscoverInstall($parent); } } catch (Throwable $error) { $this->sendErrorMessage($error); } return false; } /** * @param InstallerAdapter $parent * * @return bool */ public function update($parent) { try { return $this->customUpdate($parent); } catch (Throwable $error) { $this->sendErrorMessage($error); } return false; } /** * @param string $type * @param InstallerAdapter $parent * * @return bool * @throws \Exception */ public function preFlight($type, $parent) { if ($this->cancelInstallation) { $this->sendDebugMessage('CANCEL: ' . __METHOD__); return false; } try { $this->sendDebugMessage(__METHOD__); $success = true; if ($type === 'update') { $this->clearUpdateServers(); } if (in_array($type, [static::TYPE_INSTALL, static::TYPE_UPDATE])) { // Check minimum target Joomla Platform if (isset($this->manifest->alledia->targetplatform)) { $targetPlatform = (string)$this->manifest->alledia->targetplatform; if ($this->validateTargetVersion(JVERSION, $targetPlatform) == false) { // Platform version is invalid. Displays a warning and cancel the install $targetPlatform = str_replace('*', 'x', $targetPlatform); $msg = Text::sprintf('LIB_SHACKINSTALLER_WRONG_PLATFORM', $this->getName(), $targetPlatform); $this->sendMessage($msg, 'warning'); $success = false; } } // Check for minimum mysql version if ($targetMySqlVersion = $this->manifest->alledia->mysqlminimum) { $targetMySqlVersion = (string)$targetMySqlVersion; if ($this->dbo->getServerType() == 'mysql') { $dbVersion = $this->dbo->getVersion(); if (stripos($dbVersion, 'maria') !== false) { // For MariaDB this is a bit of a punt. We'll assume any version of Maria will do $dbVersion = $targetMySqlVersion; } if ($this->validateTargetVersion($dbVersion, $targetMySqlVersion) == false) { // mySQL version too low $minimumMySql = str_replace('*', 'x', $targetMySqlVersion); $msg = Text::sprintf('LIB_SHACKINSTALLER_WRONG_MYSQL', $this->getName(), $minimumMySql); $this->sendMessage($msg, 'warning'); $success = false; } } } // Check for minimum php version if (isset($this->manifest->alledia->phpminimum)) { $targetPhpVersion = (string)$this->manifest->alledia->phpminimum; if ($this->validateTargetVersion(phpversion(), $targetPhpVersion) == false) { // php version is too low $minimumPhp = str_replace('*', 'x', $targetPhpVersion); $msg = Text::sprintf('LIB_SHACKINSTALLER_WRONG_PHP', $this->getName(), $minimumPhp); $this->sendMessage($msg, 'warning'); $success = false; } } // Check for minimum previous version $targetVersion = (string)$this->manifest->alledia->previousminimum; if ($type == static::TYPE_UPDATE && $targetVersion) { if (!$this->validatePreviousVersion($targetVersion)) { // Previous minimum is not installed $minimumVersion = str_replace('*', 'x', $targetVersion); $msg = Text::sprintf('LIB_SHACKINSTALLER_WRONG_PREVIOUS', $this->getName(), $minimumVersion); $this->sendMessage($msg, 'warning'); $success = false; } } } if ($success) { $success = $this->customPreFlight($type, $parent); } if ($success) { if ($type === static::TYPE_UPDATE) { $this->preserveFavicon(); } if ( $type !== static::TYPE_UNINSTALL && empty($this->manifest->alledia->obsolete->preflight) == false ) { $this->clearObsolete($this->manifest->alledia->obsolete->preflight); } } $this->cancelInstallation = !$success; return $success; } catch (Throwable $error) { $this->sendErrorMessage($error); } return false; } /** * @param string $type * @param InstallerAdapter $parent * * @return void * @throws \Exception */ public function postFlight($type, $parent) { $this->sendDebugMessage(__METHOD__); if ($this->cancelInstallation) { $this->sendMessage('LIB_SHACKINSTALLER_INSTALL_CANCELLED', 'warning'); return; } try { /* * Joomla 4 now calls postFlight on uninstalls. Which is kinda cool actually. * But this code is problematic in that scenario */ if ($type != static::TYPE_UNINSTALL) { $this->clearObsolete(); $this->installRelated(); $this->addAllediaAuthorshipToExtension(); $this->element = (string)$this->manifest->alledia->element; // Check and publish/reorder the plugin, if required if ( $this->type === 'plugin' && in_array($type, [static::TYPE_INSTALL, static::TYPE_DISCOVER_INSTALL]) ) { $this->publishThisPlugin(); $this->reorderThisPlugin(); } // If Free, remove any Pro library $license = $this->getLicense(); if (!$license->isPro()) { $proLibraryPath = $license->getProLibraryPath(); if (is_dir($proLibraryPath)) { Folder::delete($proLibraryPath); } } if ($type === static::TYPE_UPDATE) { $this->preserveFavicon(); } } $this->customPostFlight($type, $parent); if ($type != static::TYPE_UNINSTALL) { $this->displayWelcome($type); } } catch (Throwable $error) { $this->sendErrorMessage($error); } } /** * @param InstallerAdapter $parent * * @return void * @throws \Exception */ public function uninstall($parent) { $this->sendDebugMessage(__METHOD__); try { $this->uninstallRelated(); $this->customUninstall($parent); } catch (Throwable $error) { $this->sendErrorMessage($error); } } /** * For use in subclasses * * @param string $type * @param InstallerAdapter $parent * * @return bool * @throws Throwable */ protected function customPreFlight(string $type, InstallerAdapter $parent): bool { return true; } /** * For use in subclasses * * @param InstallerAdapter $parent * * @return bool * @throws Throwable */ protected function customInstall(InstallerAdapter $parent): bool { return true; } /** * For use in subclasses * * @param InstallerAdapter $parent * * @return bool * @throws Throwable */ protected function customDiscoverInstall(InstallerAdapter $parent): bool { return true; } /** * For use in subclasses * * @param InstallerAdapter $parent * * @return bool * @throws Throwable */ protected function customUpdate(InstallerAdapter $parent): bool { return true; } /** * For use in subclassses * * @param string $type * @param InstallerAdapter $parent * * @return void * @throws Throwable */ protected function customPostFlight(string $type, InstallerAdapter $parent) { } /** * For use in subclasses * * @param InstallerAdapter $parent * * @return void * @throws Throwable */ protected function customUninstall(InstallerAdapter $parent) { } /** * @return void * @throws \Exception */ final protected function installRelated() { $this->sendDebugMessage(__METHOD__); if ($this->manifest->alledia->relatedExtensions) { $source = $this->installer->getPath('source'); $extensionsPath = $source . '/extensions'; $defaultAttributes = $this->manifest->alledia->relatedExtensions->attributes(); $defaultDowngrade = $this->getXmlValue($defaultAttributes['downgrade'], 'bool'); $defaultPublish = $this->getXmlValue($defaultAttributes['publish'], 'bool'); foreach ($this->manifest->alledia->relatedExtensions->extension as $extension) { $path = $extensionsPath . '/' . $this->getXmlValue($extension); if (is_dir($path)) { $type = $this->getXmlValue($extension['type']); $element = $this->getXmlValue($extension['element']); $group = $this->getXmlValue($extension['group']); $key = md5(join(':', [$type, $element, $group])); if ($type == 'plugin' && in_array($group, ['search', 'finder'])) { if (is_dir(JPATH_ADMINISTRATOR . '/components/com_' . $group) == false) { // skip search/finder plugins based on installed components $this->sendDebugMessage( sprintf( 'Skipped/Uninstalled plugin %s', ucwords($group . ' ' . $element) ) ); $this->uninstallExtension($type, $element, $group); continue; } } $current = $this->findExtension($type, $element, $group); $isNew = empty($current); $typeName = ucwords(trim($group . ' ' . $type)); // Get data from the manifest $tmpInstaller = new Installer(); $tmpInstaller->setPath('source', $path); $tmpInstaller->setPath('parent', $this->installer->getPath('source')); $newManifest = $tmpInstaller->getManifest(); $newVersion = (string)$newManifest->version; $this->storeFeedbackForRelatedExtension($key, 'name', (string)$newManifest->name); $downgrade = $this->getXmlValue($extension['downgrade'], 'bool', $defaultDowngrade); if (!$isNew && !$downgrade) { $currentManifestPath = $this->getManifestPath($type, $element, $group); $currentManifest = $this->getInfoFromManifest($currentManifestPath); // Avoid to update for an outdated version $currentVersion = $currentManifest->get('version'); if (version_compare($currentVersion, $newVersion, '>')) { // Store the state of the install/update $this->storeFeedbackForRelatedExtension( $key, 'message', Text::sprintf( 'LIB_SHACKINSTALLER_RELATED_UPDATE_STATE_SKIPED', $newVersion, $currentVersion ) ); // Skip the install for this extension continue; } } $text = 'LIB_SHACKINSTALLER_RELATED_' . ($isNew ? 'INSTALL' : 'UPDATE'); if ($tmpInstaller->install($path)) { $this->sendMessage(Text::sprintf($text, $typeName, $element)); if ($isNew) { $current = $this->findExtension($type, $element, $group); if (is_object($current)) { if ($type === 'plugin') { if ($this->getXmlValue($extension['publish'], 'bool', $defaultPublish)) { $current->publish(); $this->storeFeedbackForRelatedExtension($key, 'publish', true); } if ($ordering = $this->getXmlValue($extension['ordering'])) { $this->setPluginOrder($current, $ordering); $this->storeFeedbackForRelatedExtension($key, 'ordering', $ordering); } } } } $this->storeFeedbackForRelatedExtension( $key, 'message', Text::sprintf('LIB_SHACKINSTALLER_RELATED_UPDATE_STATE_INSTALLED', $newVersion) ); } else { $this->sendMessage(Text::sprintf($text . '_FAIL', $typeName, $element), 'error'); $this->storeFeedbackForRelatedExtension( $key, 'message', Text::sprintf( 'LIB_SHACKINSTALLER_RELATED_UPDATE_STATE_FAILED', $newVersion ) ); } unset($tmpInstaller); } } } } /** * Uninstall the related extensions that are useless without the component * * @return void * @throws \Exception */ final protected function uninstallRelated() { if ($this->manifest->alledia->relatedExtensions) { $defaultAttributes = $this->manifest->alledia->relatedExtensions->attributes(); $defaultUninstall = $this->getXmlValue($defaultAttributes['uninstall'], 'bool'); foreach ($this->manifest->alledia->relatedExtensions->extension as $extension) { $type = $this->getXmlValue($extension['type']); $element = $this->getXmlValue($extension['element']); $group = $this->getXmlValue($extension['group']); $uninstall = $this->getXmlValue($extension['uninstall'], 'bool', $defaultUninstall); $systemExtension = in_array(join('.', [$type, $group, $element]), $this->systemExtensions); if ($uninstall && $systemExtension == false) { $this->uninstallExtension($type, $element, $group); } else { $message = 'LIB_SHACKINSTALLER_RELATED_NOT_UNINSTALLED' . ($systemExtension ? '_SYSTEM' : ''); if ($type == 'plugin') { $type = $group . ' ' . $type; } $this->sendDebugMessage(Text::sprintf($message, ucwords($type), $element)); } } } } /** * @param string $type * @param string $element * @param ?string $group * * @return void * @throws \Exception */ final protected function uninstallExtension(string $type, string $element, ?string $group = null) { if ($extension = $this->findExtension($type, $element, $group)) { $installer = new Installer(); $success = $installer->uninstall($extension->get('type'), $extension->get('extension_id')); $msg = 'LIB_SHACKINSTALLER_RELATED_UNINSTALL' . ($success ? '' : '_FAIL'); if ($type == 'plugin') { $type = $group . ' ' . $type; } $this->sendMessage( Text::sprintf($msg, ucwords($type), $element), $success ? 'message' : 'error' ); } } /** * @param ?string $type * @param ?string $element * @param ?string $group * * @return ?Extension * @throws \Exception */ final protected function findExtension(?string $type, ?string $element, ?string $group = null): ?Extension { // @TODO: Why do we need to use JTable? /** @var Extension $row */ $row = \JTable::getInstance('extension'); $prefixes = [ 'component' => 'com_', 'module' => 'mod_' ]; // Fix the element, if the prefix is not found if (array_key_exists($type, $prefixes)) { if (substr_count($element, $prefixes[$type]) === 0) { $element = $prefixes[$type] . $element; } } // Fix the element for templates if ($type == 'template') { $element = str_replace('tpl_', '', $element); } $terms = [ 'type' => $type, 'element' => $element ]; if ($type === 'plugin') { $terms['folder'] = $group; } $eid = $row->find($terms); if ($eid) { if ($row->load($eid) == false) { throw new \Exception($row->getError()); } return $row; } return null; } /** * Set requested ordering for selected plugin extension * Accepted ordering arguments: * (n<=1 | first) First within folder * (* | last) Last within folder * (before:element) Before the named plugin * (after:element) After the named plugin * * @param Extension $extension * @param string $order * * @return void */ final protected function setPluginOrder($extension, $order) { if ($extension->get('type') == 'plugin' && empty($order) == false) { $db = $this->dbo; $query = $db->getQuery(true); $query->select('extension_id, element'); $query->from('#__extensions'); $query->where([ $db->quoteName('folder') . ' = ' . $db->quote($extension->get('folder')), $db->quoteName('type') . ' = ' . $db->quote($extension->get('type')) ]); $query->order($db->quoteName('ordering')); $plugins = $db->setQuery($query)->loadObjectList('element'); // Set the order only if plugin already successfully installed if (array_key_exists($extension->get('element'), $plugins)) { $target = [ $extension->get('element') => $plugins[$extension->get('element')] ]; $others = array_diff_key($plugins, $target); if ((is_numeric($order) && $order <= 1) || $order == 'first') { // First in order $neworder = array_merge($target, $others); } elseif (($order == '*') || ($order == 'last')) { // Last in order $neworder = array_merge($others, $target); } elseif (preg_match('/^(before|after):(\S+)$/', $order, $match)) { // place before or after named plugin $place = $match[1]; $element = $match[2]; $neworder = []; $previous = ''; foreach ($others as $plugin) { if ( (($place == 'before') && ($plugin->element == $element)) || (($place == 'after') && ($previous == $element)) ) { $neworder = array_merge($neworder, $target); } $neworder[$plugin->element] = $plugin; $previous = $plugin->element; } if (count($neworder) < count($plugins)) { // Make it last if the requested plugin isn't installed $neworder = array_merge($neworder, $target); } } else { $neworder = []; } if (count($neworder) == count($plugins)) { // Only reorder if have a validated new order BaseDatabaseModel::addIncludePath( JPATH_ADMINISTRATOR . '/components/com_plugins/models', 'PluginsModels' ); // @TODO: Model class is (\PluginsModelPlugin) in J3 but this works either way /** @var PluginModel $model */ $model = BaseDatabaseModel::getInstance('Plugin', 'PluginsModel'); $ids = []; foreach ($neworder as $plugin) { $ids[] = $plugin->extension_id; } $order = range(1, count($ids)); $model->saveorder($ids, $order); } } } } /** * Add a message to the message list * * @param string $message * @param string $type * * @return void * @deprecated v2.0.0: use $this->sendMessage() */ final protected function setMessage($message, $type = 'message') { $this->sendMessage($message, $type); } /** * Display queued messages * * @return void * @deprecated v2.0.0: use $this->sendMessage() */ final protected function showMessages() { if ($this->messages) { foreach ($this->messages as $msg) { $text = $msg[0] ?? null; $type = $msg[1] ?? null; if ($text) { $this->sendMessage($text, $type); } } $this->messages = []; } } /** * Delete obsolete files, folders and extensions. * Files and folders are identified from the site * root path. * * @return void * @throws \Exception */ final protected function clearObsolete(SimpleXMLElement $obsolete = null) { $obsolete = $obsolete ?: $this->manifest->alledia->obsolete; $this->sendDebugMessage(__METHOD__ . '<pre>' . print_r($obsolete, 1) . '</pre>'); if ($obsolete) { if ($obsolete->extension) { foreach ($obsolete->extension as $extension) { $type = $this->getXmlValue($extension['type']); $element = $this->getXmlValue($extension['element']); $group = $this->getXmlValue($extension['group']); $current = $this->findExtension($type, $element, $group); if (empty($current) == false) { // Try to uninstall $tmpInstaller = new Installer(); $uninstalled = $tmpInstaller->uninstall($type, $current->get('extension_id')); $typeName = ucfirst(trim(($group ?: '') . ' ' . $type)); if ($uninstalled) { $this->sendMessage( Text::sprintf( 'LIB_SHACKINSTALLER_OBSOLETE_UNINSTALLED_SUCCESS', strtolower($typeName), $element ) ); } else { $this->sendMessage( Text::sprintf( 'LIB_SHACKINSTALLER_OBSOLETE_UNINSTALLED_FAIL', strtolower($typeName), $element ), 'error' ); } } } } if ($obsolete->file) { foreach ($obsolete->file as $file) { $path = JPATH_ROOT . '/' . trim((string)$file, '/'); if (is_file($path)) { File::delete($path); } } } if ($obsolete->folder) { foreach ($obsolete->folder as $folder) { $path = JPATH_ROOT . '/' . trim((string)$folder, '/'); if (is_dir($path)) { Folder::delete($path); } } } } $oldLanguageFiles = Folder::files(JPATH_ADMINISTRATOR . '/language', '\.lib_allediainstaller\.', true, true); foreach ($oldLanguageFiles as $oldLanguageFile) { File::delete($oldLanguageFile); } } /** * Finds the extension row for the main extension * * @return ?Extension * @throws \Exception */ final protected function findThisExtension(): ?Extension { return $this->findExtension( $this->getXmlValue($this->manifest['type']), $this->getXmlValue($this->manifest->alledia->element), $this->getXmlValue($this->manifest['group']) ); } /** * Use this in preflight to clear out obsolete update servers when the url has changed. * * @return void * @throws \Exception */ final protected function clearUpdateServers() { if ($extension = $this->findThisExtension()) { $db = $this->dbo; $query = $db->getQuery(true) ->select($db->quoteName('update_site_id')) ->from($db->quoteName('#__update_sites_extensions')) ->where($db->quoteName('extension_id') . '=' . (int)$extension->get('extension_id')); if ($list = $db->setQuery($query)->loadColumn()) { $query = $db->getQuery(true) ->delete($db->quoteName('#__update_sites_extensions')) ->where($db->quoteName('extension_id') . '=' . (int)$extension->get('extension_id')); $db->setQuery($query)->execute(); array_walk($list, 'intval'); $query = $db->getQuery(true) ->delete($db->quoteName('#__update_sites')) ->where($db->quoteName('update_site_id') . ' IN (' . join(',', $list) . ')'); $db->setQuery($query)->execute(); } } } /** * Get the full element, like com_myextension, lib_extension * * @param ?string $type * @param ?string $element * @param ?string $group * * @return string */ final protected function getFullElement($type = null, $element = null, $group = null) { $prefixes = [ 'component' => 'com', 'plugin' => 'plg', 'template' => 'tpl', 'library' => 'lib', 'cli' => 'cli', 'module' => 'mod', 'file' => 'file' ]; $type = $type ?: $this->type; $element = $element ?: (string)$this->manifest->alledia->element; $group = $group ?: $this->group; $fullElement = $prefixes[$type] . '_'; if ($type === 'plugin') { $fullElement .= $group . '_'; } return $fullElement . $element; } /** * @return Licensed */ final protected function getLicense() { if ($this->license === null) { $this->license = new Licensed( (string)$this->manifest->alledia->namespace, $this->type, $this->group ); } return $this->license; } /** * @param string $manifestPath * * @return Registry */ final protected function getInfoFromManifest($manifestPath) { $info = new Registry(); if (is_file($manifestPath)) { $xml = simplexml_load_file($manifestPath); $attributes = (array)$xml->attributes(); $attributes = $attributes['@attributes']; foreach ($attributes as $attribute => $value) { $info->set($attribute, $value); } foreach ($xml->children() as $e) { if (!$e->children()) { $info->set($e->getName(), (string)$e); } } } else { $relativePath = str_replace(JPATH_SITE . '/', '', $manifestPath); $this->sendMessage( Text::sprintf('LIB_SHACKINSTALLER_MANIFEST_NOT_FOUND', $relativePath), 'error' ); } return $info; } /** * @param string $type * @param string $element * @param ?string $group * * @return string */ final protected function getExtensionPath($type, $element, $group = '') { $folders = [ 'component' => 'administrator/components/', 'plugin' => 'plugins/', 'template' => 'templates/', 'library' => 'libraries/', 'cli' => 'cli/', 'module' => 'modules/', 'file' => 'administrator/manifests/files/' ]; $basePath = JPATH_SITE . '/' . $folders[$type]; switch ($type) { case 'plugin': $basePath .= $group . '/'; break; case 'module': if (!preg_match('/^mod_/', $element)) { $basePath .= 'mod_'; } break; case 'component': if (!preg_match('/^com_/', $element)) { $basePath .= 'com_'; } break; case 'template': if (preg_match('/^tpl_/', $element)) { $element = str_replace('tpl_', '', $element); } break; } if ($type !== 'file') { $basePath .= $element; } return $basePath; } /** * @param string $type * @param string $element * @param ?string $group * * @return int */ final protected function getExtensionId(string $type, string $element, ?string $group = ''): int { $db = $this->dbo; $query = $db->getQuery(true) ->select('extension_id') ->from('#__extensions') ->where([ $db->quoteName('element') . ' = ' . $db->quote($element), $db->quoteName('folder') . ' = ' . $db->quote($group), $db->quoteName('type') . ' = ' . $db->quote($type) ]); $db->setQuery($query); return (int)$db->loadResult(); } /** * Get the path for the manifest file * * @return string The path */ final protected function getManifestPath($type, $element, $group = '') { $installer = new Installer(); switch ($type) { case 'library': case 'file': $folders = [ 'library' => 'libraries', 'file' => 'files' ]; $manifestPath = JPATH_SITE . '/administrator/manifests/' . $folders[$type] . '/' . $element . '.xml'; if (!file_exists($manifestPath) || !$installer->isManifest($manifestPath)) { $manifestPath = false; } break; default: $basePath = $this->getExtensionPath($type, $element, $group); $installer->setPath('source', $basePath); $installer->getManifest(); $manifestPath = $installer->getPath('manifest'); break; } return $manifestPath; } /** * Check if it needs to publish the extension * * @return void * @throws \Exception */ final protected function publishThisPlugin() { $attributes = $this->manifest->alledia->element->attributes(); $publish = (string)$attributes['publish']; if ($publish === 'true' || $publish === '1') { $extension = $this->findThisExtension(); $extension->publish(); } } /** * Check if it needs to reorder the extension * * @return void * @throws \Exception */ final protected function reorderThisPlugin() { $attributes = $this->manifest->alledia->element->attributes(); $ordering = (string)$attributes['ordering']; if ($ordering !== '') { $extension = $this->findThisExtension(); $this->setPluginOrder($extension, $ordering); } } /** * Stores feedback data for related extensions to display after install * * @param string $key * @param string $property * @param string $value * * @return void */ final protected function storeFeedbackForRelatedExtension(string $key, string $property, string $value) { $this->sendDebugMessage(sprintf( '%s<br>**** %s-%s-%s<br><br>', __METHOD__, $key, $property, $value )); if (empty($this->relatedExtensionFeedback[$key])) { $this->relatedExtensionFeedback[$key] = []; } $this->relatedExtensionFeedback[$key][$property] = $value; } /** * This method add a mark to the extensions, allowing to detect our extensions * on the extensions table. * * @return void * @throws \Exception */ final protected function addAllediaAuthorshipToExtension() { if ($extension = $this->findThisExtension()) { $db = $this->dbo; // Update the extension $customData = json_decode($extension->get('custom_data')) ?: (object)[]; $customData->author = 'Joomlashack'; $query = $db->getQuery(true) ->update($db->quoteName('#__extensions')) ->set($db->quoteName('custom_data') . '=' . $db->quote(json_encode($customData))) ->where($db->quoteName('extension_id') . '=' . (int)$extension->get('extension_id')); $db->setQuery($query)->execute(); // Update the Alledia framework // @TODO: remove this after libraries be able to have a custom install script $query = $db->getQuery(true) ->update($db->quoteName('#__extensions')) ->set($db->quoteName('custom_data') . '=' . $db->quote('{"author":"Joomlashack"}')) ->where([ $db->quoteName('type') . '=' . $db->quote('library'), $db->quoteName('element') . '=' . $db->quote('allediaframework') ]); $db->setQuery($query)->execute(); } } /** * Add styles to the output. Used because when the postFlight * method is called, we can't add stylesheets to the head. * * @param mixed $stylesheets */ final protected function addStyle($stylesheets) { if (is_string($stylesheets)) { $stylesheets = [$stylesheets]; } foreach ($stylesheets as $path) { if (file_exists($path)) { $style = file_get_contents($path); echo '<style>' . $style . '</style>'; } } } /** * On new component install, this will check and fix any menus * that may have been created in a previous installation. * * @return void * @throws \Exception */ final protected function fixMenus() { if ($this->type == 'component') { $db = $this->dbo; if ($extension = $this->findThisExtension()) { $id = $extension->get('extension_id'); $option = $extension->get('name'); $query = $db->getQuery(true) ->update('#__menu') ->set('component_id = ' . $db->quote($id)) ->where([ 'type = ' . $db->quote('component'), 'link LIKE ' . $db->quote("%option={$option}%") ]); $db->setQuery($query)->execute(); // Check hidden admin menu option // @TODO: Remove after Joomla! incorporates this natively $menuElement = $this->manifest->administration->menu; if (in_array((string)$menuElement['hidden'], ['true', 'hidden'])) { $menu = Table::getInstance('Menu'); $menu->load(['component_id' => $id, 'client_id' => 1]); if ($menu->id) { $menu->delete(); } } } } } /** * Get and store a cache of columns of a table * * @param string $table The table name * * @return string[] * @deprecated v2.1.0: Use $this->findColumn() */ final protected function getColumnsFromTable($table) { if (!isset($this->columns[$table])) { $db = $this->dbo; $db->setQuery('SHOW COLUMNS FROM ' . $db->quoteName($table)); $rows = $db->loadObjectList(); $columns = []; foreach ($rows as $row) { $columns[] = $row->Field; } $this->columns[$table] = $columns; } return $this->columns[$table]; } /** * Get and store a cache of indexes of a table * * @param string $table The table name * * @return string[] * @deprecated v2.1.0: use $this->findIndex() */ final protected function getIndexesFromTable($table) { if (!isset($this->indexes[$table])) { $db = $this->dbo; $db->setQuery('SHOW INDEX FROM ' . $db->quoteName($table)); $rows = $db->loadObjectList(); $indexes = []; foreach ($rows as $row) { $indexes[] = $row->Key_name; } $this->indexes[$table] = $indexes; } return $this->indexes[$table]; } /** * Add columns to a table if they doesn't exists * * @param string $table The table name * @param string[] $columns Assoc array of columnNames => definition * * @return void * @deprecated v2.1.0: Use $this->addColumns() */ final protected function addColumnsIfNotExists(string $table, array $columns) { $columnSpecs = []; foreach ($columns as $columnName => $columnData) { $columnId = $table . '.' . $columnName; $columnSpecs[$columnId] = $columnData; } $this->addColumns($columnSpecs); } /** * Add indexes to a table if they doesn't exists * * @param string $table The table name * @param array $indexes Assoc array of indexName => definition * * @return void * @deprecated v2.1.0: use $this->addIndexes() */ final protected function addIndexesIfNotExists($table, $indexes) { $db = $this->dbo; $existentIndexes = $this->getIndexesFromTable($table); foreach ($indexes as $index => $specification) { if (!in_array($index, $existentIndexes)) { $db->setQuery( "ALTER TABLE {$db->quoteName($table)} CREATE INDEX {$specification} ON {$index}" ) ->execute(); } } } /** * Drop columns from a table if they exists * * @param string $table The table name * @param string[] $columns The column names that needed to be checked and added * * @return void * @deprecated v2.1.0: Use $this->dropColumns() */ final protected function dropColumnsIfExists($table, $columns) { $columnIds = []; foreach ($columns as $column) { $columnIds[] = $table . '.' . $column; } $this->dropColumns($columnIds); } /** * Check if a table exists * * @param string $name * * @return bool * @deprecated v2.1.0: Use $this->findTable() */ final protected function tableExists(string $name) { return $this->findTable($name); } /** * Parses a conditional string, returning a Boolean value (default: false). * For now it only supports an extension name and * as version. * * @param string $expression * * @return bool * @throws \Exception */ final protected function parseConditionalExpression(string $expression): bool { $expression = strtolower($expression); $terms = explode('=', $expression); $firstTerm = array_shift($terms); if (count($terms) == 0) { return $firstTerm == 'true' || $firstTerm == '1'; } elseif (preg_match('/^(com_|plg_|mod_|lib_|tpl_|cli_)/', $firstTerm)) { // The first term is the name of an extension $info = $this->getExtensionInfoFromElement($firstTerm); $extension = $this->findExtension($info['type'], $firstTerm, $info['group']); // @TODO: compare the version, if specified, or different than * // @TODO: Check if the extension is enabled, not just installed if (empty($extension) == false) { return true; } } return false; } /** * Get extension's info from element string, or extension name * * @param string $element The extension name, as element * * @return string[] An associative array with information about the extension */ final protected function getExtensionInfoFromElement($element) { $result = array_fill_keys( ['type', 'name', 'group', 'prefix', 'namespace'], null ); $types = [ 'com' => 'component', 'plg' => 'plugin', 'mod' => 'module', 'lib' => 'library', 'tpl' => 'template', 'cli' => 'cli' ]; $element = explode('_', $element, 3); $prefix = $result['prefix'] = array_shift($element); $name = array_pop($element); $group = array_pop($element); if (array_key_exists($prefix, $types)) { $result = array_merge( $result, [ 'type' => $types[$prefix], 'group' => $group, 'name' => $name ] ); } $result['namespace'] = preg_replace_callback( '/^(os[a-z])(.*)/i', function ($matches) { return strtoupper($matches[1]) . $matches[2]; }, $name ?? '' ); return $result; } /** * Check if the actual version is at least the minimum target version. * * @param string $actualVersion * @param string $targetVersion * @param ?string $compare * * @return bool True, if the target version is greater than or equal to actual version */ final protected function validateTargetVersion( string $actualVersion, string $targetVersion, ?string $compare = null ): bool { if ($targetVersion === '.*') { // Any version is valid return true; } $targetVersion = str_replace('*', '0', $targetVersion); return version_compare($actualVersion, $targetVersion, $compare ?: 'ge'); } /** * @param string $targetVersion * @param ?string $compare * * @return bool */ final protected function validatePreviousVersion(string $targetVersion, ?string $compare = null): bool { if ($this->previousManifest) { $lastVersion = (string)$this->previousManifest->version; return $this->validateTargetVersion($lastVersion, $targetVersion, $compare); } return true; } /** * Get the extension name. If no custom name is set, uses the namespace * * @return string */ final protected function getName() { return (string)($this->manifest->alledia->name ?? $this->manifest->alledia->namespace); } /** * If a template, preserve the favicon during an update. * Rename favicon during preFlight(). Rename back during postFlight() */ final protected function preserveFavicon() { $nameOfExtension = (string)$this->manifest->alledia->element; $extensionType = $this->getExtensionInfoFromElement($nameOfExtension); if ($extensionType['prefix'] === 'tpl') { $pathToTemplate = $this->getExtensionPath($this->type, $nameOfExtension); // These will be used to preserve the favicon during an update $favicon = $pathToTemplate . '/favicon.ico'; $faviconTemp = $pathToTemplate . '/favicon-temp.ico'; /** * Rename favicon. * The order of the conditionals should be kept the same, because * preFlight() runs before postFLight(). * If the order is reversed, favicon in update package will replace * $faviconTemp during update, which we don't want to happen. */ if (is_file($faviconTemp)) { rename($faviconTemp, $favicon); } elseif (is_file($favicon)) { rename($favicon, $faviconTemp); } } } /** * @param ?bool $force Force to get a fresh list of tables * * @return string[] List of tables */ final protected function getTables(?bool $force = false): array { if ($force || $this->tables === null) { $this->tables = $this->dbo->setQuery('SHOW TABLES')->loadColumn(); } return $this->tables; } /** * @param string $table * * @return bool */ final protected function findTable(string $table): bool { return in_array($this->dbo->replacePrefix($table), $this->getTables()); } /** * @param string[] $columnSpecs * * @return void * @TODO: allow use of specification array */ final protected function addColumns(array $columnSpecs) { $db = $this->dbo; foreach ($columnSpecs as $columnId => $specification) { if (strpos($columnId, '.') !== false && empty($this->findColumn($columnId))) { list($table, $columnName) = explode('.', $columnId); $db->setQuery( sprintf( 'ALTER TABLE %s ADD COLUMN %s %s', $db->quoteName($table), $db->quoteName($columnName), $specification ) ) ->execute(); } } } /** * @param string[] $columnIds * * @return void */ final protected function dropColumns(array $columnIds) { $db = $this->dbo; foreach ($columnIds as $columnId) { if (strpos($columnId, '.') !== false) { list($table, $column) = explode('.', $columnId); $db->setQuery( sprintf( 'ALTER TABLE %s DROP COLUMN %s', $db->quoteName($table), $column ) ) ->execute(); } } } /** * @param string $columnId * * @return ?object */ final protected function findColumn(string $columnId): ?object { if (strpos($columnId, '.') !== false) { $db = $this->dbo; list($table, $field) = explode('.', $columnId, 2); if (isset($this->tableColumns[$table]) == false) { $this->tableColumns[$table] = $db->setQuery('SHOW COLUMNS FROM ' . $db->quoteName($table)) ->loadObjectList(); } foreach ($this->tableColumns[$table] as $column) { if ($column->Field == $field) { return $column; } } } return null; } /** * @param array $indexes * * @return void */ final protected function addIndexes(array $indexes) { $db = $this->dbo; foreach ($indexes as $indexId => $ordering) { if (strpos($indexId, '.') !== false) { $index = explode('.', $indexId); $indexTable = array_shift($index) ?: ''; $indexName = array_shift($index) ?: ''; $indexType = array_shift($index) ?: ''; if ($this->findIndex($indexTable . '.' . $indexName) == false) { $db->setQuery( sprintf( 'ALTER TABLE %s ADD %s INDEX %s(%s)', $db->quoteName($indexTable), $indexType, $db->quoteName($indexName), join(',', $ordering) ) ) ->execute(); } } } } /** * @param string[] $indexIds * * @return void */ final protected function dropIndexes(array $indexIds) { $db = $this->dbo; foreach ($indexIds as $indexId) { if (strpos($indexId, '.') !== false) { if ($this->findIndex($indexId)) { list($table, $indexName) = explode('.', $indexId); $db->setQuery( sprintf( 'ALTER TABLE %s DROP INDEX %s', $db->quoteName($table), $db->quoteName($indexName) ) ) ->execute(); } } } } /** * @param string $indexId * * @return object[] */ final protected function findIndex(string $indexId): array { if (strpos($indexId, '.') !== false) { $db = $this->dbo; list($table, $indexName) = explode('.', $indexId); if (isset($this->tableIndexes[$table]) == false) { $this->tableIndexes[$table] = $db->setQuery('SHOW INDEX FROM ' . $db->quoteName($table)) ->loadObjectList(); } $indexes = []; foreach ($this->tableIndexes[$table] as $index) { if ($index->Key_name == $indexName) { $indexes[] = $index; } } return $indexes; } return []; } /** * @param string[] $constraintIds * * @return void */ final protected function dropConstraints(array $constraintIds) { $db = $this->dbo; foreach ($constraintIds as $constraintId) { if (strpos($constraintId, '.') !== false && $this->findConstraint($constraintId)) { list($table, $constraintName) = explode('.', $constraintId); $db->setQuery( sprintf( 'ALTER TABLE %s DROP FOREIGN KEY %s', $db->quoteName($table), $db->quoteName($constraintName) ) ) ->execute(); } } } /** * @param string $constraintId * * @return object[] */ final protected function findConstraint(string $constraintId): array { if (strpos($constraintId, '.') !== false) { $db = $this->dbo; list($table, $constraint) = explode('.', $constraintId); if (isset($this->tableConstraints[$table]) == false) { $query = $db->getQuery(true) ->select('*') ->from('information_schema.KEY_COLUMN_USAGE') ->where('TABLE_NAME = ' . $db->quote($db->replacePrefix($table))); $this->tableConstraints[$table] = $db->setQuery($query)->loadObjectList(); } $items = []; foreach ($this->tableConstraints[$table] as $item) { if ($item->CONSTRAINT_NAME == $constraint) { $items[] = $item; } } return $items ?: []; } return []; } /** * @return ?string * @throws \Exception */ final protected function getSchemaVersion(): ?string { if ($extension = $this->findThisExtension()) { $query = $this->dbo->getQuery(true) ->select('version_id') ->from('#__schemas') ->where('extension_id = ' . $extension->get('extension_id')); return $this->dbo->setQuery($query)->loadResult(); } return null; } /** * @param string|string[] $queries * * @return bool|Throwable */ final protected function executeQuery($schemaVersion, $queries) { if ($this->schemaVersion && version_compare($this->schemaVersion, $schemaVersion, 'lt')) { $this->sendDebugMessage(sprintf('Running v%s Schema Updates', $schemaVersion)); $db = $this->dbo; try { foreach ($queries as $query) { $db->setQuery($query)->execute(); } } catch (Throwable $error) { return $error; } } return true; } /** * Joomla 4 does a database check that has lots of problems with standard sql syntax * causing it to declare the database tables as not up to date and in some cases * generates various sql errors. This can optionally be called during Post Install to * clear out all update files and still maintain the latest schema version correctly. * * @param string $basePath */ final protected function clearDBUpdateFiles(string $basePath) { $this->sendDebugMessage(__METHOD__); $updatePath = $basePath . '/sql/updates'; if (is_dir($updatePath) && $files = Folder::files($updatePath, '\.sql$', true, true)) { $this->sendDebugMessage('Removing:<pre>' . print_r($files, 1) . '</pre>'); $final = reset($files); foreach ($files as $file) { $version = basename($file, '.sql'); $lastVersion = basename($final, '.sql'); if (version_compare($version, $lastVersion, 'gt')) { $final = $file; } File::delete($file); } if ($final) { File::write($final, ''); $this->sendDebugMessage('Wrote blank: ' . $final); } } } /** * @param SimpleXMLElement|string $element * @param ?string $type * @param mixed $default * * @return bool|string */ final protected function getXmlValue($element, $type = 'string', $default = null) { $value = $element ? (string)$element : $default; switch ($type) { case 'bool': case 'boolean': $value = $element ? $value == 'true' || $value == '1' : (bool)$default; break; case 'string': default: if ($value) { $value = trim($value); } break; } return $value; } /** * @param string $text * @param string $type * * @return void */ final protected function sendMessage(string $text, string $type = 'message') { if ($this->outputAllowed) { try { $this->app = $this->app ?: Factory::getApplication(); $this->app->enqueueMessage($text, $type); } catch (Throwable $error) { // Give up trying to send a message normally } } } /** * @param Throwable $error * @param bool $cancel * * @return void */ final protected function sendErrorMessage(Throwable $error, bool $cancel = true) { if ($cancel) { $this->cancelInstallation = true; } if ($this->outputAllowed) { $trace = $error->getTrace(); $trace = array_shift($trace); if (empty($trace['class'])) { $caller = basename($trace['file']); } else { $className = explode('\\', $trace['class']); $caller = array_pop($className); } $line = $trace['line']; $function = $trace['function'] ?? null; $file = $trace['file']; if ($function) { $message = sprintf('%s: %s<br>%s::%s() - %s', $line, $file, $caller, $function, $error->getMessage()); } else { $message = sprintf('%s:%s (%s) - %s', $line, $caller, $file, $error->getMessage()); } $this->sendMessage($message, 'error'); } } /** * @param string $text * * @return void */ final protected function sendDebugMessage(string $text) { if ($this->debug) { $type = Version::MAJOR_VERSION == 3 ? 'Debug-' . get_class($this) : CMSApplicationInterface::MSG_DEBUG; $this->sendMessage($text, $type); } } /** * @param string $type * * @return void */ final protected function displayWelcome(string $type) { if ($this->outputAllowed == false) { return; } $this->sendDebugMessage( sprintf( '%s<br>Parent: %s<br>Current: %s', __METHOD__, $this->installer->getPath('parent'), $this->installer->getPath('source') ) ); $license = $this->getLicense(); $name = $this->getName() . ($license->isPro() ? ' Pro' : ''); // Get the footer content $this->footer = ''; // Check if we have a dedicated config.xml file $configPath = $license->getExtensionPath() . '/config.xml'; if (is_file($configPath)) { $config = $license->getConfig(); if (empty($config) == false) { $footerElement = $config->xpath('//field[@type="customfooter"]'); } } else { $footerElement = $this->manifest->xpath('//field[@type="customfooter"]'); } if (empty($footerElement) == false) { if (class_exists('\\JFormFieldCustomFooter') == false) { // Custom footer field is not (and should not be) automatically loaded $customFooterPath = $license->getExtensionPath() . '/form/fields/customfooter.php'; if (is_file($customFooterPath)) { include_once $customFooterPath; } } if (class_exists('\\JFormFieldCustomFooter')) { $field = new JFormFieldCustomFooter(); $field->fromInstaller = true; $this->footer = $field->getInputUsingCustomElement($footerElement[0]); unset($field, $footerElement); } } // Show additional installation messages $extensionPath = $this->getExtensionPath( $this->type, (string)$this->manifest->alledia->element, $this->group ); // If Pro extension, includes the license form view if ($license->isPro()) { // Get the OSMyLicensesManager extension to handle the license key if ($licensesManagerExtension = new Licensed('osmylicensesmanager', 'plugin', 'system')) { if (isset($licensesManagerExtension->params)) { $this->licenseKey = $licensesManagerExtension->params->get('license-keys', ''); } else { $this->licenseKey = ''; } $this->isLicensesManagerInstalled = true; } } // Welcome message if (in_array($type, [static::TYPE_INSTALL, static::TYPE_DISCOVER_INSTALL])) { $string = 'LIB_SHACKINSTALLER_THANKS_INSTALL'; } else { $string = 'LIB_SHACKINSTALLER_THANKS_UPDATE'; } // Variables for the included template $this->welcomeMessage = Text::sprintf($string, $name); $this->mediaURL = Uri::root() . 'media/' . $license->getFullElement(); $this->addStyle($this->mediaFolder . '/css/installer.css'); /* * Include the template * Try to find the template in an alternative folder, since some extensions * which uses FOF will display the "Installers" view on admin, errouniously. * FOF look for views automatically reading the views folder. So on that * case we move the installer view to another folder. */ $path = $extensionPath . '/views/installer/tmpl/default.php'; if (is_file($path)) { include $path; } else { $path = $extensionPath . '/alledia_views/installer/tmpl/default.php'; if (is_file($path)) { include $path; } } } /** * WARNIMG! This is duplicated from the Joomlashack Framework * * @param string $name * @param string $prefix * @param string $component * @param ?string $appName * @param ?array $options * * @return mixed * @throws \Exception */ protected function getJoomlaModel( string $name, string $prefix, string $component, ?string $appName = null, ?array $options = [] ) { $defaultApp = 'Site'; $appNames = [$defaultApp, 'Administrator']; $appName = ucfirst($appName ?: $defaultApp); $appName = in_array($appName, $appNames) ? $appName : $defaultApp; if (Version::MAJOR_VERSION < 4) { $basePath = $appName == 'Administrator' ? JPATH_ADMINISTRATOR : JPATH_SITE; $path = $basePath . '/components/' . $component; BaseDatabaseModel::addIncludePath($path . '/models'); Table::addIncludePath($path . '/tables'); $model = BaseDatabaseModel::getInstance($name, $prefix, $options); } else { $model = Factory::getApplication()->bootComponent($component) ->getMVCFactory()->createModel($name, $appName, $options); } return $model; } } library/Installer/AutoLoader.php 0000644 00000015140 15247143460 0012724 0 ustar 00 <?php /** * @package ShackInstaller * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2023 Joomlashack.com. All rights reserved * @license https://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackInstaller. * * ShackInstaller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackInstaller is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>. */ namespace Alledia\Installer; defined('_JEXEC') or die(); class AutoLoader { /** * Associative array where the key is a namespace prefix and the value * is an array of base directories for classes in that namespace. * * @var array */ protected static $prefixes = []; /** * Associative array of prefixes for loading specialized camelCase classes * where Uppercase letters in the class name indicate directory structure * * @var array */ protected static $camelPrefixes = []; /** * @var AutoLoader */ protected static $instance = null; /** * @param string $method */ protected static function registerLoader($method) { if (static::$instance === null) { static::$instance = new static(); } spl_autoload_register([static::$instance, $method]); } /** * Register a psr4 namespace * * @param string $prefix The namespace prefix. * @param string $baseDir A base directory for class files in the * namespace. * @param ?bool $prepend If true, prepend the base directory to the stack * instead of appending it; this causes it to be searched first rather * than last. * * @return void */ public static function register(string $prefix, string $baseDir, ?bool $prepend = false) { if (count(self::$prefixes) == 0) { static::registerLoader('loadClass'); } // normalize namespace prefix $prefix = trim($prefix, '\\') . '\\'; // normalize the base directory with a trailing separator $baseDir = rtrim($baseDir, '\\/') . '/'; // initialise the namespace prefix array if (empty(self::$prefixes[$prefix])) { self::$prefixes[$prefix] = []; } // retain the base directory for the namespace prefix if ($prepend) { array_unshift(self::$prefixes[$prefix], $baseDir); } else { array_push(self::$prefixes[$prefix], $baseDir); } } /** * Loads the class file for a given class name. * * @param string $class The fully-qualified class name. * * @return ?string The mapped file name on success */ protected function loadClass(string $class): ?string { $prefixes = explode('\\', $class); $className = ''; while ($prefixes) { $className = array_pop($prefixes) . $className; $prefix = join('\\', $prefixes) . '\\'; if ($filePath = $this->loadMappedFile($prefix, $className)) { return $filePath; } $className = '\\' . $className; } return null; } /** * Load the mapped file for a namespace prefix and class. * * @param string $prefix The namespace prefix. * @param string $className The relative class name. * * @return ?string path that was loaded */ protected function loadMappedFile(string $prefix, string $className): ?string { // are there any base directories for this namespace prefix? if (isset(self::$prefixes[$prefix]) === false) { return null; } // look through base directories for this namespace prefix foreach (self::$prefixes[$prefix] as $baseDir) { $path = $baseDir . str_replace('\\', '/', $className) . '.php'; if (is_file($path)) { require_once $path; return $path; } } return null; } /** * Register a base directory for classes organized using camelCase. * Class names beginning with the prefix will be automatically loaded * if there is a matching file in the directory tree starting with $baseDir. * File names and directory names are all expected to be lower case. * * Example: * * $prefix = 'Simplerenew' * $baseDir = '/library/joomla' * * A class name of: SimplerenewViewAdmin * Would be in : /library/joomla/view/admin.php * * This system is intended for situations where full name spacing is either * unavailable or impractical due to integration with other systems. * * @param string $prefix * @param string $baseDir * * @return void * @throws \Exception */ public static function registerCamelBase(string $prefix, string $baseDir) { if (!is_dir($baseDir)) { throw new \Exception("Cannot register '{$prefix}'. The requested base directory does not exist!'"); } if (count(self::$camelPrefixes) == 0) { // Register function on first call static::registerLoader('loadCamelClass'); } if (empty(self::$camelPrefixes[$prefix])) { self::$camelPrefixes[$prefix] = $baseDir; } } /** * Autoload a class using the camelCase structure * * @param string $class * * @return string */ protected function loadCamelClass(string $class): ?string { if (!class_exists($class)) { foreach (self::$camelPrefixes as $prefix => $baseDir) { if (strpos($class, $prefix) === 0) { $parts = preg_split('/(?<=[a-z])(?=[A-Z])/x', substr($class, strlen($prefix))); $file = strtolower(join('/', $parts)); $filePath = $baseDir . '/' . $file . '.php'; if (is_file($filePath)) { require_once $filePath; return $filePath; } } } } return null; } } form/fields/subtitle.php 0000644 00000005535 15247143460 0011337 0 ustar 00 <?php /** * @package ShackDefaultFiles * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2015-2022 Joomlashack.com. All rights reserved * @license https://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackDefaultFiles. * * ShackDefaultFiles is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackDefaultFiles is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackDefaultFiles. If not, see <https://www.gnu.org/licenses/>. */ use Joomla\CMS\Form\FormHelper; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; defined('_JEXEC') or die(); FormHelper::loadFieldClass('Spacer'); class JFormFieldSubtitle extends JFormFieldSpacer { /** * @inheritDoc */ protected function getLabel() { $html = []; $class = $this->class ?: sprintf(' class="%s"', $this->class); $tag = $this->element['tag'] ? (string)$this->element['tag'] : 'h4'; $html[] = '<span class="spacer">'; $html[] = '<span class="before"></span>'; $html[] = '<span' . $class . '>'; if ((string)$this->element['hr'] == 'true') { $html[] = '<hr' . $class . '>'; } else { $label = ''; // Get the label text from the XML element, defaulting to the element name. $text = (string)$this->element['label'] ?: (string)$this->element['name']; $text = $this->translateLabel ? Text::_($text) : $text; // Build the class for the label. $class = $this->description ? 'hasTooltip' : ''; $class = $this->required == true ? $class . ' required' : $class; // Add the opening label tag and main attributes attributes. $label .= '<' . $tag . ' id="' . $this->id . '-lbl" class="' . $class . '"'; if ($this->description) { // Use description to build a tooltip. HTMLHelper::_('bootstrap.tooltip'); $label .= sprintf( ' title="%s"', HTMLHelper::tooltipText(trim($text, ':'), Text::_($this->description), 0) ); } // Add the label text and closing tag. $label .= '>' . $text . '</' . $tag . '>'; $html[] = $label; } $html[] = '</span>'; $html[] = '<span class="after"></span>'; $html[] = '</span>'; return implode('', $html); } } form/fields/layouts/alledia/customfooter.php 0000644 00000007445 15247143460 0015332 0 ustar 00 <?php /** * @package ShackDefaultFiles * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2018-2022 Joomlashack.com. All rights reserved * @license https://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackDefaultFiles. * * ShackDefaultFiles is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackDefaultFiles is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackDefaultFiles. If not, see <https://www.gnu.org/licenses/>. */ use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; defined('_JEXEC') or die(); /** * @var array $displayData */ $class = $displayData['class']; $media = $displayData['media']; $jslogo = $media . '/' . $displayData['jslogo']; $jedurl = $displayData['jedurl']; $showGoProAd = $displayData['showGoProAd']; $goProUrl = $displayData['goProUrl']; $fromInstaller = $displayData['fromInstaller']; $footerCss = HTMLHelper::_('stylesheet', $media . '/field_customfooter.css', ['relative' => true, 'pathOnly' => true]); $adminCss = HTMLHelper::_('stylesheet', $media . '/admin-default.css', ['relative' => true, 'pathOnly' => true]); ?> <link href="<?php echo $footerCss; ?>" rel="stylesheet"/> <link href="<?php echo $adminCss; ?>" rel="stylesheet"/> <div class="<?php echo $class; ?>"> <div> <?php if ($showGoProAd) : ?> <div class="gopro-ad"> <?php echo HTMLHelper::_( 'link', $goProUrl, Text::_('SHACKDEFAULTFILES_GO_PRO'), 'class="gopto-btn" target="_blank"' ); ?> </div> <?php endif; if ($jedurl) : ?> <div class="joomlashack-jedlink"> <?php echo Text::_('SHACKDEFAULTFILES_LIKE_THIS_EXTENSION'); echo ' ' . HTMLHelper::_( 'link', $jedurl, Text::_('SHACKDEFAULTFILES_LEAVE_A_REVIEW_ON_JED'), 'target="_blank"' ); echo ' ' . str_repeat("<i class=\"icon-star\"></i>", 5); ?> </div> <?php endif; ?> <div class="poweredby"> Powered by <?php echo HTMLHelper::_( 'link', 'https://www.joomlashack.com', HTMLHelper::_('image', $jslogo, 'Joomlashack', 'class="joomlashack-logo" width="150"', true), 'target="_blank"' ); ?> </div> <div class="joomlashack-copyright"> <?php echo '© ' . date('Y'); ?> Joomlashack.com. All rights reserved. </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { let footer = document.getElementsByClassName('joomlashack-footer')[0], parent = footer.parentElement; let hasClass = function(elem, className) { return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' '); }; if (hasClass(parent, 'controls')) { let wrapper = document.getElementById('content'); wrapper.parentNode.insertBefore(footer, wrapper.nextSibling); } }); </script> form/fields/customfooter.php 0000644 00000010622 15247143460 0012226 0 ustar 00 <?php /** * @package ShackDefaultFiles * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2015-2022 Joomlashack.com. All rights reserved * @license https://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackDefaultFiles. * * ShackDefaultFiles is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackDefaultFiles is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackDefaultFiles. If not, see <https://www.gnu.org/licenses/>. */ use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; defined('_JEXEC') or die(); class JFormFieldCustomFooter extends FormField { /** * @inheritdoc */ protected $layout = 'alledia.customfooter'; /** * @var bool */ protected $fromInstaller = false; /** * @inheritDoc */ public function __set($name, $value = null) { switch ($name) { case 'fromInstaller': $this->fromInstaller = (bool)$value; break; default: parent::__set($name, $value); } } /** * @inheritDoc * */ public function setup(\SimpleXMLElement $element, $value, $group = null) { if ($path = realpath(__DIR__ . '/../..')) { Factory::getLanguage()->load('shackdefaultfiles',$path); } return parent::setup($element, $value, $group); } /** * @inheritDoc */ protected function getInput() { return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * @inheritDoc */ protected function getRenderer($layoutId = 'default') { $renderer = parent::getRenderer($layoutId); if ($layoutId == $this->layout) { $renderer->addIncludePath(__DIR__ . '/layouts'); } return $renderer; } /** * @inheritDoc */ protected function getLayoutData() { $displayData = parent::getLayoutData(); $requiredClasses = [ 'joomlashack-footer', 'row-fluid' ]; if ($this->fromInstaller) { $requiredClasses[] = 'installer'; } $classes = array_unique( array_filter( array_merge( preg_split('/\s/', $displayData['class']), $requiredClasses ) ) ); $goProUrl = (string)$this->element['showgoproad'] ?: '0'; $showGoProAd = !($goProUrl == '0' || $goProUrl == 'false'); if ($showGoProAd && !filter_var($goProUrl, FILTER_VALIDATE_URL)) { $goProUrl = 'https://www.joomlashack.com/plans'; } return array_merge( $displayData, [ 'class' => join(' ', $classes), 'media' => $this->element['media'], 'jslogo' => (string)$this->element['jslogo'] ?: 'joomlashack-logo.png', 'jshome' => (string)$this->element['jshome'] ?: 'https://www.joomlashack.com', 'jedurl' => (string)$this->element['jedurl'], 'fromInstaller' => $this->fromInstaller, 'showGoProAd' => $showGoProAd, 'goProUrl' => $goProUrl ] ); } /** * @param ?string $path * * @return string * @TODO: Doesn't seem to be useful */ protected function getStyle(?string $path): string { if ($path && is_file($path)) { return '<style>' . file_get_contents($path) . '</style>'; } return ''; } /** * @inheritDoc */ protected function getLabel() { return ''; } /** * @param SimpleXMLElement $element * * @return ?string */ public function getInputUsingCustomElement(SimpleXMLElement $element): ?string { $this->element = $element; $this->setup($element, null); return $this->getInput(); } } script.installer.php 0000644 00000002171 15247143460 0010564 0 ustar 00 <?php /** * @package ShackExtensionSupport * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2022 Joomlashack.com. All rights reserved * @license http://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackExtensionSupport. * * ShackExtensionSupport is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackExtensionSupport is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackExtensionSupport. If not, see <http://www.gnu.org/licenses/>. */ defined('_JEXEC') or die(); use Alledia\Installer\AbstractScript; require_once 'library/Installer/include.php'; class PlgSystemOsmylicensesmanagerInstallerScript extends AbstractScript { } osmylicensesmanager.xml 0000644 00000005210 15247143460 0011342 0 ustar 00 <?xml version="1.0" encoding="utf-8"?> <extension type="plugin" group="system" method="upgrade"> <name>plg_system_osmylicensesmanager</name> <author>Joomlashack.com</author> <authorEmail>help@joomlashack.com</authorEmail> <authorUrl>https://www.joomlashack.com</authorUrl> <copyright>Copyright 2016-2022 Joomlashack. All rights reserved</copyright> <license>GNU GPL; see LICENSE file</license> <description>PLG_SYSTEM_OSMYLICENSESMANAGER_DESCRIPTION</description> <version>2.0.15</version> <creationDate>June 16 2022</creationDate> <variant>FREE</variant> <alledia> <element publish="true">osmylicensesmanager</element> <namespace>OSMyLicensesManager</namespace> <name>Joomlashack Extension Support</name> <license>free</license> <platform>3.9</platform> <phpminimum>7.2.5</phpminimum> <relatedExtensions> <extension type="library" element="allediaframework">ShackFramework</extension> </relatedExtensions> <include>ShackDefaultFiles</include> <obsolete> <file>/plugins/system/osmylicensesmanager/library/Free/UpdateHelper.php</file> <extension type="plugin" group="system" element="ossystem"/> </obsolete> </alledia> <scriptfile>script.installer.php</scriptfile> <files> <folder>form</folder> <folder>language</folder> <folder>library</folder> <folder>views</folder> <filename plugin="osmylicensesmanager">osmylicensesmanager.php</filename> <filename>include.php</filename> </files> <media destination="plg_system_osmylicensesmanager" folder="media"> <folder>css</folder> <folder>images</folder> </media> <config> <fields name="params"> <fieldset name="basic" addfieldpath="/plugins/system/osmylicensesmanager/form/fields"> <field name="license-keys" type="text" label="PLG_SYSTEM_OSMYLICENSESMANAGER_FIELD_LICENSE_KEYS_LABEL" description="PLG_SYSTEM_OSMYLICENSESMANAGER_FIELD_LICENSE_KEYS_DESC"/> <field type="customfooter" name="customfooter" media="plg_system_osmylicensesmanager"/> </fieldset> </fields> </config> <updateservers> <server type="extension" priority="1" name="Joomlashack Extension Support"><![CDATA[https://deploy.ostraining.com/client/update/free/stable/plg_system_osmylicensesmanager]]></server> </updateservers> </extension> osmylicensesmanager.php 0000644 00000010063 15247143460 0011333 0 ustar 00 <?php /** * @package ShackExtensionSupport * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2022 Joomlashack.com. All rights reserved * @license http://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackExtensionSupport. * * ShackExtensionSupport is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackExtensionSupport is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackExtensionSupport. If not, see <http://www.gnu.org/licenses/>. */ use Alledia\Framework\Joomla\Extension\AbstractPlugin; use Alledia\Framework\Joomla\Extension\Helper; use Alledia\OSMyLicensesManager\Free\PluginHelper; use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Factory; defined('_JEXEC') or die(); if (include 'include.php') { class PlgSystemOSMyLicensesManager extends AbstractPlugin { /** * @var CMSApplication */ protected $app = null; /** * @inheritdoc */ protected $namespace = 'OSMyLicensesManager'; /** * @return void */ public function onAfterInitialise() { $plugin = $this->app->input->getCmd('plugin'); $task = $this->app->input->getCmd('task'); $user = Factory::getUser(); if ( $this->app->isClient('administrator') && $plugin == 'system_osmylicensesmanager' && $task == 'license.save' && $user->guest == false ) { // The user is saving a license key from the installer screen $this->init(); $licenseKeys = $this->app->input->post->getString('license-keys', ''); $result = (object)[ 'success' => PluginHelper::updateLicenseKeys($licenseKeys) ]; echo json_encode($result); jexit(); } } /** * @return void */ public function onAfterRender() { $option = $this->app->input->getCmd('option'); $extension = $this->app->input->getCmd('extension'); if ( $this->app->isClient('administrator') && $option === 'com_categories' && $extension ) { $this->addCustomFooterToCategories($extension); } } /** * @param string $url * * @return void */ public function onInstallerBeforePackageDownload(string &$url) { if ( PluginHelper::isOurDownloadURL($url) && PluginHelper::getLicenseTypeFromURL($url) !== 'free' ) { $this->init(); // Append the license keys to the URL $licenseKeys = $this->params->get('license-keys', ''); $url = PluginHelper::appendLicenseKeyToURL($url, $licenseKeys); } } /** * @param ?string $element * * @return void */ protected function addCustomFooterToCategories(?string $element) { if ($element) { // Check if the specified extension is from Alledia if ($extension = Helper::getExtensionForElement($element)) { if ($footer = $extension->getFooterMarkup()) { $this->app->setBody( str_replace('</section>', '</section>' . $footer, $this->app->getBody()) ); } } } } } } include.php 0000644 00000003407 15247143460 0006712 0 ustar 00 <?php /** * @package ShackExtensionSupport * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2022 Joomlashack.com. All rights reserved * @license http://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackExtensionSupport. * * ShackExtensionSupport is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackExtensionSupport is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackExtensionSupport. If not, see <http://www.gnu.org/licenses/>. */ use Alledia\Framework\AutoLoader; use Joomla\CMS\Factory; defined('_JEXEC') or die(); if (!defined('ALLEDIA_FRAMEWORK_LOADED')) { $frameworkPath = JPATH_SITE . '/libraries/allediaframework/include.php'; if ( !(is_file($frameworkPath) && include $frameworkPath) && Factory::getApplication()->isClient('administrator') ) { Factory::getApplication() ->enqueueMessage('[Joomlashack Extension Support] Joomlashack Framework not found', 'error'); } } if (defined('ALLEDIA_FRAMEWORK_LOADED') && !defined('SHACKEXTENSIONSUPPORT_LOADED')) { AutoLoader::register('\\Alledia\\OSMyLicensesManager', JPATH_SITE . '/plugins/system/osmylicensesmanager/library'); define('SHACKEXTENSIONSUPPORT_LOADED', 1); } return defined('ALLEDIA_FRAMEWORK_LOADED') && defined('SHACKEXTENSIONSUPPORT_LOADED'); language/en-GB/en-GB.shackdefaultfiles.ini 0000644 00000002203 15247143460 0014273 0 ustar 00 ; @package ShackDefaultFiles ; @contact www.joomlashack.com, help@joomlashack.com ; @copyright 2021-2022 Joomlashack.com. All rights reserved ; @license https://www.gnu.org/licenses/gpl.html GNU/GPL ; ; This file is part of ShackDefaultFiles. ; ; ShackDefaultFiles is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 2 of the License, or ; (at your option) any later version. ; ; ShackDefaultFiles is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with ShackDefaultFiles. If not, see <https://www.gnu.org/licenses/>. ; ; Note : All ini files need to be saved as UTF-8 - No BOM SHACKDEFAULTFILES_GO_PRO = "Go Pro to access more features" SHACKDEFAULTFILES_LEAVE_A_REVIEW_ON_JED = "Leave a review on the JED" SHACKDEFAULTFILES_LIKE_THIS_EXTENSION = "Like this extension?" language/en-GB/en-GB.lib_shackinstaller.sys.ini 0000644 00000007764 15247143460 0015305 0 ustar 00 ; @package ShackInstaller ; @contact www.joomlashack.com, help@joomlashack.com ; @copyright 2016-2023 Joomlashack.com. All rights reserved ; @license https://www.gnu.org/licenses/gpl.html GNU/GPL ; ; This file is part of ShackInstaller. ; ; ShackInstaller is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 2 of the License, or ; (at your option) any later version. ; ; ShackInstaller is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>. ; ; Note : All ini files need to be saved as UTF-8 - No BOM LIB_SHACKINSTALLER_ABORT_INSTALL = "Another extension is preventing installation. Please disable it and try again: %s" LIB_SHACKINSTALLER_ABORT_UNINSTALL = "Another extension has prevented completing the uninstll. Additional, related extensions may need to uninstalled." LIB_SHACKINSTALLER_CHANGE_LICENSE_KEY = "Change my license key" LIB_SHACKINSTALLER_I_DONT_REMEMBER_MY_KEY = "I don't remember my key!" LIB_SHACKINSTALLER_INSTALL_CANCELLED = "Install process canceled." LIB_SHACKINSTALLER_LICENSE_KEY_ERROR = "We found an error trying to save your license key. Please try again inside the Joomlashack License Key Manager plugin. You can find it by going to Extensions -> Plugins -> search for 'license'." LIB_SHACKINSTALLER_LICENSE_KEY_SUCCESS = "Your license key was saved successfully!" LIB_SHACKINSTALLER_LICENSE_KEYS_MANAGER_REQUIRED = "You are using a Joomlashack Pro extension, but you don't have the Joomlashack License Key Manager plugin installed. Please install it and configure your license key in order to be able to update this extension." LIB_SHACKINSTALLER_LICENSE_KEYS_PLACEHOLDER = "license key" LIB_SHACKINSTALLER_LICENSED_AS = "%s and all related extensions are licensed as %s" LIB_SHACKINSTALLER_MANIFEST_NOT_FOUND = "Manifest file not found: %s" LIB_SHACKINSTALLER_MSG_LICENSE_KEYS_EMPTY = "* Update requires a valid license key." LIB_SHACKINSTALLER_OBSOLETE_UNINSTALLED_FAIL = "Uninstalling %s %s, failed" LIB_SHACKINSTALLER_OBSOLETE_UNINSTALLED_SUCCESS = "Uninstalling %s %s was successful" LIB_SHACKINSTALLER_PUBLISHED = "Published" LIB_SHACKINSTALLER_RELATED_EXTENSIONS = "Related Extensions" LIB_SHACKINSTALLER_RELATED_INSTALL = "%s %s was successfully installed" LIB_SHACKINSTALLER_RELATED_INSTALL_FAIL = "Installation of %s %s failed" LIB_SHACKINSTALLER_RELATED_NOT_UNINSTALLED = "This extension does not uninstall %s %s" LIB_SHACKINSTALLER_RELATED_NOT_UNINSTALLED_SYSTEM = "The %s %s won't be uninstalled because of possible dependencies" LIB_SHACKINSTALLER_RELATED_UNINSTALL = "%s %s was successfully removed" LIB_SHACKINSTALLER_RELATED_UNINSTALL_FAIL = "Unable to remove %s %s" LIB_SHACKINSTALLER_RELATED_UPDATE = "%s %s was successfully updated" LIB_SHACKINSTALLER_RELATED_UPDATE_FAIL = "Update of %s %s failed" LIB_SHACKINSTALLER_RELATED_UPDATE_STATE_FAILED = "Failed, version %s" LIB_SHACKINSTALLER_RELATED_UPDATE_STATE_INSTALLED = "Installed v%s" LIB_SHACKINSTALLER_RELATED_UPDATE_STATE_SKIPED = "Skipped %s, the version %s is already installed" LIB_SHACKINSTALLER_RELEASE_V = "Release: v%s" LIB_SHACKINSTALLER_SAVE_LICENSE_KEY = "Save my license key" LIB_SHACKINSTALLER_SHOW_DETAILS = "Show more details..." LIB_SHACKINSTALLER_SORTED = "Sorted [%s]" LIB_SHACKINSTALLER_THANKS_INSTALL = "Thanks for installing %s!" LIB_SHACKINSTALLER_THANKS_UPDATE = "Thanks for updating %s!" LIB_SHACKINSTALLER_WRONG_MYSQL = "Sorry, %s requires at least MySQL %s." LIB_SHACKINSTALLER_WRONG_PHP = "Sorry, %s requires at least php %s." LIB_SHACKINSTALLER_WRONG_PLATFORM = "Sorry, %s requires Joomla! %s." LIB_SHACKINSTALLER_WRONG_PREVIOUS = "Sorry, updating %s requires at least version %s to be installed first." language/en-GB/en-GB.plg_system_osmylicensesmanager.sys.ini 0000644 00000002462 15247143460 0017754 0 ustar 00 ; @package ShackExtensionSupport ; @contact www.joomlashack.com, help@joomlashack.com ; @copyright 2016-2022 Joomlashack.com. All rights reserved ; @license http://www.gnu.org/licenses/gpl.html GNU/GPL ; ; This file is part of ShackExtensionSupport. ; ; ShackExtensionSupport is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 2 of the License, or ; (at your option) any later version. ; ; ShackExtensionSupport is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with ShackExtensionSupport. If not, see <http://www.gnu.org/licenses/>. ; ; Note : All ini files need to be saved as UTF-8 - No BOM PLG_SYSTEM_OSMYLICENSESMANAGER = "System - Joomlashack Extension Support" PLG_SYSTEM_OSMYLICENSESMANAGER_DESCRIPTION = "For Pro licensed Joomlashack extensions, you must have a valid License Key to receive extension updates. Get your license key here: <a href=\"https://www.joomlashack.com/account/key/\" target=\"_blank\">Your Pro License Key</a>." language/en-GB/en-GB.plg_system_osmylicensesmanager.ini 0000644 00000002750 15247143460 0017137 0 ustar 00 ; @package ShackExtensionSupport ; @contact www.joomlashack.com, help@joomlashack.com ; @copyright 2016-2022 Joomlashack.com. All rights reserved ; @license http://www.gnu.org/licenses/gpl.html GNU/GPL ; ; This file is part of ShackExtensionSupport. ; ; ShackExtensionSupport is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 2 of the License, or ; (at your option) any later version. ; ; ShackExtensionSupport is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with ShackExtensionSupport. If not, see <http://www.gnu.org/licenses/>. ; ; Note : All ini files need to be saved as UTF-8 - No BOM PLG_SYSTEM_OSMYLICENSESMANAGER = "System - Joomlashack Extension Support" PLG_SYSTEM_OSMYLICENSESMANAGER_DESCRIPTION = "For Pro licensed Joomlashack extensions, you must have a valid License Key to receive extension updates. Get your license key here: <a href=\"https://www.joomlashack.com/account/key/\" target=\"_blank\">Your Pro License Key</a>." PLG_SYSTEM_OSMYLICENSESMANAGER_FIELD_LICENSE_KEYS_LABEL = "License Key" PLG_SYSTEM_OSMYLICENSESMANAGER_FIELD_LICENSE_KEYS_DESC = "Joomlashack license key to update Pro extensions." language/en-GB/en-GB.lib_allediainstaller.sys.ini 0000644 00000014004 15247143460 0015570 0 ustar 00 ; @package AllediaInstaller ; @contact www.joomlashack.com, help@joomlashack.com ; @copyright Copyright (C) 2016 Open Sources Training, LLC, All rights reserved ; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL ; ; Note : All ini files need to be saved as UTF-8 - No BOM ; ; @TODO: this file should be removed once all extensions have been updated LIB_ALLEDIAINSTALLER_CHANGE_LICENSE_KEY = "Change my license key" LIB_ALLEDIAINSTALLER_I_DONT_REMEMBER_MY_KEY = "I don't remember my key!" LIB_ALLEDIAINSTALLER_INSTALL_CANCELLED = "Install process canceled." LIB_ALLEDIAINSTALLER_LICENSE_KEY_ERROR = "We found an error trying to save your license key. Please try again inside the Joomlashack License Key Manager plugin. You can find it by going to Extensions -> Plugins -> search for 'license'." LIB_ALLEDIAINSTALLER_LICENSE_KEY_SUCCESS = "Your license key was saved successfully!" LIB_ALLEDIAINSTALLER_LICENSE_KEYS_MANAGER_REQUIRED = "You are using a Joomlashack Pro extension, but you don't have the Joomlashack License Key Manager plugin installed. Please install it and configure your license key in order to be able to update this extension." LIB_ALLEDIAINSTALLER_LICENSE_KEYS_PLACEHOLDER = "license key" LIB_ALLEDIAINSTALLER_LICENSED_AS = "%s and all related extensions are licensed as %s" LIB_ALLEDIAINSTALLER_MANIFEST_NOT_FOUND = "Manifest file not found: %s" LIB_ALLEDIAINSTALLER_MSG_LICENSE_KEYS_EMPTY = "* Update requires a valid license key." LIB_ALLEDIAINSTALLER_OBSOLETE_UNINSTALLED_FAIL = "Uninstalling %s %s, failed" LIB_ALLEDIAINSTALLER_OBSOLETE_UNINSTALLED_SUCCESS = "Uninstalling %s %s was successful" LIB_ALLEDIAINSTALLER_PUBLISHED = "Published" LIB_ALLEDIAINSTALLER_RELATED_EXTENSIONS = "Related Extensions" LIB_ALLEDIAINSTALLER_RELATED_INSTALL = "%s %s was successfully installed" LIB_ALLEDIAINSTALLER_RELATED_INSTALL_FAIL = "Installation of %s %s failed" LIB_ALLEDIAINSTALLER_RELATED_NOT_UNINSTALLED = "The %s %s won't be uninstalled because of possible dependencies" LIB_ALLEDIAINSTALLER_RELATED_UNINSTALL = "%s %s was successfully removed" LIB_ALLEDIAINSTALLER_RELATED_UNINSTALL_FAIL = "Unable to remove %s %s" LIB_ALLEDIAINSTALLER_RELATED_UPDATE = "%s %s was successfully updated" LIB_ALLEDIAINSTALLER_RELATED_UPDATE_FAIL = "Update of %s %s failed" LIB_ALLEDIAINSTALLER_RELATED_UPDATE_STATE_FAILED = "Failed, version %s" LIB_ALLEDIAINSTALLER_RELATED_UPDATE_STATE_INSTALLED = "Installed v%s" LIB_ALLEDIAINSTALLER_RELATED_UPDATE_STATE_SKIPED = "Skipped %s, the version %s is already installed" LIB_ALLEDIAINSTALLER_RELEASE_V = "Release: v%s" LIB_ALLEDIAINSTALLER_SAVE_LICENSE_KEY = "Save my license key" LIB_ALLEDIAINSTALLER_SHOW_DETAILS = "Show more details..." LIB_ALLEDIAINSTALLER_SORTED = "Sorted [%s]" LIB_ALLEDIAINSTALLER_THANKS_INSTALL = "Thanks for installing %s!" LIB_ALLEDIAINSTALLER_THANKS_UPDATE = "Thanks for updating %s!" LIB_ALLEDIAINSTALLER_WRONG_MYSQL = "Sorry, %s requires at least MySQL %s." LIB_ALLEDIAINSTALLER_WRONG_PHP = "Sorry, %s requires at least php %s." LIB_ALLEDIAINSTALLER_WRONG_PLATFORM = "Sorry, %s requires Joomla! %s." LIB_ALLEDIAINSTALLER_WRONG_PREVIOUS = "Sorry, updating %s requires at least version %s to be installed first." ; Copied from lib_shackinstaller.sys while we transition from old extension LIB_SHACKINSTALLER_CHANGE_LICENSE_KEY = "Change my license key" LIB_SHACKINSTALLER_I_DONT_REMEMBER_MY_KEY = "I don't remember my key!" LIB_SHACKINSTALLER_INSTALL_CANCELLED = "Install process canceled." LIB_SHACKINSTALLER_LICENSE_KEY_ERROR = "We found an error trying to save your license key. Please try again inside the Joomlashack License Key Manager plugin. You can find it by going to Extensions -> Plugins -> search for 'license'." LIB_SHACKINSTALLER_LICENSE_KEY_SUCCESS = "Your license key was saved successfully!" LIB_SHACKINSTALLER_LICENSE_KEYS_MANAGER_REQUIRED = "You are using a Joomlashack Pro extension, but you don't have the Joomlashack License Key Manager plugin installed. Please install it and configure your license key in order to be able to update this extension." LIB_SHACKINSTALLER_LICENSE_KEYS_PLACEHOLDER = "license key" LIB_SHACKINSTALLER_LICENSED_AS = "%s and all related extensions are licensed as %s" LIB_SHACKINSTALLER_MANIFEST_NOT_FOUND = "Manifest file not found: %s" LIB_SHACKINSTALLER_MSG_LICENSE_KEYS_EMPTY = "* Update requires a valid license key." LIB_SHACKINSTALLER_OBSOLETE_UNINSTALLED_FAIL = "Uninstalling %s %s, failed" LIB_SHACKINSTALLER_OBSOLETE_UNINSTALLED_SUCCESS = "Uninstalling %s %s was successful" LIB_SHACKINSTALLER_PUBLISHED = "Published" LIB_SHACKINSTALLER_RELATED_EXTENSIONS = "Related Extensions" LIB_SHACKINSTALLER_RELATED_INSTALL = "%s %s was successfully installed" LIB_SHACKINSTALLER_RELATED_INSTALL_FAIL = "Installation of %s %s failed" LIB_SHACKINSTALLER_RELATED_NOT_UNINSTALLED = "This extension does not uninstall %s %s" LIB_SHACKINSTALLER_RELATED_NOT_UNINSTALLED_SYSTEM = "The %s %s won't be uninstalled because of possible dependencies" LIB_SHACKINSTALLER_RELATED_UNINSTALL = "%s %s was successfully removed" LIB_SHACKINSTALLER_RELATED_UNINSTALL_FAIL = "Unable to remove %s %s" LIB_SHACKINSTALLER_RELATED_UPDATE = "%s %s was successfully updated" LIB_SHACKINSTALLER_RELATED_UPDATE_FAIL = "Update of %s %s failed" LIB_SHACKINSTALLER_RELATED_UPDATE_STATE_FAILED = "Failed, version %s" LIB_SHACKINSTALLER_RELATED_UPDATE_STATE_INSTALLED = "Installed v%s" LIB_SHACKINSTALLER_RELATED_UPDATE_STATE_SKIPED = "Skipped %s, the version %s is already installed" LIB_SHACKINSTALLER_RELEASE_V = "Release: v%s" LIB_SHACKINSTALLER_SAVE_LICENSE_KEY = "Save my license key" LIB_SHACKINSTALLER_SHOW_DETAILS = "Show more details..." LIB_SHACKINSTALLER_SORTED = "Sorted [%s]" LIB_SHACKINSTALLER_THANKS_INSTALL = "Thanks for installing %s!" LIB_SHACKINSTALLER_THANKS_UPDATE = "Thanks for updating %s!" LIB_SHACKINSTALLER_WRONG_MYSQL = "Sorry, %s requires at least MySQL %s." LIB_SHACKINSTALLER_WRONG_PHP = "Sorry, %s requires at least php %s." LIB_SHACKINSTALLER_WRONG_PLATFORM = "Sorry, %s requires Joomla! %s." LIB_SHACKINSTALLER_WRONG_PREVIOUS = "Sorry, updating %s requires at least version %s to be installed first." views/installer/tmpl/default_license.php 0000644 00000014241 15247143460 0014521 0 ustar 00 <?php /** * @package ShackInstaller * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2023 Joomlashack.com. All rights reserved * @license https://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackInstaller. * * ShackInstaller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackInstaller is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>. */ use Alledia\Installer\AbstractScript; use Alledia\Installer\Extension\Generic; use Alledia\Installer\Extension\Licensed; use Joomla\CMS\Language\Text; use Joomla\CMS\Uri\Uri; defined('_JEXEC') or die(); /** * @var AbstractScript $this * @var string $type * @var Licensed $license * @var string $name * @var string $configPath * @var string $customFooterPath * @var string $extensionPath * @var Generic $licensesManagerExtension * @var string $string * @var string $path */ $licenseUpdate = Uri::root() . '/administrator/index.php?plugin=system_osmylicensesmanager&task=license.save'; if ($this->isLicensesManagerInstalled) : ?> <div class="joomlashack-license-form"> <?php if (!empty($this->licenseKey)) : ?> <a href="" class="joomlashack-installer-change-license-button btn btn-success"> <?php echo Text::_('LIB_SHACKINSTALLER_CHANGE_LICENSE_KEY'); ?> </a> <?php endif; ?> <div id="joomlashack-installer-license-panel"> <input type="text" name="joomlashack-license-keys" id="joomlashack-license-keys" value="<?php echo $this->licenseKey; ?>" class="form-control" placeholder="<?php echo Text::_('LIB_SHACKINSTALLER_LICENSE_KEYS_PLACEHOLDER'); ?>"/> <p class="joomlashack-empty-key-msg"> <?php echo Text::_('LIB_SHACKINSTALLER_MSG_LICENSE_KEYS_EMPTY'); ?> <a href="https://www.joomlashack.com/account/key/" target="_blank"> <?php echo Text::_('LIB_SHACKINSTALLER_I_DONT_REMEMBER_MY_KEY'); ?> </a> </p> <a id="joomlashack-license-save-button" class="btn btn-success" href="#"> <?php echo Text::_('LIB_SHACKINSTALLER_SAVE_LICENSE_KEY'); ?> </a> </div> <div id="joomlashack-installer-license-success" style="display: none"> <p><?php echo Text::_('LIB_SHACKINSTALLER_LICENSE_KEY_SUCCESS'); ?></p> </div> <div id="joomlashack-installer-license-error" style="display: none"> <p><?php echo Text::_('LIB_SHACKINSTALLER_LICENSE_KEY_ERROR'); ?></p> </div> </div> <script> (function() { let panel = document.getElementById('joomlashack-installer-license-panel'), updateButtons = document.getElementsByClassName('joomlashack-installer-change-license-button'), saveButton = document.getElementById('joomlashack-license-save-button'); if (panel) { if (updateButtons.length > 0) { panel.style.display = 'none'; Array.from(updateButtons).forEach(function(button) { button.addEventListener('click', function(event) { event.preventDefault(); panel.style.display = 'block'; this.style.display = 'none'; }) }); } if (saveButton) { saveButton.addEventListener('click', function(event) { event.preventDefault(); let request = new XMLHttpRequest(), data = new FormData(), keyField = document.getElementById('joomlashack-license-keys') data.append('license-keys', keyField.value) request.onreadystatechange = function(data) { if (this.readyState === XMLHttpRequest.DONE) { try { if (this.status === 200) { let result = JSON.parse(this.response), success = document.getElementById('joomlashack-installer-license-success'), error = document.getElementById('joomlashack-installer-license-error'); panel.style.display = 'none'; if (result.success) { success.style.display = 'block'; } else { error.style.display = 'block'; } } else { error.style.display = 'block'; } } catch (e) { panel.style.display = 'none'; error.style.display = 'block'; } } }; request.open('POST', '<?php echo $licenseUpdate; ?>'); request.send(data); }); } } })(); </script> <?php else : ?> <div class="error"> <?php echo Text::_('LIB_SHACKINSTALLER_LICENSE_KEYS_MANAGER_REQUIRED'); ?> </div> <?php endif; views/installer/tmpl/default_info.php 0000644 00000007710 15247143460 0014035 0 ustar 00 <?php /** * @package ShackInstaller * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2023 Joomlashack.com. All rights reserved * @license https://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackInstaller. * * ShackInstaller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackInstaller is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>. */ use Alledia\Installer\AbstractScript; use Alledia\Installer\Extension\Generic; use Alledia\Installer\Extension\Licensed; use Joomla\CMS\Language\Text; defined('_JEXEC') or die(); /** * @var AbstractScript $this * @var string $type * @var Licensed $license * @var string $name * @var string $configPath * @var string $customFooterPath * @var string $extensionPath * @var Generic $licensesManagerExtension * @var string $string * @var string $path */ ?> <div class="joomlashack-details-container"> <a href="javascript:void(0);" id="joomlashack-installer-footer-toggler"> <?php echo Text::_('LIB_SHACKINSTALLER_SHOW_DETAILS'); ?> </a> <div id="joomlashack-installer-footer" style="display: none;"> <div class="joomlashack-license"> <?php echo Text::sprintf('LIB_SHACKINSTALLER_RELEASE_V', (string)$this->manifest->version); ?> </div> <br> <?php if (!empty($this->manifest->alledia->relatedExtensions)) : ?> <table class="joomlashack-related-table"> <thead> <tr> <th colspan="2"><?php echo Text::_('LIB_SHACKINSTALLER_RELATED_EXTENSIONS'); ?></th> </tr> </thead> <tbody> <?php foreach ($this->relatedExtensionFeedback as $data) : ?> <tr> <td><?php echo Text::_($data['name']); ?></td> <td> <?php $messages = [$data['message']]; if (isset($data['publish']) && $data['publish']) { $messages[] = Text::_('LIB_SHACKINSTALLER_PUBLISHED'); } if (isset($data['ordering'])) { $messages[] = Text::sprintf('LIB_SHACKINSTALLER_SORTED', $data['ordering']); } $messages = implode(', ', $messages); echo $messages; ?> </td> </tr> <?php endforeach; ?> </tbody> </table> <?php endif; ?> <div class="joomlashack-license"> <?php echo Text::sprintf( 'LIB_SHACKINSTALLER_LICENSED_AS', $this->getName(), '<a href="https://www.gnu.org/licenses/gpl-3.0">GNU/GPL v3.0</a>' ); ?>. </div> </div> </div> <script> (function() { let footer = document.getElementById('joomlashack-installer-footer'), toggle = document.getElementById('joomlashack-installer-footer-toggler'); if (footer && toggle) { toggle.addEventListener('click', function(event) { event.preventDefault(); footer.style.display = 'block'; this.style.display = 'none'; }); } })(); </script> views/installer/tmpl/default.php 0000644 00000003564 15247143460 0013025 0 ustar 00 <?php /** * @package ShackInstaller * @contact www.joomlashack.com, help@joomlashack.com * @copyright 2016-2023 Joomlashack.com. All rights reserved * @license https://www.gnu.org/licenses/gpl.html GNU/GPL * * This file is part of ShackInstaller. * * ShackInstaller is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * ShackInstaller is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>. */ use Alledia\Installer\AbstractScript; use Alledia\Installer\Extension\Generic; use Alledia\Installer\Extension\Licensed; defined('_JEXEC') or die(); /** * @var AbstractScript $this * @var string $type * @var Licensed $license * @var string $name * @var string $configPath * @var string $customFooterPath * @var string $extensionPath * @var Generic $licensesManagerExtension * @var string $string * @var string $path */ ?> <div class="joomlashack-wrapper"> <div class="joomlashack-content"> <h2><?php echo $this->welcomeMessage; ?></h2> <?php if (is_file(__DIR__ . '/default_custom.php')) : include __DIR__ . '/default_custom.php'; endif; if ($license->isPro()) : include __DIR__ . '/default_license.php'; endif; include __DIR__ . "/default_info.php"; ?> <?php echo $this->footer; ?> </div> </div>
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0 |
proxy
|
phpinfo
|
Settings