Файловый менеджер - Редактировать - /home/wuectly/www/03cbe/Adapter.zip
Назад
PK $r!]�:�{ Fopen.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 2, or later */ namespace FOF30\Download\Adapter; defined('_JEXEC') || die; use FOF30\Download\DownloadInterface; use FOF30\Download\Exception\DownloadError; use Joomla\CMS\Language\Text; /** * A download adapter using URL fopen() wrappers */ class Fopen extends AbstractAdapter implements DownloadInterface { public function __construct() { $this->priority = 100; $this->supportsFileSize = false; $this->supportsChunkDownload = true; $this->name = 'fopen'; // If we are not allowed to use ini_get, we assume that URL fopen is disabled if (!function_exists('ini_get')) { $this->isSupported = false; } else { $this->isSupported = ini_get('allow_url_fopen'); } } /** * Download a part (or the whole) of a remote URL and return the downloaded * data. You are supposed to check the size of the returned data. If it's * smaller than what you expected you've reached end of file. If it's empty * you have tried reading past EOF. If it's larger than what you expected * the server doesn't support chunk downloads. * * If this class' supportsChunkDownload returns false you should assume * that the $from and $to parameters will be ignored. * * @param string $url The remote file's URL * @param integer $from Byte range to start downloading from. Use null for start of file. * @param integer $to Byte range to stop downloading. Use null to download the entire file ($from is * ignored) * @param array $params Additional params that will be added before performing the download * * @return string The raw file data retrieved from the remote URL. * * @throws DownloadError A generic exception is thrown on error */ public function downloadAndReturn($url, $from = null, $to = null, array $params = []) { if (empty($from)) { $from = 0; } if (empty($to)) { $to = 0; } if ($to < $from) { $temp = $to; $to = $from; $from = $temp; unset($temp); } if (!(empty($from) && empty($to))) { $options = [ 'http' => [ 'method' => 'GET', 'header' => "Range: bytes=$from-$to\r\n", ], 'ssl' => [ 'verify_peer' => true, 'cafile' => JPATH_LIBRARIES . '/src/Http/Transport/cacert.pem', 'verify_depth' => 5, ], ]; $options = array_merge($options, $params); $context = stream_context_create($options); $result = @file_get_contents($url, false, $context, $from - $to + 1); } else { $options = [ 'http' => [ 'method' => 'GET', ], 'ssl' => [ 'verify_peer' => true, 'cafile' => JPATH_LIBRARIES . '/src/Http/Transport/cacert.pem', 'verify_depth' => 5, ], ]; $options = array_merge($options, $params); $context = stream_context_create($options); $result = @file_get_contents($url, false, $context); } global $http_response_header_test; if (!isset($http_response_header) && empty($http_response_header_test)) { $error = Text::_('LIB_FOF_DOWNLOAD_ERR_FOPEN_ERROR'); throw new DownloadError($error, 404); } else { // Used for testing if (!isset($http_response_header) && !empty($http_response_header_test)) { $http_response_header = $http_response_header_test; } $http_code = 200; $nLines = count($http_response_header); for ($i = $nLines - 1; $i >= 0; $i--) { $line = $http_response_header[$i]; if (strncasecmp("HTTP", $line, 4) == 0) { $response = explode(' ', $line); $http_code = $response[1]; break; } } if ($http_code >= 299) { $error = Text::sprintf('LIB_FOF_DOWNLOAD_ERR_HTTPERROR', $http_code); throw new DownloadError($error, $http_code); } } if ($result === false) { $error = Text::sprintf('LIB_FOF_DOWNLOAD_ERR_FOPEN_ERROR'); throw new DownloadError($error, 1); } else { return $result; } } } PK $r!]@�E.g g AbstractAdapter.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 2, or later */ namespace FOF30\Download\Adapter; defined('_JEXEC') || die; use FOF30\Download\DownloadInterface; use FOF30\Download\Exception\DownloadError; abstract class AbstractAdapter implements DownloadInterface { /** * Load order priority * * @var int */ public $priority = 100; /** * Name of the adapter (identical to filename) * * @var string */ public $name = ''; /** * Is this adapter supported in the current execution environment? * * @var bool */ public $isSupported = false; /** * Does this adapter support chunked downloads? * * @var bool */ public $supportsChunkDownload = false; /** * Does this adapter support querying the remote file's size? * * @var bool */ public $supportsFileSize = false; /** * Does this download adapter support downloading files in chunks? * * @return boolean True if chunk download is supported */ public function supportsChunkDownload() { return $this->supportsChunkDownload; } /** * Does this download adapter support reading the size of a remote file? * * @return boolean True if remote file size determination is supported */ public function supportsFileSize() { return $this->supportsFileSize; } /** * Is this download class supported in the current server environment? * * @return boolean True if this server environment supports this download class */ public function isSupported() { return $this->isSupported; } /** * Get the priority of this adapter. If multiple download adapters are * supported on a site, the one with the highest priority will be * used. * * @return boolean */ public function getPriority() { return $this->priority; } /** * Returns the name of this download adapter in use * * @return string */ public function getName() { return $this->name; } /** * Download a part (or the whole) of a remote URL and return the downloaded * data. You are supposed to check the size of the returned data. If it's * smaller than what you expected you've reached end of file. If it's empty * you have tried reading past EOF. If it's larger than what you expected * the server doesn't support chunk downloads. * * If this class' supportsChunkDownload returns false you should assume * that the $from and $to parameters will be ignored. * * @param string $url The remote file's URL * @param integer $from Byte range to start downloading from. Use null for start of file. * @param integer $to Byte range to stop downloading. Use null to download the entire file ($from is * ignored) * @param array $params Additional params that will be added before performing the download * * @return string The raw file data retrieved from the remote URL. * * @throws DownloadError A generic exception is thrown on error */ public function downloadAndReturn($url, $from = null, $to = null, array $params = []) { return ''; } /** * Get the size of a remote file in bytes * * @param string $url The remote file's URL * * @return integer The file size, or -1 if the remote server doesn't support this feature */ public function getFileSize($url) { return -1; } } PK $r!]a��b b Curl.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 2, or later */ namespace FOF30\Download\Adapter; defined('_JEXEC') || die; use FOF30\Download\DownloadInterface; use FOF30\Download\Exception\DownloadError; use Joomla\CMS\Language\Text; /** * A download adapter using the cURL PHP integration */ class Curl extends AbstractAdapter implements DownloadInterface { protected $headers = []; public function __construct() { $this->priority = 110; $this->supportsFileSize = true; $this->supportsChunkDownload = true; $this->name = 'curl'; $this->isSupported = function_exists('curl_init') && function_exists('curl_exec') && function_exists('curl_close'); } /** * Download a part (or the whole) of a remote URL and return the downloaded * data. You are supposed to check the size of the returned data. If it's * smaller than what you expected you've reached end of file. If it's empty * you have tried reading past EOF. If it's larger than what you expected * the server doesn't support chunk downloads. * * If this class' supportsChunkDownload returns false you should assume * that the $from and $to parameters will be ignored. * * @param string $url The remote file's URL * @param integer $from Byte range to start downloading from. Use null for start of file. * @param integer $to Byte range to stop downloading. Use null to download the entire file ($from is * ignored) * @param array $params Additional params that will be added before performing the download * * @return string The raw file data retrieved from the remote URL. * * @throws DownloadError A generic exception is thrown on error */ public function downloadAndReturn($url, $from = null, $to = null, array $params = []) { $ch = curl_init(); if (empty($from)) { $from = 0; } if (empty($to)) { $to = 0; } if ($to < $from) { $temp = $to; $to = $from; $from = $temp; unset($temp); } curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_AUTOREFERER, 1); curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_SSLVERSION, 0); curl_setopt($ch, CURLOPT_CAINFO, JPATH_LIBRARIES . '/src/Http/Transport/cacert.pem'); curl_setopt($ch, CURLOPT_HEADERFUNCTION, [$this, 'reponseHeaderCallback']); if (!(empty($from) && empty($to))) { curl_setopt($ch, CURLOPT_RANGE, "$from-$to"); } if (!is_array($params)) { $params = []; } $patched_accept_encoding = false; // Work around LiteSpeed sending compressed output under HTTP/2 when no encoding was requested // See https://github.com/joomla/joomla-cms/issues/21423#issuecomment-410941000 if (defined('CURLOPT_ACCEPT_ENCODING')) { if (!array_key_exists(CURLOPT_ACCEPT_ENCODING, $params)) { $params[CURLOPT_ACCEPT_ENCODING] = 'identity'; } $patched_accept_encoding = true; } if (!empty($params)) { foreach ($params as $k => $v) { // I couldn't patch the accept encoding header (missing constant), so I'll check if we manually set it if (!$patched_accept_encoding && $k == CURLOPT_HTTPHEADER) { foreach ($v as $custom_header) { // Ok, we explicitly set the Accept-Encoding header, so we consider it patched if (stripos($custom_header, 'Accept-Encoding') !== false) { $patched_accept_encoding = true; } } } @curl_setopt($ch, $k, $v); } } // Accept encoding wasn't patched, let's manually do that if (!$patched_accept_encoding) { @curl_setopt($ch, CURLOPT_HTTPHEADER, ['Accept-Encoding: identity']); $patched_accept_encoding = true; } $result = curl_exec($ch); $errno = curl_errno($ch); $errmsg = curl_error($ch); $error = ''; $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($result === false) { $error = Text::sprintf('LIB_FOF_DOWNLOAD_ERR_CURL_ERROR', $errno, $errmsg); } elseif (($http_status >= 300) && ($http_status <= 399) && isset($this->headers['location']) && !empty($this->headers['location'])) { return $this->downloadAndReturn($this->headers['location'], $from, $to, $params); } elseif ($http_status > 399) { $result = false; $errno = $http_status; $error = Text::sprintf('LIB_FOF_DOWNLOAD_ERR_HTTPERROR', $http_status); } curl_close($ch); if ($result === false) { throw new DownloadError($error, $errno); } else { return $result; } } /** * Get the size of a remote file in bytes * * @param string $url The remote file's URL * * @return integer The file size, or -1 if the remote server doesn't support this feature */ public function getFileSize($url) { $result = -1; $ch = curl_init(); curl_setopt($ch, CURLOPT_AUTOREFERER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_SSLVERSION, 0); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_NOBODY, true); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_CAINFO, JPATH_LIBRARIES . '/src/Http/Transport/cacert.pem'); $data = curl_exec($ch); curl_close($ch); if ($data) { $content_length = "unknown"; $status = "unknown"; $redirection = null; if (preg_match("/^HTTP\/1\.[01] (\d\d\d)/i", $data, $matches)) { $status = (int) $matches[1]; } if (preg_match("/Content-Length: (\d+)/i", $data, $matches)) { $content_length = (int) $matches[1]; } if (preg_match("/Location: (.*)/i", $data, $matches)) { $redirection = (int) $matches[1]; } if ($status == 200 || ($status > 300 && $status <= 308)) { $result = $content_length; } if (($status > 300) && ($status <= 308)) { if (!empty($redirection)) { return $this->getFileSize($redirection); } return -1; } } return $result; } /** * Handles the HTTP headers returned by cURL * * @param resource $ch cURL resource handle (unused) * @param string $data Each header line, as returned by the server * * @return int The length of the $data string */ protected function reponseHeaderCallback(&$ch, &$data) { $strlen = strlen($data); if (($strlen) <= 2) { return $strlen; } if (substr($data, 0, 4) == 'HTTP') { return $strlen; } if (strpos($data, ':') === false) { return $strlen; } [$header, $value] = explode(': ', trim($data), 2); $this->headers[strtolower($header)] = $value; return $strlen; } } PK �t!]`�ߍ� � AdapterInstance.phpnu &1i� <?php /** * Joomla! Content Management System * * @copyright (C) 2008 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Adapter; defined('JPATH_PLATFORM') or die; use Joomla\CMS\Object\CMSObject; /** * Adapter Instance Class * * @since 1.6 * @deprecated 5.0 Will be removed without replacement */ class AdapterInstance extends CMSObject { /** * Parent * * @var Adapter * @since 1.6 */ protected $parent = null; /** * Database * * @var \JDatabaseDriver * @since 1.6 */ protected $db = null; /** * Constructor * * @param Adapter $parent Parent object * @param \JDatabaseDriver $db Database object * @param array $options Configuration Options * * @since 1.6 */ public function __construct(Adapter $parent, \JDatabaseDriver $db, array $options = array()) { // Set the properties from the options array that is passed in $this->setProperties($options); // Set the parent and db in case $options for some reason overrides it. $this->parent = $parent; // Pull in the global dbo in case something happened to it. $this->db = $db ?: \JFactory::getDbo(); } /** * Retrieves the parent object * * @return Adapter * * @since 1.6 */ public function getParent() { return $this->parent; } } PK �t!] ��� � Adapter.phpnu &1i� <?php /** * Joomla! Content Management System * * @copyright (C) 2008 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Adapter; defined('JPATH_PLATFORM') or die; use Joomla\CMS\Object\CMSObject; /** * Adapter Class * Retains common adapter pattern functions * Class harvested from joomla.installer.installer * * @since 1.6 * @deprecated 5.0 Will be removed without replacement */ class Adapter extends CMSObject { /** * Associative array of adapters * * @var static[] * @since 1.6 */ protected $_adapters = array(); /** * Adapter Folder * * @var string * @since 1.6 */ protected $_adapterfolder = 'adapters'; /** * Adapter Class Prefix * * @var string * @since 1.6 */ protected $_classprefix = 'J'; /** * Base Path for the adapter instance * * @var string * @since 1.6 */ protected $_basepath = null; /** * Database Connector Object * * @var \JDatabaseDriver * @since 1.6 */ protected $_db; /** * Constructor * * @param string $basepath Base Path of the adapters * @param string $classprefix Class prefix of adapters * @param string $adapterfolder Name of folder to append to base path * * @since 1.6 */ public function __construct($basepath, $classprefix = null, $adapterfolder = null) { $this->_basepath = $basepath; $this->_classprefix = $classprefix ? $classprefix : 'J'; $this->_adapterfolder = $adapterfolder ? $adapterfolder : 'adapters'; $this->_db = \JFactory::getDbo(); } /** * Get the database connector object * * @return \JDatabaseDriver Database connector object * * @since 1.6 */ public function getDbo() { return $this->_db; } /** * Return an adapter. * * @param string $name Name of adapter to return * @param array $options Adapter options * * @return static|boolean Adapter of type 'name' or false * * @since 1.6 */ public function getAdapter($name, $options = array()) { if (array_key_exists($name, $this->_adapters)) { return $this->_adapters[$name]; } if ($this->setAdapter($name, $options)) { return $this->_adapters[$name]; } return false; } /** * Set an adapter by name * * @param string $name Adapter name * @param object &$adapter Adapter object * @param array $options Adapter options * * @return boolean True if successful * * @since 1.6 */ public function setAdapter($name, &$adapter = null, $options = array()) { if (is_object($adapter)) { $this->_adapters[$name] = &$adapter; return true; } $class = rtrim($this->_classprefix, '\\') . '\\' . ucfirst($name); if (class_exists($class)) { $this->_adapters[$name] = new $class($this, $this->_db, $options); return true; } $class = rtrim($this->_classprefix, '\\') . '\\' . ucfirst($name) . 'Adapter'; if (class_exists($class)) { $this->_adapters[$name] = new $class($this, $this->_db, $options); return true; } $fullpath = $this->_basepath . '/' . $this->_adapterfolder . '/' . strtolower($name) . '.php'; if (!file_exists($fullpath)) { return false; } // Try to load the adapter object $class = $this->_classprefix . ucfirst($name); \JLoader::register($class, $fullpath); if (!class_exists($class)) { return false; } $this->_adapters[$name] = new $class($this, $this->_db, $options); return true; } /** * Loads all adapters. * * @param array $options Adapter options * * @return void * * @since 1.6 */ public function loadAllAdapters($options = array()) { $files = new \DirectoryIterator($this->_basepath . '/' . $this->_adapterfolder); /* @type $file \DirectoryIterator */ foreach ($files as $file) { $fileName = $file->getFilename(); // Only load for php files. if (!$file->isFile() || $file->getExtension() != 'php') { continue; } // Try to load the adapter object require_once $this->_basepath . '/' . $this->_adapterfolder . '/' . $fileName; // Derive the class name from the filename. $name = str_ireplace('.php', '', ucfirst(trim($fileName))); $class = $this->_classprefix . ucfirst($name); if (!class_exists($class)) { // Skip to next one continue; } $adapter = new $class($this, $this->_db, $options); $this->_adapters[$name] = clone $adapter; } } } PK b�!]�g�5 5 LibraryAdapter.phpnu &1i� <?php /** * Joomla! Content Management System * * @copyright (C) 2008 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Installer\Adapter; defined('JPATH_PLATFORM') or die; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Installer\InstallerAdapter; use Joomla\CMS\Installer\Manifest\LibraryManifest; use Joomla\CMS\Table\Table; use Joomla\CMS\Table\Update; \JLoader::import('joomla.filesystem.folder'); /** * Library installer * * @since 3.1 */ class LibraryAdapter extends InstallerAdapter { /** * Method to check if the extension is present in the filesystem, flags the route as update if so * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function checkExtensionInFilesystem() { if ($this->currentExtensionId) { // Already installed, can we upgrade? if ($this->parent->isOverwrite() || $this->parent->isUpgrade()) { // We can upgrade, so uninstall the old one $installer = new Installer; // we don't want to compromise this instance! $installer->setPackageUninstall(true); $installer->uninstall('library', $this->currentExtensionId); // Clear the cached data $this->currentExtensionId = null; $this->extension = Table::getInstance('Extension', 'JTable', array('dbo' => $this->db)); // From this point we'll consider this an update $this->setRoute('update'); } else { // Abort the install, no upgrade possible throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ABORT_LIB_INSTALL_ALREADY_INSTALLED')); } } } /** * Method to copy the extension's base files from the `<files>` tag(s) and the manifest file * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function copyBaseFiles() { if ($this->parent->parseFiles($this->getManifest()->files, -1) === false) { throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ABORT_LIB_COPY_FILES')); } } /** * Method to finalise the installation processing * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function finaliseInstall() { // Clobber any possible pending updates /** @var Update $update */ $update = Table::getInstance('update'); $uid = $update->find( array( 'element' => $this->element, 'type' => $this->type, ) ); if ($uid) { $update->delete($uid); } // Lastly, we will copy the manifest file to its appropriate place. if ($this->route !== 'discover_install') { $manifest = array(); $manifest['src'] = $this->parent->getPath('manifest'); $manifest['dest'] = JPATH_MANIFESTS . '/libraries/' . $this->element . '.xml'; $destFolder = dirname($manifest['dest']); if (!is_dir($destFolder) && !@mkdir($destFolder)) { // Install failed, rollback changes throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ABORT_LIB_INSTALL_COPY_SETUP')); } if (!$this->parent->copyFiles(array($manifest), true)) { // Install failed, rollback changes throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ABORT_LIB_INSTALL_COPY_SETUP')); } // If there is a manifest script, let's copy it. if ($this->manifest_script) { $path['src'] = $this->parent->getPath('source') . '/' . $this->manifest_script; $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->manifest_script; if ($this->parent->isOverwrite() || !file_exists($path['dest'])) { if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_MANIFEST', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)) ) ); } } } } } /** * Get the filtered extension element from the manifest * * @param string $element Optional element name to be converted * * @return string The filtered element * * @since 3.4 */ public function getElement($element = null) { if (!$element) { $element = (string) $this->getManifest()->libraryname; } return $element; } /** * Custom loadLanguage method * * @param string $path The path where to find language files. * * @return void * * @since 3.1 */ public function loadLanguage($path = null) { $source = $this->parent->getPath('source'); if (!$source) { $this->parent->setPath('source', JPATH_PLATFORM . '/' . $this->getElement()); } $extension = 'lib_' . str_replace('/', '_', $this->getElement()); $librarypath = (string) $this->getManifest()->libraryname; $source = $path ?: JPATH_PLATFORM . '/' . $librarypath; $this->doLoadLanguage($extension, $source, JPATH_SITE); } /** * Method to parse optional tags in the manifest * * @return void * * @since 3.4 */ protected function parseOptionalTags() { $this->parent->parseLanguages($this->getManifest()->languages); $this->parent->parseMedia($this->getManifest()->media); } /** * Prepares the adapter for a discover_install task * * @return void * * @since 3.4 */ public function prepareDiscoverInstall() { $manifestPath = JPATH_MANIFESTS . '/libraries/' . $this->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $this->setManifest($this->parent->getManifest()); } /** * Method to do any prechecks and setup the install paths for the extension * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function setupInstallPaths() { $group = (string) $this->getManifest()->libraryname; if (!$group) { throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ABORT_LIB_INSTALL_NOFILE')); } // Don't install libraries which would override core folders $restrictedFolders = array('cms', 'fof', 'idna_convert', 'joomla', 'legacy', 'php-encryption', 'phpass', 'phputf8', 'src', 'vendor'); if (in_array($group, $restrictedFolders)) { throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ABORT_LIB_INSTALL_CORE_FOLDER')); } $this->parent->setPath('extension_root', JPATH_PLATFORM . '/' . implode(DIRECTORY_SEPARATOR, explode('/', $group))); } /** * Method to store the extension to the database * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function storeExtension() { // Discover installs are stored a little differently if ($this->route === 'discover_install') { $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->extension->manifest_cache = json_encode($manifest_details); $this->extension->state = 0; $this->extension->name = $manifest_details['name']; $this->extension->enabled = 1; $this->extension->params = $this->parent->getParams(); if (!$this->extension->store()) { // Install failed, roll back changes throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ERROR_LIB_DISCOVER_STORE_DETAILS')); } return; } $this->extension->name = $this->name; $this->extension->type = 'library'; $this->extension->element = $this->element; // There is no folder for libraries $this->extension->folder = ''; $this->extension->enabled = 1; $this->extension->protected = 0; $this->extension->access = 1; $this->extension->client_id = 0; $this->extension->params = $this->parent->getParams(); // Custom data $this->extension->custom_data = ''; $this->extension->system_data = ''; // Update the manifest cache for the entry $this->extension->manifest_cache = $this->parent->generateManifestCache(); if (!$this->extension->store()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_LIB_INSTALL_ROLLBACK', $this->extension->getError() ) ); } // Since we have created a library item, we add it to the installation step stack // so that if we have to rollback the changes we can undo it. $this->parent->pushStep(array('type' => 'extension', 'id' => $this->extension->extension_id)); } /** * Custom uninstall method * * @param string $id The id of the library to uninstall. * * @return boolean True on success * * @since 3.1 */ public function uninstall($id) { $retval = true; // First order of business will be to load the module object table from the database. // This should give us the necessary information to proceed. $row = Table::getInstance('extension'); if (!$row->load((int) $id) || $row->element === '') { \JLog::add(\JText::_('ERRORUNKOWNEXTENSION'), \JLog::WARNING, 'jerror'); return false; } // Is the library we are trying to uninstall a core one? // Because that is not a good idea... if ($row->protected) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_LIB_UNINSTALL_WARNCORELIBRARY'), \JLog::WARNING, 'jerror'); return false; } /* * Does this extension have a parent package? * If so, check if the package disallows individual extensions being uninstalled if the package is not being uninstalled */ if ($row->package_id && !$this->parent->isPackageUninstall() && !$this->canUninstallPackageChild($row->package_id)) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_CANNOT_UNINSTALL_CHILD_OF_PACKAGE', $row->name), \JLog::WARNING, 'jerror'); return false; } $manifestFile = JPATH_MANIFESTS . '/libraries/' . $row->element . '.xml'; // Because libraries may not have their own folders we cannot use the standard method of finding an installation manifest if (file_exists($manifestFile)) { $manifest = new LibraryManifest($manifestFile); // Set the library root path $this->parent->setPath('extension_root', JPATH_PLATFORM . '/' . $manifest->libraryname); $xml = simplexml_load_file($manifestFile); // If we cannot load the XML file return null if (!$xml) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_LIB_UNINSTALL_LOAD_MANIFEST'), \JLog::WARNING, 'jerror'); return false; } // Check for a valid XML root tag. if ($xml->getName() !== 'extension') { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_LIB_UNINSTALL_INVALID_MANIFEST'), \JLog::WARNING, 'jerror'); return false; } $this->parent->removeFiles($xml->files, -1); \JFile::delete($manifestFile); } else { // Remove this row entry since its invalid $row->delete($row->extension_id); unset($row); \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_LIB_UNINSTALL_INVALID_NOTFOUND_MANIFEST'), \JLog::WARNING, 'jerror'); return false; } // TODO: Change this so it walked up the path backwards so we clobber multiple empties // If the folder is empty, let's delete it if (\JFolder::exists($this->parent->getPath('extension_root'))) { if (is_dir($this->parent->getPath('extension_root'))) { $files = \JFolder::files($this->parent->getPath('extension_root')); if (!count($files)) { \JFolder::delete($this->parent->getPath('extension_root')); } } } $this->parent->removeFiles($xml->media); $this->parent->removeFiles($xml->languages); $elementParts = explode('/', $row->element); // Delete empty vendor folders if (2 === count($elementParts)) { @rmdir(JPATH_MANIFESTS . '/libraries/' . $elementParts[0]); @rmdir(JPATH_PLATFORM . '/' . $elementParts[0]); } $row->delete($row->extension_id); unset($row); return $retval; } /** * Custom discover method * * @return array Extension list of extensions available * * @since 3.1 */ public function discover() { $results = array(); $mainFolder = JPATH_MANIFESTS . '/libraries'; $folder = new \RecursiveDirectoryIterator($mainFolder); $iterator = new \RegexIterator( new \RecursiveIteratorIterator($folder), '/\.xml$/i', \RecursiveRegexIterator::GET_MATCH ); foreach ($iterator as $file => $pattern) { $element = str_replace(array($mainFolder . DIRECTORY_SEPARATOR, '.xml'), '', $file); $manifestCache = Installer::parseXMLInstallFile($file); $extension = Table::getInstance('extension'); $extension->set('type', 'library'); $extension->set('client_id', 0); $extension->set('element', $element); $extension->set('folder', ''); $extension->set('name', $element); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifestCache)); $extension->set('params', '{}'); $results[] = $extension; } return $results; } /** * Refreshes the extension table cache * * @return boolean Result of operation, true if updated, false on failure * * @since 3.1 */ public function refreshManifestCache() { // Need to find to find where the XML file is since we don't store this normally $manifestPath = JPATH_MANIFESTS . '/libraries/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; try { return $this->parent->extension->store(); } catch (\RuntimeException $e) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_LIB_REFRESH_MANIFEST_CACHE'), \JLog::WARNING, 'jerror'); return false; } } } PK b�!]o,�Dg g LanguageAdapter.phpnu &1i� <?php /** * Joomla! Content Management System * * @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Installer\Adapter; defined('JPATH_PLATFORM') or die; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Installer\InstallerAdapter; use Joomla\CMS\Language\Language; use Joomla\CMS\Language\LanguageHelper; use Joomla\CMS\Table\Table; use Joomla\Registry\Registry; jimport('joomla.filesystem.folder'); /** * Language installer * * @since 3.1 */ class LanguageAdapter extends InstallerAdapter { /** * Core language pack flag * * @var boolean * @since 3.0.0 */ protected $core = false; /** * Method to copy the extension's base files from the `<files>` tag(s) and the manifest file * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function copyBaseFiles() { // TODO - Refactor adapter to use common code } /** * Method to do any prechecks and setup the install paths for the extension * * @return void * * @since 3.4 */ protected function setupInstallPaths() { // TODO - Refactor adapter to use common code } /** * Method to store the extension to the database * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function storeExtension() { // TODO - Refactor adapter to use common code } /** * Custom install method * * Note: This behaves badly due to hacks made in the middle of 1.5.x to add * the ability to install multiple distinct packs in one install. The * preferred method is to use a package to install multiple language packs. * * @return boolean|integer The extension ID on success, boolean false on failure * * @since 3.1 */ public function install() { $source = $this->parent->getPath('source'); if (!$source) { $this->parent ->setPath( 'source', ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/language/' . $this->parent->extension->element ); } $this->setManifest($this->parent->getManifest()); // Get the client application target if ($cname = (string) $this->getManifest()->attributes()->client) { // Attempt to map the client to a base path $client = ApplicationHelper::getClientInfo($cname, true); if ($client === null) { $this->parent->abort(\JText::sprintf('JLIB_INSTALLER_ABORT', \JText::sprintf('JLIB_INSTALLER_ERROR_UNKNOWN_CLIENT_TYPE', $cname))); return false; } $basePath = $client->path; $clientId = $client->id; $element = $this->getManifest()->files; return $this->_install($cname, $basePath, $clientId, $element); } else { // No client attribute was found so we assume the site as the client $cname = 'site'; $basePath = JPATH_SITE; $clientId = 0; $element = $this->getManifest()->files; return $this->_install($cname, $basePath, $clientId, $element); } } /** * Install function that is designed to handle individual clients * * @param string $cname Cname @todo: not used * @param string $basePath The base name. * @param integer $clientId The client id. * @param object &$element The XML element. * * @return boolean|integer The extension ID on success, boolean false on failure * * @since 3.1 */ protected function _install($cname, $basePath, $clientId, &$element) { $this->setManifest($this->parent->getManifest()); // Get the language name // Set the extensions name $name = \JFilterInput::getInstance()->clean((string) $this->getManifest()->name, 'string'); $this->set('name', $name); // Get the Language tag [ISO tag, eg. en-GB] $tag = (string) $this->getManifest()->tag; // Check if we found the tag - if we didn't, we may be trying to install from an older language package if (!$tag) { $this->parent->abort(\JText::sprintf('JLIB_INSTALLER_ABORT', \JText::_('JLIB_INSTALLER_ERROR_NO_LANGUAGE_TAG'))); return false; } $this->set('tag', $tag); // Set the language installation path $this->parent->setPath('extension_site', $basePath . '/language/' . $tag); // Do we have a meta file in the file list? In other words... is this a core language pack? if ($element && count($element->children())) { $files = $element->children(); foreach ($files as $file) { if ((string) $file->attributes()->file === 'meta') { $this->core = true; break; } } } // If the language directory does not exist, let's create it $created = false; if (!file_exists($this->parent->getPath('extension_site'))) { if (!$created = \JFolder::create($this->parent->getPath('extension_site'))) { $this->parent ->abort( \JText::sprintf( 'JLIB_INSTALLER_ABORT', \JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_FOLDER_FAILED', $this->parent->getPath('extension_site')) ) ); return false; } } else { // Look for an update function or update tag $updateElement = $this->getManifest()->update; // Upgrade manually set or update tag detected if ($updateElement || $this->parent->isUpgrade()) { // Transfer control to the update function return $this->update(); } elseif (!$this->parent->isOverwrite()) { // Overwrite is set // We didn't have overwrite set, find an update function or find an update tag so lets call it safe if (file_exists($this->parent->getPath('extension_site'))) { // If the site exists say so. \JLog::add( \JText::sprintf('JLIB_INSTALLER_ABORT', \JText::sprintf('JLIB_INSTALLER_ERROR_FOLDER_IN_USE', $this->parent->getPath('extension_site'))), \JLog::WARNING, 'jerror' ); } else { // If the admin exists say so. \JLog::add( \JText::sprintf('JLIB_INSTALLER_ABORT', \JText::sprintf('JLIB_INSTALLER_ERROR_FOLDER_IN_USE', $this->parent->getPath('extension_administrator')) ), \JLog::WARNING, 'jerror' ); } return false; } } /* * If we created the language directory we will want to remove it if we * have to roll back the installation, so let's add it to the installation * step stack */ if ($created) { $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_site'))); } // Copy all the necessary files if ($this->parent->parseFiles($element) === false) { // Install failed, rollback changes $this->parent->abort(); return false; } // Parse optional tags $this->parent->parseMedia($this->getManifest()->media); /* * Log that PDF Fonts in language packs are deprecated and will be removed in 4.0 * Ref: https://github.com/joomla/joomla-cms/issues/31286 */ if (is_dir($basePath . '/language/pdf_fonts')) { try { \JLog::add( 'Using the "pdf_fonts" folder to load language specific fonts in languages is deprecated and will be removed in 4.0.', \JLog::WARNING, 'deprecated' ); } catch (RuntimeException $exception) { // Informational log only } } // Copy all the necessary font files to the common pdf_fonts directory $this->parent->setPath('extension_site', $basePath . '/language/pdf_fonts'); $overwrite = $this->parent->setOverwrite(true); if ($this->parent->parseFiles($this->getManifest()->fonts) === false) { // Install failed, rollback changes $this->parent->abort(); return false; } $this->parent->setOverwrite($overwrite); // Get the language description $description = (string) $this->getManifest()->description; if ($description) { $this->parent->set('message', \JText::_($description)); } else { $this->parent->set('message', ''); } // Add an entry to the extension table with a whole heap of defaults $row = Table::getInstance('extension'); $row->set('name', $this->get('name')); $row->set('type', 'language'); $row->set('element', $this->get('tag')); // There is no folder for languages $row->set('folder', ''); $row->set('enabled', 1); $row->set('protected', 0); $row->set('access', 0); $row->set('client_id', $clientId); $row->set('params', $this->parent->getParams()); $row->set('manifest_cache', $this->parent->generateManifestCache()); if (!$row->check() || !$row->store()) { // Install failed, roll back changes $this->parent->abort(\JText::sprintf('JLIB_INSTALLER_ABORT', $row->getError())); return false; } // Create an unpublished content language. if ((int) $clientId === 0) { $manifestfile = JPATH_SITE . '/language/' . $this->tag . '/' . $this->tag . '.xml'; if (!is_file($manifestfile)) { $manifestfile = JPATH_SITE . '/language/' . $this->tag . '/langmetadata.xml'; } // Load the site language manifest. $siteLanguageManifest = LanguageHelper::parseXMLLanguageFile($manifestfile); // Set the content language title as the language metadata name. $contentLanguageTitle = $siteLanguageManifest['name']; // Set, as fallback, the content language native title to the language metadata name. $contentLanguageNativeTitle = $contentLanguageTitle; // If exist, load the native title from the language xml metadata. if (isset($siteLanguageManifest['nativeName']) && $siteLanguageManifest['nativeName']) { $contentLanguageNativeTitle = $siteLanguageManifest['nativeName']; } // Try to load a language string from the installation language var. Will be removed in 4.0. if ($contentLanguageNativeTitle === $contentLanguageTitle) { $manifestfile = JPATH_INSTALLATION . '/language/' . $this->tag . '/' . $this->tag . '.xml'; if (!is_file($manifestfile)) { $manifestfile = JPATH_INSTALLATION . '/language/' . $this->tag . '/langmetadata.xml'; } if (file_exists($manifestfile)) { $installationLanguage = new Language($this->tag); $installationLanguage->load('', JPATH_INSTALLATION); if ($installationLanguage->hasKey('INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME')) { // Make sure it will not use the en-GB fallback. $defaultLanguage = new Language('en-GB'); $defaultLanguage->load('', JPATH_INSTALLATION); $defaultLanguageNativeTitle = $defaultLanguage->_('INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME'); $installationLanguageNativeTitle = $installationLanguage->_('INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME'); if ($defaultLanguageNativeTitle !== $installationLanguageNativeTitle) { $contentLanguageNativeTitle = $installationLanguage->_('INSTL_DEFAULTLANGUAGE_NATIVE_LANGUAGE_NAME'); } } } } // Prepare language data for store. $languageData = array( 'lang_id' => 0, 'lang_code' => $this->tag, 'title' => $contentLanguageTitle, 'title_native' => $contentLanguageNativeTitle, 'sef' => $this->getSefString($this->tag), 'image' => strtolower(str_replace('-', '_', $this->tag)), 'published' => 0, 'ordering' => 0, 'access' => (int) \JFactory::getConfig()->get('access', 1), 'description' => '', 'metakey' => '', 'metadesc' => '', 'sitename' => '', ); $tableLanguage = Table::getInstance('language'); if (!$tableLanguage->bind($languageData) || !$tableLanguage->check() || !$tableLanguage->store() || !$tableLanguage->reorder()) { \JLog::add( \JText::sprintf('JLIB_INSTALLER_WARNING_UNABLE_TO_INSTALL_CONTENT_LANGUAGE', $siteLanguageManifest['name'], $tableLanguage->getError()), \JLog::NOTICE, 'jerror' ); } } // Clobber any possible pending updates $update = Table::getInstance('update'); $uid = $update->find(array('element' => $this->get('tag'), 'type' => 'language', 'folder' => '')); if ($uid) { $update->delete($uid); } // Clean installed languages cache. \JFactory::getCache()->clean('com_languages'); return $row->get('extension_id'); } /** * Gets a unique language SEF string. * * This function checks other existing language with the same code, if they exist provides a unique SEF name. * For instance: en-GB, en-US and en-AU will share the same SEF code by default: www.mywebsite.com/en/ * To avoid this conflict, this function creates an specific SEF in case of existing conflict: * For example: www.mywebsite.com/en-au/ * * @param string $itemLanguageTag Language Tag. * * @return string * * @since 3.7.0 */ protected function getSefString($itemLanguageTag) { $langs = explode('-', $itemLanguageTag); $prefixToFind = $langs[0]; $numberPrefixesFound = 0; // Get the sef value of all current content languages. $db = \JFactory::getDbo(); $query = $db->getQuery(true) ->select($db->qn('sef')) ->from($db->qn('#__languages')); $db->setQuery($query); $siteLanguages = $db->loadObjectList(); foreach ($siteLanguages as $siteLang) { if ($siteLang->sef === $prefixToFind) { $numberPrefixesFound++; } } return $numberPrefixesFound === 0 ? $prefixToFind : strtolower($itemLanguageTag); } /** * Custom update method * * @return boolean True on success, false on failure * * @since 3.1 */ public function update() { $xml = $this->parent->getManifest(); $this->setManifest($xml); $cname = $xml->attributes()->client; // Attempt to map the client to a base path $client = ApplicationHelper::getClientInfo($cname, true); if ($client === null || (empty($cname) && $cname !== 0)) { $this->parent->abort(\JText::sprintf('JLIB_INSTALLER_ABORT', \JText::sprintf('JLIB_INSTALLER_ERROR_UNKNOWN_CLIENT_TYPE', $cname))); return false; } $basePath = $client->path; $clientId = $client->id; // Get the language name // Set the extensions name $name = (string) $this->getManifest()->name; $name = \JFilterInput::getInstance()->clean($name, 'string'); $this->set('name', $name); // Get the Language tag [ISO tag, eg. en-GB] $tag = (string) $xml->tag; // Check if we found the tag - if we didn't, we may be trying to install from an older language package if (!$tag) { $this->parent->abort(\JText::sprintf('JLIB_INSTALLER_ABORT', \JText::_('JLIB_INSTALLER_ERROR_NO_LANGUAGE_TAG'))); return false; } $this->set('tag', $tag); // Set the language installation path $this->parent->setPath('extension_site', $basePath . '/language/' . $tag); // Do we have a meta file in the file list? In other words... is this a core language pack? if (count($xml->files->children())) { foreach ($xml->files->children() as $file) { if ((string) $file->attributes()->file === 'meta') { $this->core = true; break; } } } // Copy all the necessary files if ($this->parent->parseFiles($xml->files) === false) { // Install failed, rollback changes $this->parent->abort(); return false; } // Parse optional tags $this->parent->parseMedia($xml->media); /* * Log that PDF Fonts in language packs are deprecated and will be removed in 4.0 * Ref: https://github.com/joomla/joomla-cms/issues/31286 */ if (is_dir($basePath . '/language/pdf_fonts')) { try { \JLog::add( 'Using the "pdf_fonts" folder to load language specific fonts in languages is deprecated and will be removed in 4.0.', \JLog::WARNING, 'deprecated' ); } catch (RuntimeException $exception) { // Informational log only } } // Copy all the necessary font files to the common pdf_fonts directory $this->parent->setPath('extension_site', $basePath . '/language/pdf_fonts'); $overwrite = $this->parent->setOverwrite(true); if ($this->parent->parseFiles($xml->fonts) === false) { // Install failed, rollback changes $this->parent->abort(); return false; } $this->parent->setOverwrite($overwrite); // Get the language description and set it as message $this->parent->set('message', (string) $xml->description); /** * --------------------------------------------------------------------------------------------- * Finalization and Cleanup Section * --------------------------------------------------------------------------------------------- */ // Clobber any possible pending updates $update = Table::getInstance('update'); $uid = $update->find(array('element' => $this->get('tag'), 'type' => 'language', 'client_id' => $clientId)); if ($uid) { $update->delete($uid); } // Update an entry to the extension table $row = Table::getInstance('extension'); $eid = $row->find(array('element' => $this->get('tag'), 'type' => 'language', 'client_id' => $clientId)); if ($eid) { $row->load($eid); } else { // Set the defaults // There is no folder for language $row->set('folder', ''); $row->set('enabled', 1); $row->set('protected', 0); $row->set('access', 0); $row->set('client_id', $clientId); $row->set('params', $this->parent->getParams()); } $row->set('name', $this->get('name')); $row->set('type', 'language'); $row->set('element', $this->get('tag')); $row->set('manifest_cache', $this->parent->generateManifestCache()); // Clean installed languages cache. \JFactory::getCache()->clean('com_languages'); if (!$row->check() || !$row->store()) { // Install failed, roll back changes $this->parent->abort(\JText::sprintf('JLIB_INSTALLER_ABORT', $row->getError())); return false; } return $row->get('extension_id'); } /** * Custom uninstall method * * @param string $eid The tag of the language to uninstall * * @return boolean True on success * * @since 3.1 */ public function uninstall($eid) { // Load up the extension details $extension = Table::getInstance('extension'); $extension->load($eid); // Grab a copy of the client details $client = ApplicationHelper::getClientInfo($extension->get('client_id')); // Check the element isn't blank to prevent nuking the languages directory...just in case $element = $extension->get('element'); if (empty($element)) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_ELEMENT_EMPTY'), \JLog::WARNING, 'jerror'); return false; } // Check that the language is not protected, Normally en-GB. $protected = $extension->get('protected'); if ($protected == 1) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_PROTECTED'), \JLog::WARNING, 'jerror'); return false; } // Verify that it's not the default language for that client $params = ComponentHelper::getParams('com_languages'); if ($params->get($client->name) === $element) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_DEFAULT'), \JLog::WARNING, 'jerror'); return false; } /* * Does this extension have a parent package? * If so, check if the package disallows individual extensions being uninstalled if the package is not being uninstalled */ if ($extension->package_id && !$this->parent->isPackageUninstall() && !$this->canUninstallPackageChild($extension->package_id)) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_CANNOT_UNINSTALL_CHILD_OF_PACKAGE', $extension->name), \JLog::WARNING, 'jerror'); return false; } // Construct the path from the client, the language and the extension element name $path = $client->path . '/language/' . $element; // Get the package manifest object and remove media $this->parent->setPath('source', $path); // We do findManifest to avoid problem when uninstalling a list of extension: getManifest cache its manifest file $this->parent->findManifest(); $this->setManifest($this->parent->getManifest()); $this->parent->removeFiles($this->getManifest()->media); // Check it exists if (!\JFolder::exists($path)) { // If the folder doesn't exist lets just nuke the row as well and presume the user killed it for us $extension->delete(); \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_PATH_EMPTY'), \JLog::WARNING, 'jerror'); return false; } if (!\JFolder::delete($path)) { // If deleting failed we'll leave the extension entry in tact just in case \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_DIRECTORY'), \JLog::WARNING, 'jerror'); return false; } // Remove the extension table entry $extension->delete(); // Setting the language of users which have this language as the default language $db = \JFactory::getDbo(); $query = $db->getQuery(true) ->from('#__users') ->select('*'); $db->setQuery($query); $users = $db->loadObjectList(); if ($client->name === 'administrator') { $param_name = 'admin_language'; } else { $param_name = 'language'; } $count = 0; foreach ($users as $user) { $registry = new Registry($user->params); if ($registry->get($param_name) === $element) { $registry->set($param_name, ''); $query->clear() ->update('#__users') ->set('params=' . $db->quote($registry)) ->where('id=' . (int) $user->id); $db->setQuery($query); $db->execute(); $count++; } } // Clean installed languages cache. \JFactory::getCache()->clean('com_languages'); if (!empty($count)) { \JLog::add(\JText::plural('JLIB_INSTALLER_NOTICE_LANG_RESET_USERS', $count), \JLog::NOTICE, 'jerror'); } // All done! return true; } /** * Custom discover method * Finds language files * * @return boolean True on success * * @since 3.1 */ public function discover() { $results = array(); $site_languages = \JFolder::folders(JPATH_SITE . '/language'); $admin_languages = \JFolder::folders(JPATH_ADMINISTRATOR . '/language'); foreach ($site_languages as $language) { $manifestfile = JPATH_SITE . '/language/' . $language . '/langmetadata.xml'; if (!is_file($manifestfile)) { $manifestfile = JPATH_SITE . '/language/' . $language . '/' . $language . '.xml'; if (!is_file($manifestfile)) { continue; } } $manifest_details = Installer::parseXMLInstallFile($manifestfile); $extension = Table::getInstance('extension'); $extension->set('type', 'language'); $extension->set('client_id', 0); $extension->set('element', $language); $extension->set('folder', ''); $extension->set('name', $language); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $extension->set('params', '{}'); $results[] = $extension; } foreach ($admin_languages as $language) { $manifestfile = JPATH_ADMINISTRATOR . '/language/' . $language . '/langmetadata.xml'; if (!is_file($manifestfile)) { $manifestfile = JPATH_ADMINISTRATOR . '/language/' . $language . '/' . $language . '.xml'; if (!is_file($manifestfile)) { continue; } } $manifest_details = Installer::parseXMLInstallFile($manifestfile); $extension = Table::getInstance('extension'); $extension->set('type', 'language'); $extension->set('client_id', 1); $extension->set('element', $language); $extension->set('folder', ''); $extension->set('name', $language); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $extension->set('params', '{}'); $results[] = $extension; } return $results; } /** * Custom discover install method * Basically updates the manifest cache and leaves everything alone * * @return integer The extension id * * @since 3.1 */ public function discover_install() { // Need to find to find where the XML file is since we don't store this normally $client = ApplicationHelper::getClientInfo($this->parent->extension->client_id); $short_element = $this->parent->extension->element; $manifestPath = $client->path . '/language/' . $short_element . '/langmetadata.xml'; if (!is_file($manifestPath)) { $manifestPath = $client->path . '/language/' . $short_element . '/' . $short_element . '.xml'; } $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $this->parent->setPath('source', $client->path . '/language/' . $short_element); $this->parent->setPath('extension_root', $this->parent->getPath('source')); $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->state = 0; $this->parent->extension->name = $manifest_details['name']; $this->parent->extension->enabled = 1; // @todo remove code: $this->parent->extension->params = $this->parent->getParams(); try { $this->parent->extension->check(); $this->parent->extension->store(); } catch (\RuntimeException $e) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_LANG_DISCOVER_STORE_DETAILS'), \JLog::WARNING, 'jerror'); return false; } // Clean installed languages cache. \JFactory::getCache()->clean('com_languages'); return $this->parent->extension->get('extension_id'); } /** * Refreshes the extension table cache * * @return boolean result of operation, true if updated, false on failure * * @since 3.1 */ public function refreshManifestCache() { $client = ApplicationHelper::getClientInfo($this->parent->extension->client_id); $manifestPath = $client->path . '/language/' . $this->parent->extension->element . '/' . $this->parent->extension->element . '.xml'; if (!is_file($manifestPath)) { $manifestPath = $client->path . '/language/' . $this->parent->extension->element . '/langmetadata.xml'; } $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; if ($this->parent->extension->store()) { return true; } else { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_MOD_REFRESH_MANIFEST_CACHE'), \JLog::WARNING, 'jerror'); return false; } } } PK b�!]r^ɠQ Q ModuleAdapter.phpnu &1i� <?php /** * Joomla! Content Management System * * @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Installer\Adapter; defined('JPATH_PLATFORM') or die; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Installer\InstallerAdapter; use Joomla\CMS\Table\Table; use Joomla\Utilities\ArrayHelper; \JLoader::import('joomla.filesystem.folder'); /** * Module installer * * @since 3.1 */ class ModuleAdapter extends InstallerAdapter { /** * The install client ID * * @var integer * @since 3.4 */ protected $clientId; /** * `<scriptfile>` element of the extension manifest * * @var object * @since 3.1 */ protected $scriptElement = null; /** * Method to check if the extension is already present in the database * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function checkExistingExtension() { try { $this->currentExtensionId = $this->extension->find( array( 'element' => $this->element, 'type' => $this->type, 'client_id' => $this->clientId, ) ); } catch (\RuntimeException $e) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_ROLLBACK', \JText::_('JLIB_INSTALLER_' . $this->route), $e->getMessage() ), $e->getCode(), $e ); } } /** * Method to copy the extension's base files from the `<files>` tag(s) and the manifest file * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function copyBaseFiles() { // Copy all necessary files if ($this->parent->parseFiles($this->getManifest()->files, -1) === false) { throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ABORT_MOD_COPY_FILES')); } // If there is a manifest script, let's copy it. if ($this->manifest_script) { $path['src'] = $this->parent->getPath('source') . '/' . $this->manifest_script; $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->manifest_script; if ($this->parent->isOverwrite() || !file_exists($path['dest'])) { if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ABORT_MOD_INSTALL_MANIFEST')); } } } } /** * Method to finalise the installation processing * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function finaliseInstall() { // Clobber any possible pending updates $update = Table::getInstance('update'); $uid = $update->find( array( 'element' => $this->element, 'type' => 'module', 'client_id' => $this->clientId, ) ); if ($uid) { $update->delete($uid); } // Lastly, we will copy the manifest file to its appropriate place. if ($this->route !== 'discover_install') { if (!$this->parent->copyManifest(-1)) { // Install failed, rollback changes throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ABORT_MOD_INSTALL_COPY_SETUP')); } } } /** * Get the filtered extension element from the manifest * * @param string $element Optional element name to be converted * * @return string The filtered element * * @since 3.4 */ public function getElement($element = null) { if (!$element) { if (count($this->getManifest()->files->children())) { foreach ($this->getManifest()->files->children() as $file) { if ((string) $file->attributes()->module) { $element = strtolower((string) $file->attributes()->module); break; } } } } return $element; } /** * Custom loadLanguage method * * @param string $path The path where we find language files * * @return void * * @since 3.4 */ public function loadLanguage($path = null) { $source = $this->parent->getPath('source'); $client = $this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE; if (!$source) { $this->parent->setPath('source', $client . '/modules/' . $this->parent->extension->element); } $this->setManifest($this->parent->getManifest()); if ($this->getManifest()->files) { $extension = $this->getElement(); if ($extension) { $source = $path ?: ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/modules/' . $extension; $folder = (string) $this->getManifest()->files->attributes()->folder; if ($folder && file_exists($path . '/' . $folder)) { $source = $path . '/' . $folder; } $client = (string) $this->getManifest()->attributes()->client; $this->doLoadLanguage($extension, $source, constant('JPATH_' . strtoupper($client))); } } } /** * Method to parse optional tags in the manifest * * @return void * * @since 3.4 */ protected function parseOptionalTags() { // Parse optional tags $this->parent->parseMedia($this->getManifest()->media, $this->clientId); $this->parent->parseLanguages($this->getManifest()->languages, $this->clientId); } /** * Prepares the adapter for a discover_install task * * @return void * * @since 3.4 */ public function prepareDiscoverInstall() { $client = ApplicationHelper::getClientInfo($this->parent->extension->client_id); $manifestPath = $client->path . '/modules/' . $this->parent->extension->element . '/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $this->setManifest($this->parent->getManifest()); } /** * Method to do any prechecks and setup the install paths for the extension * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function setupInstallPaths() { // Get the target application $cname = (string) $this->getManifest()->attributes()->client; if ($cname) { // Attempt to map the client to a base path $client = ApplicationHelper::getClientInfo($cname, true); if ($client === false) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_MOD_UNKNOWN_CLIENT', \JText::_('JLIB_INSTALLER_' . $this->route), $client->name ) ); } $basePath = $client->path; $this->clientId = $client->id; } else { // No client attribute was found so we assume the site as the client $basePath = JPATH_SITE; $this->clientId = 0; } // Set the installation path if (empty($this->element)) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_MOD_INSTALL_NOFILE', \JText::_('JLIB_INSTALLER_' . $this->route) ) ); } $this->parent->setPath('extension_root', $basePath . '/modules/' . $this->element); } /** * Method to store the extension to the database * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function storeExtension() { // Discover installs are stored a little differently if ($this->route === 'discover_install') { $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->extension->manifest_cache = json_encode($manifest_details); $this->extension->state = 0; $this->extension->name = $manifest_details['name']; $this->extension->enabled = 1; $this->extension->params = $this->parent->getParams(); if (!$this->extension->store()) { // Install failed, roll back changes throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ERROR_MOD_DISCOVER_STORE_DETAILS')); } return; } // Was there a module already installed with the same name? if ($this->currentExtensionId) { if (!$this->parent->isOverwrite()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_MOD_INSTALL_ALLREADY_EXISTS', \JText::_('JLIB_INSTALLER_' . $this->route), $this->name ) ); } // Load the entry and update the manifest_cache $this->extension->load($this->currentExtensionId); // Update name $this->extension->name = $this->name; // Update manifest $this->extension->manifest_cache = $this->parent->generateManifestCache(); if (!$this->extension->store()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_MOD_ROLLBACK', \JText::_('JLIB_INSTALLER_' . $this->route), $this->extension->getError() ) ); } } else { $this->extension->name = $this->name; $this->extension->type = 'module'; $this->extension->element = $this->element; // There is no folder for modules $this->extension->folder = ''; $this->extension->enabled = 1; $this->extension->protected = 0; $this->extension->access = $this->clientId == 1 ? 2 : 0; $this->extension->client_id = $this->clientId; $this->extension->params = $this->parent->getParams(); // Custom data $this->extension->custom_data = ''; $this->extension->system_data = ''; $this->extension->manifest_cache = $this->parent->generateManifestCache(); if (!$this->extension->store()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_MOD_ROLLBACK', \JText::_('JLIB_INSTALLER_' . $this->route), $this->extension->getError() ) ); } // Since we have created a module item, we add it to the installation step stack // so that if we have to rollback the changes we can undo it. $this->parent->pushStep( array( 'type' => 'extension', 'extension_id' => $this->extension->extension_id, ) ); // Create unpublished module $name = preg_replace('#[\*?]#', '', \JText::_($this->name)); /** @var \JTableModule $module */ $module = Table::getInstance('module'); $module->title = $name; $module->content = ''; $module->module = $this->element; $module->access = '1'; $module->showtitle = '1'; $module->params = ''; $module->client_id = $this->clientId; $module->language = '*'; $module->store(); } } /** * Custom discover method * * @return array Extension list of extensions available * * @since 3.1 */ public function discover() { $results = array(); $site_list = \JFolder::folders(JPATH_SITE . '/modules'); $admin_list = \JFolder::folders(JPATH_ADMINISTRATOR . '/modules'); $site_info = ApplicationHelper::getClientInfo('site', true); $admin_info = ApplicationHelper::getClientInfo('administrator', true); foreach ($site_list as $module) { if (file_exists(JPATH_SITE . "/modules/$module/$module.xml")) { $manifest_details = Installer::parseXMLInstallFile(JPATH_SITE . "/modules/$module/$module.xml"); $extension = Table::getInstance('extension'); $extension->set('type', 'module'); $extension->set('client_id', $site_info->id); $extension->set('element', $module); $extension->set('folder', ''); $extension->set('name', $module); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $extension->set('params', '{}'); $results[] = clone $extension; } } foreach ($admin_list as $module) { if (file_exists(JPATH_ADMINISTRATOR . "/modules/$module/$module.xml")) { $manifest_details = Installer::parseXMLInstallFile(JPATH_ADMINISTRATOR . "/modules/$module/$module.xml"); $extension = Table::getInstance('extension'); $extension->set('type', 'module'); $extension->set('client_id', $admin_info->id); $extension->set('element', $module); $extension->set('folder', ''); $extension->set('name', $module); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $extension->set('params', '{}'); $results[] = clone $extension; } } return $results; } /** * Refreshes the extension table cache * * @return boolean Result of operation, true if updated, false on failure. * * @since 3.1 */ public function refreshManifestCache() { $client = ApplicationHelper::getClientInfo($this->parent->extension->client_id); $manifestPath = $client->path . '/modules/' . $this->parent->extension->element . '/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; if ($this->parent->extension->store()) { return true; } else { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_MOD_REFRESH_MANIFEST_CACHE'), \JLog::WARNING, 'jerror'); return false; } } /** * Custom uninstall method * * @param integer $id The id of the module to uninstall * * @return boolean True on success * * @since 3.1 */ public function uninstall($id) { $retval = true; $db = $this->db; // First order of business will be to load the module object table from the database. // This should give us the necessary information to proceed. if (!$this->extension->load((int) $id) || $this->extension->element === '') { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_ERRORUNKOWNEXTENSION'), \JLog::WARNING, 'jerror'); return false; } // Is the module we are trying to uninstall a core one? // Because that is not a good idea... if ($this->extension->protected) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_WARNCOREMODULE', $this->extension->name), \JLog::WARNING, 'jerror'); return false; } /* * Does this extension have a parent package? * If so, check if the package disallows individual extensions being uninstalled if the package is not being uninstalled */ if ($this->extension->package_id && !$this->parent->isPackageUninstall() && !$this->canUninstallPackageChild($this->extension->package_id)) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_CANNOT_UNINSTALL_CHILD_OF_PACKAGE', $this->extension->name), \JLog::WARNING, 'jerror'); return false; } // Get the extension root path $element = $this->extension->element; $client = ApplicationHelper::getClientInfo($this->extension->client_id); if ($client === false) { $this->parent->abort( \JText::sprintf( 'JLIB_INSTALLER_ERROR_MOD_UNINSTALL_UNKNOWN_CLIENT', $this->extension->client_id ) ); return false; } $this->parent->setPath('extension_root', $client->path . '/modules/' . $element); $this->parent->setPath('source', $this->parent->getPath('extension_root')); // Get the module's manifest object // We do findManifest to avoid problem when uninstalling a list of extensions: getManifest cache its manifest file. $this->parent->findManifest(); $this->setManifest($this->parent->getManifest()); // Attempt to load the language file; might have uninstall strings $this->loadLanguage(($this->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/modules/' . $element); // If there is a manifest class file, let's load it $this->scriptElement = $this->getManifest()->scriptfile; $manifestScript = (string) $this->getManifest()->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('extension_root') . '/' . $manifestScript; // Set the class name $classname = $element . 'InstallerScript'; \JLoader::register($classname, $manifestScriptFile); if (class_exists($classname)) { // Create a new instance $this->parent->manifestClass = new $classname($this); // And set this so we can copy it later $this->set('manifest_script', $manifestScript); } } try { $this->triggerManifestScript('uninstall'); } catch (\RuntimeException $e) { // Ignore errors for now } if (!($this->getManifest() instanceof \SimpleXMLElement)) { // Make sure we delete the folders \JFolder::delete($this->parent->getPath('extension_root')); \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_INVALID_NOTFOUND_MANIFEST'), \JLog::WARNING, 'jerror'); return false; } // Let's run the uninstall queries for the module try { $this->parseQueries(); } catch (\RuntimeException $e) { // Install failed, rollback changes \JLog::add($e->getMessage(), \JLog::WARNING, 'jerror'); $retval = false; } // Remove the schema version $query = $db->getQuery(true) ->delete('#__schemas') ->where('extension_id = ' . $this->extension->extension_id); $db->setQuery($query); $db->execute(); // Remove other files $this->parent->removeFiles($this->getManifest()->media); $this->parent->removeFiles($this->getManifest()->languages, $this->extension->client_id); // Let's delete all the module copies for the type we are uninstalling $query->clear() ->select($db->quoteName('id')) ->from($db->quoteName('#__modules')) ->where($db->quoteName('module') . ' = ' . $db->quote($this->extension->element)) ->where($db->quoteName('client_id') . ' = ' . (int) $this->extension->client_id); $db->setQuery($query); try { $modules = $db->loadColumn(); } catch (\RuntimeException $e) { $modules = array(); } // Do we have any module copies? if (count($modules)) { // Ensure the list is sane $modules = ArrayHelper::toInteger($modules); $modID = implode(',', $modules); // Wipe out any items assigned to menus $query = $db->getQuery(true) ->delete($db->quoteName('#__modules_menu')) ->where($db->quoteName('moduleid') . ' IN (' . $modID . ')'); $db->setQuery($query); try { $db->execute(); } catch (\RuntimeException $e) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_EXCEPTION', $db->stderr(true)), \JLog::WARNING, 'jerror'); $retval = false; } // Wipe out any instances in the modules table /** @var \JTableModule $module */ $module = Table::getInstance('Module'); foreach ($modules as $modInstanceId) { $module->load($modInstanceId); if (!$module->delete()) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_EXCEPTION', $module->getError()), \JLog::WARNING, 'jerror'); $retval = false; } } } // Now we will no longer need the module object, so let's delete it and free up memory $this->extension->delete($this->extension->extension_id); $query = $db->getQuery(true) ->delete($db->quoteName('#__modules')) ->where($db->quoteName('module') . ' = ' . $db->quote($this->extension->element)) ->where($db->quoteName('client_id') . ' = ' . (int) $this->extension->client_id); $db->setQuery($query); try { // Clean up any other ones that might exist as well $db->execute(); } catch (\RuntimeException $e) { // Ignore the error... } // Remove the installation folder if (!\JFolder::delete($this->parent->getPath('extension_root'))) { // \JFolder should raise an error $retval = false; } return $retval; } /** * Custom rollback method * - Roll back the menu item * * @param array $arg Installation step to rollback * * @return boolean True on success * * @since 3.1 */ protected function _rollback_menu($arg) { // Get database connector object $db = $this->parent->getDbo(); // Remove the entry from the #__modules_menu table $query = $db->getQuery(true) ->delete($db->quoteName('#__modules_menu')) ->where($db->quoteName('moduleid') . ' = ' . (int) $arg['id']); $db->setQuery($query); try { return $db->execute(); } catch (\RuntimeException $e) { return false; } } /** * Custom rollback method * - Roll back the module item * * @param array $arg Installation step to rollback * * @return boolean True on success * * @since 3.1 */ protected function _rollback_module($arg) { // Get database connector object $db = $this->parent->getDbo(); // Remove the entry from the #__modules table $query = $db->getQuery(true) ->delete($db->quoteName('#__modules')) ->where($db->quoteName('id') . ' = ' . (int) $arg['id']); $db->setQuery($query); try { return $db->execute(); } catch (\RuntimeException $e) { return false; } } } PK b�!].h�jN N PackageAdapter.phpnu &1i� <?php /** * Joomla! Content Management System * * @copyright (C) 2008 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Installer\Adapter; defined('JPATH_PLATFORM') or die; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Installer\InstallerAdapter; use Joomla\CMS\Installer\InstallerHelper; use Joomla\CMS\Installer\Manifest\PackageManifest; use Joomla\CMS\Table\Table; use Joomla\CMS\Table\Update; /** * Package installer * * @since 3.1 */ class PackageAdapter extends InstallerAdapter { /** * Flag if the internal event callback has been registered * * @var boolean * @since 3.7.0 */ private static $eventRegistered = false; /** * An array of extension IDs for each installed extension * * @var array * @since 3.7.0 */ protected $installedIds = array(); /** * The results of each installed extensions * * @var array * @since 3.1 */ protected $results = array(); /** * Flag if the adapter supports discover installs * * Adapters should override this and set to false if discover install is unsupported * * @var boolean * @since 3.4 */ protected $supportsDiscoverInstall = false; /** * Method to check if the extension is present in the filesystem, flags the route as update if so * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function checkExtensionInFilesystem() { // If the package manifest already exists, then we will assume that the package is already installed. if (file_exists(JPATH_MANIFESTS . '/packages/' . basename($this->parent->getPath('manifest')))) { // Look for an update function or update tag $updateElement = $this->manifest->update; // Upgrade manually set or update function available or update tag detected if ($updateElement || $this->parent->isUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'update'))) { // Force this one $this->parent->setOverwrite(true); $this->parent->setUpgrade(true); if ($this->currentExtensionId) { // If there is a matching extension mark this as an update $this->setRoute('update'); } } elseif (!$this->parent->isOverwrite()) { // We didn't have overwrite set, find an update function or find an update tag so lets call it safe throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_DIRECTORY', \JText::_('JLIB_INSTALLER_' . $this->route), $this->type, $this->parent->getPath('extension_root') ) ); } } } /** * Method to copy the extension's base files from the `<files>` tag(s) and the manifest file * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function copyBaseFiles() { $folder = (string) $this->getManifest()->files->attributes()->folder; $source = $this->parent->getPath('source'); if ($folder) { $source .= '/' . $folder; } // Install all necessary files if (!count($this->getManifest()->files->children())) { throw new \RuntimeException( \JText::sprintf('JLIB_INSTALLER_ABORT_PACK_INSTALL_NO_FILES', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)) ) ); } // Add a callback for the `onExtensionAfterInstall` event so we can receive the installed extension ID if (!self::$eventRegistered) { self::$eventRegistered = true; \JEventDispatcher::getInstance()->register('onExtensionAfterInstall', array($this, 'onExtensionAfterInstall')); } foreach ($this->getManifest()->files->children() as $child) { $file = $source . '/' . (string) $child; if (is_dir($file)) { // If it's actually a directory then fill it up $package = array(); $package['dir'] = $file; $package['type'] = InstallerHelper::detectType($file); } else { // If it's an archive $package = InstallerHelper::unpack($file); } $tmpInstaller = new Installer; $installResult = $tmpInstaller->install($package['dir']); if (!$installResult) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_PACK_INSTALL_ERROR_EXTENSION', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)), basename($file) ) ); } $this->results[] = array( 'name' => (string) $tmpInstaller->manifest->name, 'result' => $installResult, ); } } /** * Method to create the extension root path if necessary * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function createExtensionRoot() { /* * For packages, we only need the extension root if copying manifest files; this step will be handled * at that point if necessary */ } /** * Method to finalise the installation processing * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function finaliseInstall() { // Clobber any possible pending updates /** @var Update $update */ $update = Table::getInstance('update'); $uid = $update->find( array( 'element' => $this->element, 'type' => $this->type, ) ); if ($uid) { $update->delete($uid); } // Set the package ID for each of the installed extensions to track the relationship if (!empty($this->installedIds)) { $db = $this->db; $query = $db->getQuery(true) ->update('#__extensions') ->set($db->quoteName('package_id') . ' = ' . (int) $this->extension->extension_id) ->where($db->quoteName('extension_id') . ' IN (' . implode(', ', $this->installedIds) . ')'); try { $db->setQuery($query)->execute(); } catch (\JDatabaseExceptionExecuting $e) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_PACK_SETTING_PACKAGE_ID'), \JLog::WARNING, 'jerror'); } } // Lastly, we will copy the manifest file to its appropriate place. $manifest = array(); $manifest['src'] = $this->parent->getPath('manifest'); $manifest['dest'] = JPATH_MANIFESTS . '/packages/' . basename($this->parent->getPath('manifest')); if (!$this->parent->copyFiles(array($manifest), true)) { // Install failed, rollback changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_PACK_INSTALL_COPY_SETUP', \JText::_('JLIB_INSTALLER_ABORT_PACK_INSTALL_NO_FILES') ) ); } // If there is a manifest script, let's copy it. if ($this->manifest_script) { // First, we have to create a folder for the script if one isn't present if (!file_exists($this->parent->getPath('extension_root'))) { if (!\JFolder::create($this->parent->getPath('extension_root'))) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_CREATE_DIRECTORY', \JText::_('JLIB_INSTALLER_' . $this->route), $this->parent->getPath('extension_root') ) ); } /* * Since we created the extension directory and will want to remove it if * we have to roll back the installation, let's add it to the * installation step stack */ $this->parent->pushStep( array( 'type' => 'folder', 'path' => $this->parent->getPath('extension_root'), ) ); } $path['src'] = $this->parent->getPath('source') . '/' . $this->manifest_script; $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->manifest_script; if ($this->parent->isOverwrite() || !file_exists($path['dest'])) { if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ABORT_PACKAGE_INSTALL_MANIFEST')); } } } } /** * Get the filtered extension element from the manifest * * @param string $element Optional element name to be converted * * @return string The filtered element * * @since 3.4 */ public function getElement($element = null) { if (!$element) { // Ensure the element is a string $element = (string) $this->getManifest()->packagename; // Filter the name for illegal characters $element = 'pkg_' . \JFilterInput::getInstance()->clean($element, 'cmd'); } return $element; } /** * Load language from a path * * @param string $path The path of the language. * * @return void * * @since 3.1 */ public function loadLanguage($path) { $this->doLoadLanguage($this->getElement(), $path); } /** * Handler for the `onExtensionAfterInstall` event * * @param Installer $installer Installer instance managing the extension's installation * @param integer|boolean $eid The extension ID of the installed extension on success, boolean false on install failure * * @return void * * @since 3.7.0 */ public function onExtensionAfterInstall(Installer $installer, $eid) { if ($eid !== false) { $this->installedIds[] = $eid; } } /** * Method to parse optional tags in the manifest * * @return void * * @since 3.4 */ protected function parseOptionalTags() { $this->parent->parseLanguages($this->getManifest()->languages); } /** * Method to do any prechecks and setup the install paths for the extension * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function setupInstallPaths() { $packagepath = (string) $this->getManifest()->packagename; if (empty($packagepath)) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_PACK_INSTALL_NO_PACK', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)) ) ); } $this->parent->setPath('extension_root', JPATH_MANIFESTS . '/packages/' . $packagepath); } /** * Method to store the extension to the database * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function storeExtension() { if ($this->currentExtensionId) { if (!$this->parent->isOverwrite()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_ALREADY_EXISTS', \JText::_('JLIB_INSTALLER_' . $this->route), $this->name ) ); } $this->extension->load($this->currentExtensionId); $this->extension->name = $this->name; } else { $this->extension->name = $this->name; $this->extension->type = 'package'; $this->extension->element = $this->element; // There is no folder for packages $this->extension->folder = ''; $this->extension->enabled = 1; $this->extension->protected = 0; $this->extension->access = 1; $this->extension->client_id = 0; // Custom data $this->extension->custom_data = ''; $this->extension->system_data = ''; $this->extension->params = $this->parent->getParams(); } // Update the manifest cache for the entry $this->extension->manifest_cache = $this->parent->generateManifestCache(); if (!$this->extension->store()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_PACK_INSTALL_ROLLBACK', $this->extension->getError() ) ); } // Since we have created a package item, we add it to the installation step stack // so that if we have to rollback the changes we can undo it. $this->parent->pushStep(array('type' => 'extension', 'id' => $this->extension->extension_id)); } /** * Executes a custom install script method * * @param string $method The install method to execute * * @return boolean True on success * * @since 3.4 */ protected function triggerManifestScript($method) { ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, $method)) { switch ($method) { // The preflight method takes the route as a param case 'preflight': if ($this->parent->manifestClass->$method($this->route, $this) === false) { // The script failed, rollback changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_INSTALL_CUSTOM_INSTALL_FAILURE', \JText::_('JLIB_INSTALLER_' . $this->route) ) ); } break; // The postflight method takes the route and a results array as params case 'postflight': $this->parent->manifestClass->$method($this->route, $this, $this->results); break; // The install, uninstall, and update methods only pass this object as a param case 'install': case 'uninstall': case 'update': if ($this->parent->manifestClass->$method($this) === false) { if ($method !== 'uninstall') { // The script failed, rollback changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_INSTALL_CUSTOM_INSTALL_FAILURE', \JText::_('JLIB_INSTALLER_' . $this->route) ) ); } } break; } } // Append to the message object $this->extensionMessage .= ob_get_clean(); // If in postflight or uninstall, set the message for display if (($method === 'uninstall' || $method === 'postflight') && $this->extensionMessage !== '') { $this->parent->set('extension_message', $this->extensionMessage); } return true; } /** * Custom uninstall method * * @param integer $id The id of the package to uninstall. * * @return boolean True on success * * @since 3.1 */ public function uninstall($id) { $row = null; $retval = true; $row = Table::getInstance('extension'); $row->load($id); if ($row->protected) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_WARNCOREPACK'), \JLog::WARNING, 'jerror'); return false; } /* * Does this extension have a parent package? * If so, check if the package disallows individual extensions being uninstalled if the package is not being uninstalled */ if ($row->package_id && !$this->parent->isPackageUninstall() && !$this->canUninstallPackageChild($row->package_id)) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_CANNOT_UNINSTALL_CHILD_OF_PACKAGE', $row->name), \JLog::WARNING, 'jerror'); return false; } $manifestFile = JPATH_MANIFESTS . '/packages/' . $row->get('element') . '.xml'; $manifest = new PackageManifest($manifestFile); // Set the package root path $this->parent->setPath('extension_root', JPATH_MANIFESTS . '/packages/' . $manifest->packagename); // Because packages may not have their own folders we cannot use the standard method of finding an installation manifest if (!file_exists($manifestFile)) { // TODO: Fail? \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_MISSINGMANIFEST'), \JLog::WARNING, 'jerror'); return false; } $xml = simplexml_load_file($manifestFile); // If we cannot load the XML file return false if (!$xml) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_LOAD_MANIFEST'), \JLog::WARNING, 'jerror'); return false; } // Check for a valid XML root tag. if ($xml->getName() !== 'extension') { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_INVALID_MANIFEST'), \JLog::WARNING, 'jerror'); return false; } // If there is a manifest class file, let's load it $manifestScript = (string) $manifest->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('extension_root') . '/' . $manifestScript; // Set the class name $classname = $row->element . 'InstallerScript'; \JLoader::register($classname, $manifestScriptFile); if (class_exists($classname)) { // Create a new instance $this->parent->manifestClass = new $classname($this); // And set this so we can copy it later $this->set('manifest_script', $manifestScript); } } ob_start(); ob_implicit_flush(false); // Run uninstall if possible if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'uninstall')) { $this->parent->manifestClass->uninstall($this); } $msg = ob_get_contents(); ob_end_clean(); if ($msg != '') { $this->parent->set('extension_message', $msg); } $error = false; foreach ($manifest->filelist as $extension) { $tmpInstaller = new Installer; $tmpInstaller->setPackageUninstall(true); $id = $this->_getExtensionId($extension->type, $extension->id, $extension->client, $extension->group); $client = ApplicationHelper::getClientInfo($extension->client, true); if ($id) { if (!$tmpInstaller->uninstall($extension->type, $id, $client->id)) { $error = true; \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_NOT_PROPER', basename($extension->filename)), \JLog::WARNING, 'jerror'); } } else { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_UNKNOWN_EXTENSION'), \JLog::WARNING, 'jerror'); } } // Remove any language files $this->parent->removeFiles($xml->languages); // Clean up manifest file after we're done if there were no errors if (!$error) { \JFile::delete($manifestFile); $folder = $this->parent->getPath('extension_root'); if (\JFolder::exists($folder)) { \JFolder::delete($folder); } $row->delete(); } else { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_MANIFEST_NOT_REMOVED'), \JLog::WARNING, 'jerror'); } // Return the result up the line return $retval; } /** * Gets the extension id. * * @param string $type The extension type. * @param string $id The name of the extension (the element field). * @param integer $client The application id (0: Joomla CMS site; 1: Joomla CMS administrator). * @param string $group The extension group (mainly for plugins). * * @return integer * * @since 3.1 */ protected function _getExtensionId($type, $id, $client, $group) { $db = $this->parent->getDbo(); $query = $db->getQuery(true) ->select('extension_id') ->from('#__extensions') ->where('type = ' . $db->quote($type)) ->where('element = ' . $db->quote($id)); switch ($type) { case 'plugin': // Plugins have a folder but not a client $query->where('folder = ' . $db->quote($group)); break; case 'library': case 'package': case 'component': // Components, packages and libraries don't have a folder or client. // Included for completeness. break; case 'language': case 'module': case 'template': // Languages, modules and templates have a client but not a folder $client = ApplicationHelper::getClientInfo($client, true); $query->where('client_id = ' . (int) $client->id); break; } $db->setQuery($query); // Note: For templates, libraries and packages their unique name is their key. // This means they come out the same way they came in. return $db->loadResult(); } /** * Refreshes the extension table cache * * @return boolean Result of operation, true if updated, false on failure * * @since 3.1 */ public function refreshManifestCache() { // Need to find to find where the XML file is since we don't store this normally $manifestPath = JPATH_MANIFESTS . '/packages/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; try { return $this->parent->extension->store(); } catch (\RuntimeException $e) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_PACK_REFRESH_MANIFEST_CACHE'), \JLog::WARNING, 'jerror'); return false; } } } PK b�!] �� h@ h@ FileAdapter.phpnu &1i� <?php /** * Joomla! Content Management System * * @copyright (C) 2008 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Installer\Adapter; defined('JPATH_PLATFORM') or die; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Installer\InstallerAdapter; use Joomla\CMS\Table\Table; \JLoader::import('joomla.filesystem.folder'); /** * File installer * * @since 3.1 */ class FileAdapter extends InstallerAdapter { /** * `<scriptfile>` element of the extension manifest * * @var object * @since 3.1 */ protected $scriptElement = null; /** * Flag if the adapter supports discover installs * * Adapters should override this and set to false if discover install is unsupported * * @var boolean * @since 3.4 */ protected $supportsDiscoverInstall = false; /** * Method to copy the extension's base files from the `<files>` tag(s) and the manifest file * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function copyBaseFiles() { // Populate File and Folder List to copy $this->populateFilesAndFolderList(); // Now that we have folder list, lets start creating them foreach ($this->folderList as $folder) { if (!\JFolder::exists($folder)) { if (!$created = \JFolder::create($folder)) { throw new \RuntimeException( \JText::sprintf('JLIB_INSTALLER_ABORT_FILE_INSTALL_FAIL_SOURCE_DIRECTORY', $folder) ); } // Since we created a directory and will want to remove it if we have to roll back. // The installation due to some errors, let's add it to the installation step stack. if ($created) { $this->parent->pushStep(array('type' => 'folder', 'path' => $folder)); } } } // Now that we have file list, let's start copying them $this->parent->copyFiles($this->fileList); } /** * Method to finalise the installation processing * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function finaliseInstall() { // Clobber any possible pending updates $update = Table::getInstance('update'); $uid = $update->find( array( 'element' => $this->element, 'type' => $this->type, ) ); if ($uid) { $update->delete($uid); } // Lastly, we will copy the manifest file to its appropriate place. $manifest = array(); $manifest['src'] = $this->parent->getPath('manifest'); $manifest['dest'] = JPATH_MANIFESTS . '/files/' . basename($this->parent->getPath('manifest')); if (!$this->parent->copyFiles(array($manifest), true)) { // Install failed, rollback changes throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ABORT_FILE_INSTALL_COPY_SETUP')); } // If there is a manifest script, let's copy it. if ($this->manifest_script) { // First, we have to create a folder for the script if one isn't present if (!file_exists($this->parent->getPath('extension_root'))) { \JFolder::create($this->parent->getPath('extension_root')); } $path['src'] = $this->parent->getPath('source') . '/' . $this->manifest_script; $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->manifest_script; if ($this->parent->isOverwrite() || !file_exists($path['dest'])) { if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_MANIFEST', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)) ) ); } } } } /** * Get the filtered extension element from the manifest * * @param string $element Optional element name to be converted * * @return string The filtered element * * @since 3.4 */ public function getElement($element = null) { if (!$element) { $manifestPath = \JPath::clean($this->parent->getPath('manifest')); $element = preg_replace('/\.xml/', '', basename($manifestPath)); } return $element; } /** * Custom loadLanguage method * * @param string $path The path on which to find language files. * * @return void * * @since 3.1 */ public function loadLanguage($path) { $extension = 'files_' . strtolower(str_replace('files_', '', $this->getElement())); $this->doLoadLanguage($extension, $path, JPATH_SITE); } /** * Method to parse optional tags in the manifest * * @return void * * @since 3.4 */ protected function parseOptionalTags() { // Parse optional tags $this->parent->parseLanguages($this->getManifest()->languages); } /** * Method to do any prechecks and setup the install paths for the extension * * @return void * * @since 3.4 */ protected function setupInstallPaths() { // Set the file root path if ($this->name === 'files_joomla') { // If we are updating the Joomla core, set the root path to the root of Joomla $this->parent->setPath('extension_root', JPATH_ROOT); } else { $this->parent->setPath('extension_root', JPATH_MANIFESTS . '/files/' . $this->element); } } /** * Method to store the extension to the database * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function storeExtension() { if ($this->currentExtensionId) { // Load the entry and update the manifest_cache $this->extension->load($this->currentExtensionId); // Update name $this->extension->name = $this->name; // Update manifest $this->extension->manifest_cache = $this->parent->generateManifestCache(); if (!$this->extension->store()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_ROLLBACK', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)), $this->extension->getError() ) ); } } else { // Add an entry to the extension table with a whole heap of defaults $this->extension->name = $this->name; $this->extension->type = 'file'; $this->extension->element = $this->element; // There is no folder for files so leave it blank $this->extension->folder = ''; $this->extension->enabled = 1; $this->extension->protected = 0; $this->extension->access = 0; $this->extension->client_id = 0; $this->extension->params = ''; $this->extension->system_data = ''; $this->extension->manifest_cache = $this->parent->generateManifestCache(); $this->extension->custom_data = ''; if (!$this->extension->store()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_ROLLBACK', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)), $this->extension->getError() ) ); } // Since we have created a module item, we add it to the installation step stack // so that if we have to rollback the changes we can undo it. $this->parent->pushStep(array('type' => 'extension', 'extension_id' => $this->extension->extension_id)); } } /** * Custom uninstall method * * @param string $id The id of the file to uninstall * * @return boolean True on success * * @since 3.1 */ public function uninstall($id) { $row = Table::getInstance('extension'); if (!$row->load($id)) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_LOAD_ENTRY'), \JLog::WARNING, 'jerror'); return false; } if ($row->protected) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_WARNCOREFILE'), \JLog::WARNING, 'jerror'); return false; } /* * Does this extension have a parent package? * If so, check if the package disallows individual extensions being uninstalled if the package is not being uninstalled */ if ($row->package_id && !$this->parent->isPackageUninstall() && !$this->canUninstallPackageChild($row->package_id)) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_CANNOT_UNINSTALL_CHILD_OF_PACKAGE', $row->name), \JLog::WARNING, 'jerror'); return false; } $retval = true; $manifestFile = JPATH_MANIFESTS . '/files/' . $row->element . '.xml'; // Because files may not have their own folders we cannot use the standard method of finding an installation manifest if (file_exists($manifestFile)) { // Set the files root path $this->parent->setPath('extension_root', JPATH_MANIFESTS . '/files/' . $row->element); $xml = simplexml_load_file($manifestFile); // If we cannot load the XML file return null if (!$xml) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_LOAD_MANIFEST'), \JLog::WARNING, 'jerror'); return false; } // Check for a valid XML root tag. if ($xml->getName() !== 'extension') { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_INVALID_MANIFEST'), \JLog::WARNING, 'jerror'); return false; } $this->setManifest($xml); // If there is a manifest class file, let's load it $this->scriptElement = $this->getManifest()->scriptfile; $manifestScript = (string) $this->getManifest()->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('extension_root') . '/' . $manifestScript; // Set the class name $classname = $row->element . 'InstallerScript'; \JLoader::register($classname, $manifestScriptFile); if (class_exists($classname)) { // Create a new instance $this->parent->manifestClass = new $classname($this); // And set this so we can copy it later $this->set('manifest_script', $manifestScript); } } ob_start(); ob_implicit_flush(false); // Run uninstall if possible if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'uninstall')) { $this->parent->manifestClass->uninstall($this); } $msg = ob_get_contents(); ob_end_clean(); if ($msg != '') { $this->parent->set('extension_message', $msg); } $db = \JFactory::getDbo(); // Let's run the uninstall queries for the extension $result = $this->parent->parseSQLFiles($this->getManifest()->uninstall->sql); if ($result === false) { // Install failed, rollback changes \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_SQL_ERROR', $db->stderr(true)), \JLog::WARNING, 'jerror'); $retval = false; } // Remove the schema version $query = $db->getQuery(true) ->delete('#__schemas') ->where('extension_id = ' . $row->extension_id); $db->setQuery($query); $db->execute(); // Loop through all elements and get list of files and folders foreach ($xml->fileset->files as $eFiles) { $target = (string) $eFiles->attributes()->target; // Create folder path if (empty($target)) { $targetFolder = JPATH_ROOT; } else { $targetFolder = JPATH_ROOT . '/' . $target; } $folderList = array(); // Check if all children exists if (count($eFiles->children()) > 0) { // Loop through all filenames elements foreach ($eFiles->children() as $eFileName) { if ($eFileName->getName() === 'folder') { $folderList[] = $targetFolder . '/' . $eFileName; } else { $fileName = $targetFolder . '/' . $eFileName; \JFile::delete($fileName); } } } // Delete any folders that don't have any content in them. foreach ($folderList as $folder) { $files = \JFolder::files($folder); if ($files !== false && !count($files)) { \JFolder::delete($folder); } } } \JFile::delete($manifestFile); // Lastly, remove the extension_root $folder = $this->parent->getPath('extension_root'); if (\JFolder::exists($folder)) { \JFolder::delete($folder); } } else { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_INVALID_NOTFOUND_MANIFEST'), \JLog::WARNING, 'jerror'); // Delete the row because its broken $row->delete(); return false; } $this->parent->removeFiles($xml->languages); $row->delete(); return $retval; } /** * Function used to check if extension is already installed * * @param string $extension The element name of the extension to install * * @return boolean True if extension exists * * @since 3.1 */ protected function extensionExistsInSystem($extension = null) { // Get a database connector object $db = $this->parent->getDbo(); $query = $db->getQuery(true) ->select($db->quoteName('extension_id')) ->from($db->quoteName('#__extensions')) ->where($db->quoteName('type') . ' = ' . $db->quote('file')) ->where($db->quoteName('element') . ' = ' . $db->quote($extension)); $db->setQuery($query); try { $db->execute(); } catch (\RuntimeException $e) { // Install failed, roll back changes $this->parent->abort(\JText::sprintf('JLIB_INSTALLER_ABORT_FILE_ROLLBACK', $db->stderr(true))); return false; } $id = $db->loadResult(); if (empty($id)) { return false; } return true; } /** * Function used to populate files and folder list * * @return boolean none * * @since 3.1 */ protected function populateFilesAndFolderList() { // Initialise variable $this->folderList = array(); $this->fileList = array(); // Set root folder names $packagePath = $this->parent->getPath('source'); $jRootPath = \JPath::clean(JPATH_ROOT); // Loop through all elements and get list of files and folders foreach ($this->getManifest()->fileset->files as $eFiles) { // Check if the element is files element $folder = (string) $eFiles->attributes()->folder; $target = (string) $eFiles->attributes()->target; // Split folder names into array to get folder names. This will help in creating folders $arrList = preg_split("#/|\\/#", $target); $folderName = $jRootPath; foreach ($arrList as $dir) { if (empty($dir)) { continue; } $folderName .= '/' . $dir; // Check if folder exists, if not then add to the array for folder creation if (!\JFolder::exists($folderName)) { $this->folderList[] = $folderName; } } // Create folder path $sourceFolder = empty($folder) ? $packagePath : $packagePath . '/' . $folder; $targetFolder = empty($target) ? $jRootPath : $jRootPath . '/' . $target; // Check if source folder exists if (!\JFolder::exists($sourceFolder)) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ABORT_FILE_INSTALL_FAIL_SOURCE_DIRECTORY', $sourceFolder), \JLog::WARNING, 'jerror'); // If installation fails, rollback $this->parent->abort(); return false; } // Check if all children exists if (count($eFiles->children())) { // Loop through all filenames elements foreach ($eFiles->children() as $eFileName) { $path['src'] = $sourceFolder . '/' . $eFileName; $path['dest'] = $targetFolder . '/' . $eFileName; $path['type'] = 'file'; if ($eFileName->getName() === 'folder') { $folderName = $targetFolder . '/' . $eFileName; $this->folderList[] = $folderName; $path['type'] = 'folder'; } $this->fileList[] = $path; } } else { $files = \JFolder::files($sourceFolder); foreach ($files as $file) { $path['src'] = $sourceFolder . '/' . $file; $path['dest'] = $targetFolder . '/' . $file; $this->fileList[] = $path; } } } } /** * Refreshes the extension table cache * * @return boolean result of operation, true if updated, false on failure * * @since 3.1 */ public function refreshManifestCache() { // Need to find to find where the XML file is since we don't store this normally $manifestPath = JPATH_MANIFESTS . '/files/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; try { return $this->parent->extension->store(); } catch (\RuntimeException $e) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_PACK_REFRESH_MANIFEST_CACHE'), \JLog::WARNING, 'jerror'); return false; } } } PK b�!]^T��S� S� ComponentAdapter.phpnu &1i� <?php /** * Joomla! Content Management System * * @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Installer\Adapter; defined('JPATH_PLATFORM') or die; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Installer\InstallerAdapter; use Joomla\CMS\Table\Asset; use Joomla\CMS\Table\Extension; use Joomla\CMS\Table\Table; use Joomla\CMS\Table\Update; jimport('joomla.filesystem.folder'); /** * Component installer * * @since 3.1 */ class ComponentAdapter extends InstallerAdapter { /** * The list of current files fo the Joomla! CMS administrator that are installed and is read * from the manifest on disk in the update area to handle doing a diff * and deleting files that are in the old files list and not in the new * files list. * * @var array * @since 3.1 * */ protected $oldAdminFiles = null; /** * The list of current files that are installed and is read * from the manifest on disk in the update area to handle doing a diff * and deleting files that are in the old files list and not in the new * files list. * * @var array * @since 3.1 * */ protected $oldFiles = null; /** * A path to the PHP file that the scriptfile declaration in * the manifest refers to. * * @var string * @since 3.1 * */ protected $manifest_script = null; /** * For legacy installations this is a path to the PHP file that the scriptfile declaration in the * manifest refers to. * * @var string * @since 3.1 * */ protected $install_script = null; /** * Method to check if the extension is present in the filesystem * * @return boolean * * @since 3.4 * @throws \RuntimeException */ protected function checkExtensionInFilesystem() { /* * If the component site or admin directory already exists, then we will assume that the component is already * installed or another component is using that directory. */ if (file_exists($this->parent->getPath('extension_site')) || file_exists($this->parent->getPath('extension_administrator'))) { // Look for an update function or update tag $updateElement = $this->getManifest()->update; // Upgrade manually set or update function available or update tag detected if ($updateElement || $this->parent->isUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'update'))) { // If there is a matching extension mark this as an update $this->setRoute('update'); } elseif (!$this->parent->isOverwrite()) { // We didn't have overwrite set, find an update function or find an update tag so lets call it safe if (file_exists($this->parent->getPath('extension_site'))) { // If the site exists say so. throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ERROR_COMP_INSTALL_DIR_SITE', $this->parent->getPath('extension_site') ) ); } // If the admin exists say so throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ERROR_COMP_INSTALL_DIR_ADMIN', $this->parent->getPath('extension_administrator') ) ); } } return false; } /** * Method to copy the extension's base files from the `<files>` tag(s) and the manifest file * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function copyBaseFiles() { // Copy site files if ($this->getManifest()->files) { if ($this->route === 'update') { $result = $this->parent->parseFiles($this->getManifest()->files, 0, $this->oldFiles); } else { $result = $this->parent->parseFiles($this->getManifest()->files); } if ($result === false) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_COMP_FAIL_SITE_FILES', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)) ) ); } } // Copy admin files if ($this->getManifest()->administration->files) { if ($this->route === 'update') { $result = $this->parent->parseFiles($this->getManifest()->administration->files, 1, $this->oldAdminFiles); } else { $result = $this->parent->parseFiles($this->getManifest()->administration->files, 1); } if ($result === false) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_COMP_FAIL_ADMIN_FILES', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)) ) ); } } // If there is a manifest script, let's copy it. if ($this->manifest_script) { $path['src'] = $this->parent->getPath('source') . '/' . $this->manifest_script; $path['dest'] = $this->parent->getPath('extension_administrator') . '/' . $this->manifest_script; if ($this->parent->isOverwrite() || !file_exists($path['dest'])) { if (!$this->parent->copyFiles(array($path))) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_COMP_COPY_MANIFEST', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)) ) ); } } } } /** * Method to create the extension root path if necessary * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function createExtensionRoot() { // If the component directory does not exist, let's create it $created = false; if (!file_exists($this->parent->getPath('extension_site'))) { if (!$created = \JFolder::create($this->parent->getPath('extension_site'))) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ERROR_COMP_FAILED_TO_CREATE_DIRECTORY', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)), $this->parent->getPath('extension_site') ) ); } } /* * Since we created the component directory and we will want to remove it if we have to roll back * the installation, let's add it to the installation step stack */ if ($created) { $this->parent->pushStep( array( 'type' => 'folder', 'path' => $this->parent->getPath('extension_site'), ) ); } // If the component admin directory does not exist, let's create it $created = false; if (!file_exists($this->parent->getPath('extension_administrator'))) { if (!$created = \JFolder::create($this->parent->getPath('extension_administrator'))) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ERROR_COMP_FAILED_TO_CREATE_DIRECTORY', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)), $this->parent->getPath('extension_site') ) ); } } /* * Since we created the component admin directory and we will want to remove it if we have to roll * back the installation, let's add it to the installation step stack */ if ($created) { $this->parent->pushStep( array( 'type' => 'folder', 'path' => $this->parent->getPath('extension_administrator'), ) ); } } /** * Method to finalise the installation processing * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function finaliseInstall() { /** @var Update $update */ $update = Table::getInstance('update'); // Clobber any possible pending updates $uid = $update->find( array( 'element' => $this->element, 'type' => $this->extension->type, 'client_id' => 1, ) ); if ($uid) { $update->delete($uid); } // We will copy the manifest file to its appropriate place. if ($this->route !== 'discover_install') { if (!$this->parent->copyManifest()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_COMP_COPY_SETUP', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)) ) ); } } // Time to build the admin menus if (!$this->_buildAdminMenus($this->extension->extension_id)) { \JLog::add(\JText::_('JLIB_INSTALLER_ABORT_COMP_BUILDADMINMENUS_FAILED'), \JLog::WARNING, 'jerror'); } // Make sure that menu items pointing to the component have correct component id assigned to them. // Prevents message "Component 'com_extension' does not exist." after uninstalling / re-installing component. if (!$this->_updateMenus($this->extension->extension_id)) { \JLog::add(\JText::_('JLIB_INSTALLER_ABORT_COMP_UPDATESITEMENUS_FAILED'), \JLog::WARNING, 'jerror'); } /** @var Asset $asset */ $asset = Table::getInstance('Asset'); // Check if an asset already exists for this extension and create it if not if (!$asset->loadByName($this->extension->element)) { // Register the component container just under root in the assets table. $asset->name = $this->extension->element; $asset->parent_id = 1; $asset->rules = '{}'; $asset->title = $this->extension->name; $asset->setLocation(1, 'last-child'); if (!$asset->store()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_ROLLBACK', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)), $this->extension->getError() ) ); } } } /** * Get the filtered extension element from the manifest * * @param string $element Optional element name to be converted * * @return string The filtered element * * @since 3.4 */ public function getElement($element = null) { $element = parent::getElement($element); if (strpos($element, 'com_') !== 0) { $element = 'com_' . $element; } return $element; } /** * Custom loadLanguage method * * @param string $path The path language files are on. * * @return void * * @since 3.1 */ public function loadLanguage($path = null) { $source = $this->parent->getPath('source'); $client = $this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE; if (!$source) { $this->parent->setPath('source', $client . '/components/' . $this->parent->extension->element); } $extension = $this->getElement(); $source = $path ?: $client . '/components/' . $extension; if ($this->getManifest()->administration->files) { $element = $this->getManifest()->administration->files; } elseif ($this->getManifest()->files) { $element = $this->getManifest()->files; } else { $element = null; } if ($element) { $folder = (string) $element->attributes()->folder; if ($folder && file_exists($path . '/' . $folder)) { $source = $path . '/' . $folder; } } $this->doLoadLanguage($extension, $source); } /** * Method to parse optional tags in the manifest * * @return void * * @since 3.4 */ protected function parseOptionalTags() { // Parse optional tags $this->parent->parseMedia($this->getManifest()->media); $this->parent->parseLanguages($this->getManifest()->languages); $this->parent->parseLanguages($this->getManifest()->administration->languages, 1); } /** * Prepares the adapter for a discover_install task * * @return void * * @since 3.4 * @throws \RuntimeException */ public function prepareDiscoverInstall() { // Need to find to find where the XML file is since we don't store this normally $client = ApplicationHelper::getClientInfo($this->extension->client_id); $short_element = str_replace('com_', '', $this->extension->element); $manifestPath = $client->path . '/components/' . $this->extension->element . '/' . $short_element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $this->parent->setPath('source', $client->path . '/components/' . $this->extension->element); $this->parent->setPath('extension_root', $this->parent->getPath('source')); $this->setManifest($this->parent->getManifest()); $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->extension->manifest_cache = json_encode($manifest_details); $this->extension->state = 0; $this->extension->name = $manifest_details['name']; $this->extension->enabled = 1; $this->extension->params = $this->parent->getParams(); $stored = false; try { $this->extension->store(); $stored = true; } catch (\RuntimeException $e) { // Try to delete existing failed records before retrying $db = $this->db; $query = $db->getQuery(true) ->select($db->qn('extension_id')) ->from($db->qn('#__extensions')) ->where($db->qn('name') . ' = ' . $db->q($this->extension->name)) ->where($db->qn('type') . ' = ' . $db->q($this->extension->type)) ->where($db->qn('element') . ' = ' . $db->q($this->extension->element)); $db->setQuery($query); $extension_ids = $db->loadColumn(); if (!empty($extension_ids)) { foreach ($extension_ids as $eid) { // Remove leftover admin menus for this extension ID $this->_removeAdminMenus($eid); // Remove the extension record itself /** @var Extension $extensionTable */ $extensionTable = Table::getInstance('extension'); $extensionTable->delete($eid); } } } if (!$stored) { try { $this->extension->store(); } catch (\RuntimeException $e) { throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ERROR_COMP_DISCOVER_STORE_DETAILS'), $e->getCode(), $e); } } } /** * Method to do any prechecks and setup the install paths for the extension * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function setupInstallPaths() { // Set the installation target paths $this->parent->setPath('extension_site', \JPath::clean(JPATH_SITE . '/components/' . $this->element)); $this->parent->setPath('extension_administrator', \JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $this->element)); // Copy the admin path as it's used as a common base $this->parent->setPath('extension_root', $this->parent->getPath('extension_administrator')); // Make sure that we have an admin element if (!$this->getManifest()->administration) { throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ERROR_COMP_INSTALL_ADMIN_ELEMENT')); } } /** * Method to setup the update routine for the adapter * * @return void * * @since 3.4 */ protected function setupUpdates() { // Hunt for the original XML file $old_manifest = null; // Use a temporary instance due to side effects; start in the administrator first $tmpInstaller = new Installer; $tmpInstaller->setPath('source', $this->parent->getPath('extension_administrator')); if (!$tmpInstaller->findManifest()) { // Then the site $tmpInstaller->setPath('source', $this->parent->getPath('extension_site')); if ($tmpInstaller->findManifest()) { $old_manifest = $tmpInstaller->getManifest(); } } else { $old_manifest = $tmpInstaller->getManifest(); } if ($old_manifest) { $this->oldAdminFiles = $old_manifest->administration->files; $this->oldFiles = $old_manifest->files; } } /** * Method to store the extension to the database * * @param bool $deleteExisting Should I try to delete existing records of the same component? * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function storeExtension($deleteExisting = false) { // The extension is stored during prepareDiscoverInstall for discover installs if ($this->route === 'discover_install') { return; } // Add or update an entry to the extension table $this->extension->name = $this->name; $this->extension->type = 'component'; $this->extension->element = $this->element; // If we are told to delete existing extension entries then do so. if ($deleteExisting) { $db = $this->parent->getDbo(); $query = $db->getQuery(true) ->select($db->qn('extension_id')) ->from($db->qn('#__extensions')) ->where($db->qn('name') . ' = ' . $db->q($this->extension->name)) ->where($db->qn('type') . ' = ' . $db->q($this->extension->type)) ->where($db->qn('element') . ' = ' . $db->q($this->extension->element)); $db->setQuery($query); $extension_ids = $db->loadColumn(); if (!empty($extension_ids)) { foreach ($extension_ids as $eid) { // Remove leftover admin menus for this extension ID $this->_removeAdminMenus($eid); // Remove the extension record itself /** @var Extension $extensionTable */ $extensionTable = Table::getInstance('extension'); $extensionTable->delete($eid); } } } // If there is not already a row, generate a heap of defaults if (!$this->currentExtensionId) { $this->extension->folder = ''; $this->extension->enabled = 1; $this->extension->protected = 0; $this->extension->access = 0; $this->extension->client_id = 1; $this->extension->params = $this->parent->getParams(); $this->extension->custom_data = ''; $this->extension->system_data = ''; } $this->extension->manifest_cache = $this->parent->generateManifestCache(); $couldStore = $this->extension->store(); if (!$couldStore && $deleteExisting) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_COMP_INSTALL_ROLLBACK', $this->extension->getError() ) ); } if (!$couldStore && !$deleteExisting) { // Maybe we have a failed installation (e.g. timeout). Let's retry after deleting old records. $this->storeExtension(true); } } /** * Custom uninstall method for components * * @param integer $id The unique extension id of the component to uninstall * * @return boolean True on success * * @since 3.1 */ public function uninstall($id) { $db = $this->db; $retval = true; // First order of business will be to load the component object table from the database. // This should give us the necessary information to proceed. if (!$this->extension->load((int) $id)) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_ERRORUNKOWNEXTENSION'), \JLog::WARNING, 'jerror'); return false; } // Is the component we are trying to uninstall a core one? // Because that is not a good idea... if ($this->extension->protected) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_WARNCORECOMPONENT'), \JLog::WARNING, 'jerror'); return false; } /* * Does this extension have a parent package? * If so, check if the package disallows individual extensions being uninstalled if the package is not being uninstalled */ if ($this->extension->package_id && !$this->parent->isPackageUninstall() && !$this->canUninstallPackageChild($this->extension->package_id)) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_CANNOT_UNINSTALL_CHILD_OF_PACKAGE', $this->extension->name), \JLog::WARNING, 'jerror'); return false; } // Get the admin and site paths for the component $this->parent->setPath('extension_administrator', \JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $this->extension->element)); $this->parent->setPath('extension_site', \JPath::clean(JPATH_SITE . '/components/' . $this->extension->element)); // Copy the admin path as it's used as a common base $this->parent->setPath('extension_root', $this->parent->getPath('extension_administrator')); /** * --------------------------------------------------------------------------------------------- * Manifest Document Setup Section * --------------------------------------------------------------------------------------------- */ // Find and load the XML install file for the component $this->parent->setPath('source', $this->parent->getPath('extension_administrator')); // Get the package manifest object // We do findManifest to avoid problem when uninstalling a list of extension: getManifest cache its manifest file $this->parent->findManifest(); $this->setManifest($this->parent->getManifest()); if (!$this->getManifest()) { // Make sure we delete the folders if no manifest exists \JFolder::delete($this->parent->getPath('extension_administrator')); \JFolder::delete($this->parent->getPath('extension_site')); // Remove the menu $this->_removeAdminMenus($this->extension->extension_id); // Raise a warning \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_ERRORREMOVEMANUALLY'), \JLog::WARNING, 'jerror'); // Return return false; } // Set the extensions name $this->set('name', $this->getName()); $this->set('element', $this->getElement()); // Attempt to load the admin language file; might have uninstall strings $this->loadLanguage(JPATH_ADMINISTRATOR . '/components/' . $this->element); /** * --------------------------------------------------------------------------------------------- * Installer Trigger Loading and Uninstall * --------------------------------------------------------------------------------------------- */ $this->setupScriptfile(); try { $this->triggerManifestScript('uninstall'); } catch (\RuntimeException $e) { // Ignore errors for now } /** * --------------------------------------------------------------------------------------------- * Database Processing Section * --------------------------------------------------------------------------------------------- */ // Let's run the uninstall queries for the component try { $this->parseQueries(); } catch (\RuntimeException $e) { \JLog::add($e->getMessage(), \JLog::WARNING, 'jerror'); $retval = false; } $this->_removeAdminMenus($this->extension->extension_id); /** * --------------------------------------------------------------------------------------------- * Filesystem Processing Section * --------------------------------------------------------------------------------------------- */ // Let's remove those language files and media in the JROOT/images/ folder that are // associated with the component we are uninstalling $this->parent->removeFiles($this->getManifest()->media); $this->parent->removeFiles($this->getManifest()->languages); $this->parent->removeFiles($this->getManifest()->administration->languages, 1); // Remove the schema version $query = $db->getQuery(true) ->delete('#__schemas') ->where('extension_id = ' . $id); $db->setQuery($query); $db->execute(); // Remove the component container in the assets table. $asset = Table::getInstance('Asset'); if ($asset->loadByName($this->element)) { $asset->delete(); } // Remove categories for this component $query->clear() ->delete('#__categories') ->where('extension=' . $db->quote($this->element), 'OR') ->where('extension LIKE ' . $db->quote($this->element . '.%')); $db->setQuery($query); $db->execute(); // Rebuild the categories for correct lft/rgt $category = Table::getInstance('category'); $category->rebuild(); // Clobber any possible pending updates $update = Table::getInstance('update'); $uid = $update->find( array( 'element' => $this->extension->element, 'type' => 'component', 'client_id' => 1, 'folder' => '', ) ); if ($uid) { $update->delete($uid); } // Now we need to delete the installation directories. This is the final step in uninstalling the component. if (trim($this->extension->element)) { // Delete the component site directory if (is_dir($this->parent->getPath('extension_site'))) { if (!\JFolder::delete($this->parent->getPath('extension_site'))) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_FAILED_REMOVE_DIRECTORY_SITE'), \JLog::WARNING, 'jerror'); $retval = false; } } // Delete the component admin directory if (is_dir($this->parent->getPath('extension_administrator'))) { if (!\JFolder::delete($this->parent->getPath('extension_administrator'))) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_FAILED_REMOVE_DIRECTORY_ADMIN'), \JLog::WARNING, 'jerror'); $retval = false; } } // Now we will no longer need the extension object, so let's delete it $this->extension->delete($this->extension->extension_id); return $retval; } else { // No component option defined... cannot delete what we don't know about \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_NO_OPTION'), \JLog::WARNING, 'jerror'); return false; } } /** * Method to build menu database entries for a component * * @param int|null $componentId The component ID for which I'm building menus * * @return boolean True if successful * * @since 3.1 */ protected function _buildAdminMenus($componentId = null) { $db = $this->parent->getDbo(); $option = $this->get('element'); // If a component exists with this option in the table within the protected menutype 'main' then we don't need to add menus $query = $db->getQuery(true) ->select('m.id, e.extension_id') ->from('#__menu AS m') ->join('LEFT', '#__extensions AS e ON m.component_id = e.extension_id') ->where('m.parent_id = 1') ->where('m.client_id = 1') ->where('m.menutype = ' . $db->quote('main')) ->where('e.element = ' . $db->quote($option)); $db->setQuery($query); // In case of a failed installation (e.g. timeout error) we may have duplicate menu item and extension records. $componentrows = $db->loadObjectList(); // Check if menu items exist if (!empty($componentrows)) { // Don't do anything if overwrite has not been enabled if (!$this->parent->isOverwrite()) { return true; } // Remove all menu items foreach ($componentrows as $componentrow) { // Remove existing menu items if overwrite has been enabled if ($option) { // If something goes wrong, there's no way to rollback TODO: Search for better solution $this->_removeAdminMenus($componentrow->extension_id); } } } // Only try to detect the component ID if it's not provided if (empty($componentId)) { // Lets find the extension id $query->clear() ->select('e.extension_id') ->from('#__extensions AS e') ->where('e.type = ' . $db->quote('component')) ->where('e.element = ' . $db->quote($option)); $db->setQuery($query); $componentId = $db->loadResult(); } // Ok, now its time to handle the menus. Start with the component root menu, then handle submenus. $menuElement = $this->getManifest()->administration->menu; // Just do not create the menu if $menuElement not exist if (!$menuElement) { return true; } // If the menu item is hidden do nothing more, just return if (in_array((string) $menuElement['hidden'], array('true', 'hidden'))) { return true; } // Let's figure out what the menu item data should look like $data = array(); if ($menuElement) { // I have a menu element, use this information $data['menutype'] = 'main'; $data['client_id'] = 1; $data['title'] = (string) trim($menuElement); $data['alias'] = (string) $menuElement; $data['type'] = 'component'; $data['published'] = 1; $data['parent_id'] = 1; $data['component_id'] = $componentId; $data['img'] = ((string) $menuElement->attributes()->img) ?: 'class:component'; $data['home'] = 0; $data['path'] = ''; $data['params'] = ''; // Set the menu link $request = array(); if ((string) $menuElement->attributes()->task) { $request[] = 'task=' . $menuElement->attributes()->task; } if ((string) $menuElement->attributes()->view) { $request[] = 'view=' . $menuElement->attributes()->view; } $qstring = count($request) ? '&' . implode('&', $request) : ''; $data['link'] = 'index.php?option=' . $option . $qstring; } else { // No menu element was specified, Let's make a generic menu item $data = array(); $data['menutype'] = 'main'; $data['client_id'] = 1; $data['title'] = $option; $data['alias'] = $option; $data['link'] = 'index.php?option=' . $option; $data['type'] = 'component'; $data['published'] = 1; $data['parent_id'] = 1; $data['component_id'] = $componentId; $data['img'] = 'class:component'; $data['home'] = 0; $data['path'] = ''; $data['params'] = ''; } // Try to create the menu item in the database $parent_id = $this->_createAdminMenuItem($data, 1); if ($parent_id === false) { return false; } /* * Process SubMenus */ if (!$this->getManifest()->administration->submenu) { // No submenu? We're done. return true; } foreach ($this->getManifest()->administration->submenu->menu as $child) { $data = array(); $data['menutype'] = 'main'; $data['client_id'] = 1; $data['title'] = (string) trim($child); $data['alias'] = (string) $child; $data['type'] = 'component'; $data['published'] = 1; $data['parent_id'] = $parent_id; $data['component_id'] = $componentId; $data['img'] = ((string) $child->attributes()->img) ?: 'class:component'; $data['home'] = 0; // Set the sub menu link if ((string) $child->attributes()->link) { $data['link'] = 'index.php?' . $child->attributes()->link; } else { $request = array(); if ((string) $child->attributes()->act) { $request[] = 'act=' . $child->attributes()->act; } if ((string) $child->attributes()->task) { $request[] = 'task=' . $child->attributes()->task; } if ((string) $child->attributes()->controller) { $request[] = 'controller=' . $child->attributes()->controller; } if ((string) $child->attributes()->view) { $request[] = 'view=' . $child->attributes()->view; } if ((string) $child->attributes()->layout) { $request[] = 'layout=' . $child->attributes()->layout; } if ((string) $child->attributes()->sub) { $request[] = 'sub=' . $child->attributes()->sub; } $qstring = count($request) ? '&' . implode('&', $request) : ''; $data['link'] = 'index.php?option=' . $option . $qstring; } $submenuId = $this->_createAdminMenuItem($data, $parent_id); if ($submenuId === false) { return false; } /* * Since we have created a menu item, we add it to the installation step stack * so that if we have to rollback the changes we can undo it. */ $this->parent->pushStep(array('type' => 'menu', 'id' => $componentId)); } return true; } /** * Method to remove admin menu references to a component * * @param int $id The ID of the extension whose admin menus will be removed * * @return boolean True if successful. * * @since 3.1 */ protected function _removeAdminMenus($id) { $db = $this->parent->getDbo(); /** @var \JTableMenu $table */ $table = Table::getInstance('menu'); // Get the ids of the menu items $query = $db->getQuery(true) ->select('id') ->from('#__menu') ->where($db->quoteName('client_id') . ' = 1') ->where($db->quoteName('menutype') . ' = ' . $db->q('main')) ->where($db->quoteName('component_id') . ' = ' . (int) $id); $db->setQuery($query); $ids = $db->loadColumn(); $result = true; // Check for error if (!empty($ids)) { // Iterate the items to delete each one. foreach ($ids as $menuid) { if (!$table->delete((int) $menuid, false)) { $this->setError($table->getError()); $result = false; } } // Rebuild the whole tree $table->rebuild(); } return $result; } /** * Method to update menu database entries for a component in case the component has been uninstalled before. * NOTE: This will not update admin menus. Use _updateMenus() instead to update admin menus ase well. * * @param int|null $componentId The component ID. * * @return boolean True if successful * * @since 3.4.2 */ protected function _updateSiteMenus($componentId = null) { return $this->_updateMenus($componentId, 0); } /** * Method to update menu database entries for a component in case if the component has been uninstalled before. * * @param int|null $componentId The component ID. * @param int $clientId The client id * * @return boolean True if successful * * @since 3.7.0 */ protected function _updateMenus($componentId, $clientId = null) { $db = $this->parent->getDbo(); $option = $this->get('element'); // Update all menu items which contain 'index.php?option=com_extension' or 'index.php?option=com_extension&...' // to use the new component id. $query = $db->getQuery(true) ->update('#__menu') ->set('component_id = ' . $db->quote($componentId)) ->where('type = ' . $db->quote('component')) ->where('(' . 'link LIKE ' . $db->quote('index.php?option=' . $option) . ' OR ' . 'link LIKE ' . $db->q($db->escape('index.php?option=' . $option . '&') . '%', false) . ')'); if (isset($clientId)) { $query->where('client_id = ' . (int) $clientId); } $db->setQuery($query); try { $db->execute(); } catch (\RuntimeException $e) { return false; } return true; } /** * Custom rollback method * - Roll back the component menu item * * @param array $step Installation step to rollback. * * @return boolean True on success * * @since 3.1 */ protected function _rollback_menu($step) { return $this->_removeAdminMenus($step['id']); } /** * Discover unregistered extensions. * * @return array A list of extensions. * * @since 3.1 */ public function discover() { $results = array(); $site_components = \JFolder::folders(JPATH_SITE . '/components'); $admin_components = \JFolder::folders(JPATH_ADMINISTRATOR . '/components'); foreach ($site_components as $component) { if (file_exists(JPATH_SITE . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml')) { $manifest_details = Installer::parseXMLInstallFile( JPATH_SITE . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml' ); $extension = Table::getInstance('extension'); $extension->set('type', 'component'); $extension->set('client_id', 0); $extension->set('element', $component); $extension->set('folder', ''); $extension->set('name', $component); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $extension->set('params', '{}'); $results[] = $extension; } } foreach ($admin_components as $component) { if (file_exists(JPATH_ADMINISTRATOR . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml')) { $manifest_details = Installer::parseXMLInstallFile( JPATH_ADMINISTRATOR . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml' ); $extension = Table::getInstance('extension'); $extension->set('type', 'component'); $extension->set('client_id', 1); $extension->set('element', $component); $extension->set('folder', ''); $extension->set('name', $component); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $extension->set('params', '{}'); $results[] = $extension; } } return $results; } /** * Refreshes the extension table cache * * @return boolean Result of operation, true if updated, false on failure * * @since 3.1 */ public function refreshManifestCache() { // Need to find to find where the XML file is since we don't store this normally $client = ApplicationHelper::getClientInfo($this->parent->extension->client_id); $short_element = str_replace('com_', '', $this->parent->extension->element); $manifestPath = $client->path . '/components/' . $this->parent->extension->element . '/' . $short_element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; try { return $this->parent->extension->store(); } catch (\RuntimeException $e) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_COMP_REFRESH_MANIFEST_CACHE'), \JLog::WARNING, 'jerror'); return false; } } /** * Creates the menu item in the database. If the item already exists it tries to remove it and create it afresh. * * @param array &$data The menu item data to create * @param integer $parentId The parent menu item ID * * @return boolean|integer Menu item ID on success, false on failure */ protected function _createAdminMenuItem(array &$data, $parentId) { $db = $this->parent->getDbo(); /** @var \JTableMenu $table */ $table = Table::getInstance('menu'); try { $table->setLocation($parentId, 'last-child'); } catch (\InvalidArgumentException $e) { \JLog::add($e->getMessage(), \JLog::WARNING, 'jerror'); return false; } if (!$table->bind($data) || !$table->check() || !$table->store()) { // The menu item already exists. Delete it and retry instead of throwing an error. $query = $db->getQuery(true) ->select('id') ->from('#__menu') ->where('menutype = ' . $db->q($data['menutype'])) ->where('client_id = 1') ->where('link = ' . $db->q($data['link'])) ->where('type = ' . $db->q($data['type'])) ->where('parent_id = ' . $db->q($data['parent_id'])) ->where('home = ' . $db->q($data['home'])); $db->setQuery($query); $menu_id = $db->loadResult(); if (!$menu_id) { // Oops! Could not get the menu ID. Go back and rollback changes. \JError::raiseWarning(1, $table->getError()); return false; } else { /** @var \JTableMenu $temporaryTable */ $temporaryTable = Table::getInstance('menu'); $temporaryTable->delete($menu_id, true); $temporaryTable->load($parentId); $temporaryTable->rebuild($parentId, $temporaryTable->lft, $temporaryTable->level, $temporaryTable->path); // Retry creating the menu item $table->setLocation($parentId, 'last-child'); if (!$table->bind($data) || !$table->check() || !$table->store()) { // Install failed, warn user and rollback changes \JError::raiseWarning(1, $table->getError()); return false; } } } return $table->id; } } PK b�!]��M��C �C TemplateAdapter.phpnu &1i� <?php /** * Joomla! Content Management System * * @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Installer\Adapter; defined('JPATH_PLATFORM') or die; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Installer\InstallerAdapter; use Joomla\CMS\Table\Table; use Joomla\CMS\Table\Update; \JLoader::import('joomla.filesystem.folder'); /** * Template installer * * @since 3.1 */ class TemplateAdapter extends InstallerAdapter { /** * The install client ID * * @var integer * @since 3.4 */ protected $clientId; /** * Method to check if the extension is already present in the database * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function checkExistingExtension() { try { $this->currentExtensionId = $this->extension->find( array( 'element' => $this->element, 'type' => $this->type, 'client_id' => $this->clientId, ) ); } catch (\RuntimeException $e) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_ROLLBACK', \JText::_('JLIB_INSTALLER_' . $this->route), $e->getMessage() ), $e->getCode(), $e ); } } /** * Method to copy the extension's base files from the `<files>` tag(s) and the manifest file * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function copyBaseFiles() { // Copy all the necessary files if ($this->parent->parseFiles($this->getManifest()->files, -1) === false) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_TPL_INSTALL_COPY_FILES', 'files' ) ); } if ($this->parent->parseFiles($this->getManifest()->images, -1) === false) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_TPL_INSTALL_COPY_FILES', 'images' ) ); } if ($this->parent->parseFiles($this->getManifest()->css, -1) === false) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_TPL_INSTALL_COPY_FILES', 'css' ) ); } // If there is a manifest script, let's copy it. if ($this->manifest_script) { $path['src'] = $this->parent->getPath('source') . '/' . $this->manifest_script; $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->manifest_script; if ($this->parent->isOverwrite() || !file_exists($path['dest'])) { if (!$this->parent->copyFiles(array($path))) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_MANIFEST', \JText::_('JLIB_INSTALLER_' . strtoupper($this->getRoute())) ) ); } } } } /** * Method to finalise the installation processing * * @return void * * @since 3.1 * @throws \RuntimeException */ protected function finaliseInstall() { // Clobber any possible pending updates /** @var Update $update */ $update = Table::getInstance('update'); $uid = $update->find( array( 'element' => $this->element, 'type' => $this->type, 'client_id' => $this->clientId, ) ); if ($uid) { $update->delete($uid); } // Lastly, we will copy the manifest file to its appropriate place. if ($this->route !== 'discover_install') { if (!$this->parent->copyManifest(-1)) { // Install failed, rollback changes throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ABORT_TPL_INSTALL_COPY_SETUP')); } } } /** * Custom loadLanguage method * * @param string $path The path where to find language files. * * @return InstallerTemplate * * @since 3.1 */ public function loadLanguage($path = null) { $source = $this->parent->getPath('source'); $basePath = $this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE; if (!$source) { $this->parent->setPath('source', $basePath . '/templates/' . $this->parent->extension->element); } $this->setManifest($this->parent->getManifest()); $client = (string) $this->getManifest()->attributes()->client; // Load administrator language if not set. if (!$client) { $client = 'ADMINISTRATOR'; } $base = constant('JPATH_' . strtoupper($client)); $extension = 'tpl_' . $this->getName(); $source = $path ?: $base . '/templates/' . $this->getName(); $this->doLoadLanguage($extension, $source, $base); } /** * Method to parse optional tags in the manifest * * @return void * * @since 3.4 */ protected function parseOptionalTags() { $this->parent->parseMedia($this->getManifest()->media); $this->parent->parseLanguages($this->getManifest()->languages, $this->clientId); } /** * Overloaded method to parse queries for template installations * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function parseQueries() { if (in_array($this->route, array('install', 'discover_install'))) { $db = $this->db; $lang = \JFactory::getLanguage(); $debug = $lang->setDebug(false); $columns = array( $db->quoteName('template'), $db->quoteName('client_id'), $db->quoteName('home'), $db->quoteName('title'), $db->quoteName('params'), ); $values = array( $db->quote($this->extension->element), $this->extension->client_id, $db->quote(0), $db->quote(\JText::sprintf('JLIB_INSTALLER_DEFAULT_STYLE', \JText::_($this->extension->name))), $db->quote($this->extension->params), ); $lang->setDebug($debug); // Insert record in #__template_styles $query = $db->getQuery(true); $query->insert($db->quoteName('#__template_styles')) ->columns($columns) ->values(implode(',', $values)); // There is a chance this could fail but we don't care... $db->setQuery($query)->execute(); } } /** * Prepares the adapter for a discover_install task * * @return void * * @since 3.4 */ public function prepareDiscoverInstall() { $client = ApplicationHelper::getClientInfo($this->extension->client_id); $manifestPath = $client->path . '/templates/' . $this->extension->element . '/templateDetails.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $this->setManifest($this->parent->getManifest()); } /** * Method to do any prechecks and setup the install paths for the extension * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function setupInstallPaths() { // Get the client application target $cname = (string) $this->getManifest()->attributes()->client; if ($cname) { // Attempt to map the client to a base path $client = ApplicationHelper::getClientInfo($cname, true); if ($client === false) { throw new \RuntimeException(\JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_UNKNOWN_CLIENT', $cname)); } $basePath = $client->path; $this->clientId = $client->id; } else { // No client attribute was found so we assume the site as the client $basePath = JPATH_SITE; $this->clientId = 0; } // Set the template root path if (empty($this->element)) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_MOD_INSTALL_NOFILE', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)) ) ); } $this->parent->setPath('extension_root', $basePath . '/templates/' . $this->element); } /** * Method to store the extension to the database * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function storeExtension() { // Discover installs are stored a little differently if ($this->route === 'discover_install') { $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->extension->manifest_cache = json_encode($manifest_details); $this->extension->state = 0; $this->extension->name = $manifest_details['name']; $this->extension->enabled = 1; $this->extension->params = $this->parent->getParams(); if (!$this->extension->store()) { // Install failed, roll back changes throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ERROR_TPL_DISCOVER_STORE_DETAILS')); } return; } // Was there a template already installed with the same name? if ($this->currentExtensionId) { if (!$this->parent->isOverwrite()) { // Install failed, roll back changes throw new \RuntimeException( \JText::_('JLIB_INSTALLER_ABORT_TPL_INSTALL_ALREADY_INSTALLED') ); } // Load the entry and update the manifest_cache $this->extension->load($this->currentExtensionId); } else { $this->extension->type = 'template'; $this->extension->element = $this->element; // There is no folder for templates $this->extension->folder = ''; $this->extension->enabled = 1; $this->extension->protected = 0; $this->extension->access = 1; $this->extension->client_id = $this->clientId; $this->extension->params = $this->parent->getParams(); // Custom data $this->extension->custom_data = ''; $this->extension->system_data = ''; } // Name might change in an update $this->extension->name = $this->name; $this->extension->manifest_cache = $this->parent->generateManifestCache(); if (!$this->extension->store()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_ROLLBACK', \JText::_('JLIB_INSTALLER_' . strtoupper($this->route)), $this->extension->getError() ) ); } } /** * Custom uninstall method * * @param integer $id The extension ID * * @return boolean True on success * * @since 3.1 */ public function uninstall($id) { // First order of business will be to load the template object table from the database. // This should give us the necessary information to proceed. $row = Table::getInstance('extension'); if (!$row->load((int) $id) || $row->element === '') { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_ERRORUNKOWNEXTENSION'), \JLog::WARNING, 'jerror'); return false; } // Is the template we are trying to uninstall a core one? // Because that is not a good idea... if ($row->protected) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_WARNCORETEMPLATE', $row->name), \JLog::WARNING, 'jerror'); return false; } /* * Does this extension have a parent package? * If so, check if the package disallows individual extensions being uninstalled if the package is not being uninstalled */ if ($row->package_id && !$this->parent->isPackageUninstall() && !$this->canUninstallPackageChild($row->package_id)) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_CANNOT_UNINSTALL_CHILD_OF_PACKAGE', $row->name), \JLog::WARNING, 'jerror'); return false; } $name = $row->element; $clientId = $row->client_id; // For a template the id will be the template name which represents the subfolder of the templates folder that the template resides in. if (!$name) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_ID_EMPTY'), \JLog::WARNING, 'jerror'); return false; } // Deny remove default template $db = $this->parent->getDbo(); $query = $db->getQuery(true) ->select('COUNT(*)') ->from($db->qn('#__template_styles')) ->where($db->qn('home') . ' = ' . $db->q('1')) ->where($db->qn('template') . ' = ' . $db->q($name)) ->where($db->quoteName('client_id') . ' = ' . $clientId); $db->setQuery($query); if ($db->loadResult() != 0) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_DEFAULT'), \JLog::WARNING, 'jerror'); return false; } // Get the template root path $client = ApplicationHelper::getClientInfo($clientId); if (!$client) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_INVALID_CLIENT'), \JLog::WARNING, 'jerror'); return false; } $this->parent->setPath('extension_root', $client->path . '/templates/' . strtolower($name)); $this->parent->setPath('source', $this->parent->getPath('extension_root')); // We do findManifest to avoid problem when uninstalling a list of extensions: getManifest cache its manifest file $this->parent->findManifest(); $manifest = $this->parent->getManifest(); if (!($manifest instanceof \SimpleXMLElement)) { // Kill the extension entry $row->delete($row->extension_id); unset($row); // Make sure we delete the folders \JFolder::delete($this->parent->getPath('extension_root')); \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_INVALID_NOTFOUND_MANIFEST'), \JLog::WARNING, 'jerror'); return false; } // Remove files $this->parent->removeFiles($manifest->media); $this->parent->removeFiles($manifest->languages, $clientId); // Delete the template directory if (\JFolder::exists($this->parent->getPath('extension_root'))) { $retval = \JFolder::delete($this->parent->getPath('extension_root')); } else { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_DIRECTORY'), \JLog::WARNING, 'jerror'); $retval = false; } // Set menu that assigned to the template back to default template $subQuery = $db->getQuery(true) ->select('s.id') ->from($db->qn('#__template_styles', 's')) ->where($db->qn('s.template') . ' = ' . $db->q(strtolower($name))) ->where($db->qn('s.client_id') . ' = ' . $clientId); $query->clear() ->update($db->qn('#__menu')) ->set($db->qn('template_style_id') . ' = 0') ->where($db->qn('template_style_id') . ' IN (' . (string) $subQuery . ')'); $db->setQuery($query); $db->execute(); $query = $db->getQuery(true) ->delete($db->quoteName('#__template_styles')) ->where($db->quoteName('template') . ' = ' . $db->quote($name)) ->where($db->quoteName('client_id') . ' = ' . $clientId); $db->setQuery($query); $db->execute(); $row->delete($row->extension_id); unset($row); return $retval; } /** * Discover existing but uninstalled templates * * @return array Extension list */ public function discover() { $results = array(); $site_list = \JFolder::folders(JPATH_SITE . '/templates'); $admin_list = \JFolder::folders(JPATH_ADMINISTRATOR . '/templates'); $site_info = ApplicationHelper::getClientInfo('site', true); $admin_info = ApplicationHelper::getClientInfo('administrator', true); foreach ($site_list as $template) { if (file_exists(JPATH_SITE . "/templates/$template/templateDetails.xml")) { if ($template === 'system') { // Ignore special system template continue; } $manifest_details = Installer::parseXMLInstallFile(JPATH_SITE . "/templates/$template/templateDetails.xml"); $extension = Table::getInstance('extension'); $extension->set('type', 'template'); $extension->set('client_id', $site_info->id); $extension->set('element', $template); $extension->set('folder', ''); $extension->set('name', $template); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $extension->set('params', '{}'); $results[] = $extension; } } foreach ($admin_list as $template) { if (file_exists(JPATH_ADMINISTRATOR . "/templates/$template/templateDetails.xml")) { if ($template === 'system') { // Ignore special system template continue; } $manifest_details = Installer::parseXMLInstallFile(JPATH_ADMINISTRATOR . "/templates/$template/templateDetails.xml"); $extension = Table::getInstance('extension'); $extension->set('type', 'template'); $extension->set('client_id', $admin_info->id); $extension->set('element', $template); $extension->set('folder', ''); $extension->set('name', $template); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $extension->set('params', '{}'); $results[] = $extension; } } return $results; } /** * Refreshes the extension table cache * * @return boolean Result of operation, true if updated, false on failure * * @since 3.1 */ public function refreshManifestCache() { // Need to find to find where the XML file is since we don't store this normally. $client = ApplicationHelper::getClientInfo($this->parent->extension->client_id); $manifestPath = $client->path . '/templates/' . $this->parent->extension->element . '/templateDetails.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; try { return $this->parent->extension->store(); } catch (\RuntimeException $e) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_TPL_REFRESH_MANIFEST_CACHE'), \JLog::WARNING, 'jerror'); return false; } } } PK b�!]��LM M PluginAdapter.phpnu &1i� <?php /** * Joomla! Content Management System * * @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Installer\Adapter; defined('JPATH_PLATFORM') or die; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Installer\InstallerAdapter; use Joomla\CMS\Table\Table; use Joomla\CMS\Table\Update; \JLoader::import('joomla.filesystem.folder'); /** * Plugin installer * * @since 3.1 */ class PluginAdapter extends InstallerAdapter { /** * `<scriptfile>` element of the extension manifest * * @var object * @since 3.1 */ protected $scriptElement = null; /** * `<files>` element of the old extension manifest * * @var object * @since 3.1 */ protected $oldFiles = null; /** * Method to check if the extension is already present in the database * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function checkExistingExtension() { try { $this->currentExtensionId = $this->extension->find( array('type' => $this->type, 'element' => $this->element, 'folder' => $this->group) ); } catch (\RuntimeException $e) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_ROLLBACK', \JText::_('JLIB_INSTALLER_' . $this->route), $e->getMessage() ), $e->getCode(), $e ); } } /** * Method to copy the extension's base files from the `<files>` tag(s) and the manifest file * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function copyBaseFiles() { // Copy all necessary files if ($this->parent->parseFiles($this->getManifest()->files, -1, $this->oldFiles) === false) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_PLG_COPY_FILES', \JText::_('JLIB_INSTALLER_' . $this->route) ) ); } // If there is a manifest script, let's copy it. if ($this->manifest_script) { $path['src'] = $this->parent->getPath('source') . '/' . $this->manifest_script; $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->manifest_script; if ($this->parent->isOverwrite() || !file_exists($path['dest'])) { if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_PLG_INSTALL_MANIFEST', \JText::_('JLIB_INSTALLER_' . $this->route) ) ); } } } } /** * Method to create the extension root path if necessary * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function createExtensionRoot() { // Run the common create code first parent::createExtensionRoot(); // If we're updating at this point when there is always going to be an extension_root find the old XML files if ($this->route === 'update') { // Create a new installer because findManifest sets stuff; side effects! $tmpInstaller = new Installer; // Look in the extension root $tmpInstaller->setPath('source', $this->parent->getPath('extension_root')); if ($tmpInstaller->findManifest()) { $old_manifest = $tmpInstaller->getManifest(); $this->oldFiles = $old_manifest->files; } } } /** * Method to finalise the installation processing * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function finaliseInstall() { // Clobber any possible pending updates /** @var Update $update */ $update = Table::getInstance('update'); $uid = $update->find( array( 'element' => $this->element, 'type' => $this->type, 'folder' => $this->group, ) ); if ($uid) { $update->delete($uid); } // Lastly, we will copy the manifest file to its appropriate place. if ($this->route !== 'discover_install') { if (!$this->parent->copyManifest(-1)) { // Install failed, rollback changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_PLG_INSTALL_COPY_SETUP', \JText::_('JLIB_INSTALLER_' . $this->route) ) ); } } } /** * Get the filtered extension element from the manifest * * @param string $element Optional element name to be converted * * @return string The filtered element * * @since 3.4 */ public function getElement($element = null) { if (!$element) { // Backward Compatibility // @todo Deprecate in future version if (count($this->getManifest()->files->children())) { $type = (string) $this->getManifest()->attributes()->type; foreach ($this->getManifest()->files->children() as $file) { if ((string) $file->attributes()->$type) { $element = (string) $file->attributes()->$type; break; } } } } return $element; } /** * Get the class name for the install adapter script. * * @return string The class name. * * @since 3.4 */ protected function getScriptClassName() { return 'Plg' . str_replace('-', '', $this->group) . $this->element . 'InstallerScript'; } /** * Custom loadLanguage method * * @param string $path The path where to find language files. * * @return void * * @since 3.1 */ public function loadLanguage($path = null) { $source = $this->parent->getPath('source'); if (!$source) { $this->parent->setPath( 'source', JPATH_PLUGINS . '/' . $this->parent->extension->folder . '/' . $this->parent->extension->element ); } $element = $this->getManifest()->files; if ($element) { $group = strtolower((string) $this->getManifest()->attributes()->group); $name = ''; if (count($element->children())) { foreach ($element->children() as $file) { if ((string) $file->attributes()->plugin) { $name = strtolower((string) $file->attributes()->plugin); break; } } } if ($name) { $extension = "plg_${group}_${name}"; $source = $path ?: JPATH_PLUGINS . "/$group/$name"; $folder = (string) $element->attributes()->folder; if ($folder && file_exists("$path/$folder")) { $source = "$path/$folder"; } $this->doLoadLanguage($extension, $source, JPATH_ADMINISTRATOR); } } } /** * Method to parse optional tags in the manifest * * @return void * * @since 3.4 */ protected function parseOptionalTags() { // Parse optional tags -- media and language files for plugins go in admin app $this->parent->parseMedia($this->getManifest()->media, 1); $this->parent->parseLanguages($this->getManifest()->languages, 1); } /** * Prepares the adapter for a discover_install task * * @return void * * @since 3.4 */ public function prepareDiscoverInstall() { $client = ApplicationHelper::getClientInfo($this->extension->client_id); $basePath = $client->path . '/plugins/' . $this->extension->folder; if (is_dir($basePath . '/' . $this->extension->element)) { $manifestPath = $basePath . '/' . $this->extension->element . '/' . $this->extension->element . '.xml'; } else { // @deprecated 4.0 - This path supports Joomla! 1.5 plugin folder layouts $manifestPath = $basePath . '/' . $this->extension->element . '.xml'; } $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $this->setManifest($this->parent->getManifest()); } /** * Method to do any prechecks and setup the install paths for the extension * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function setupInstallPaths() { $this->group = (string) $this->getManifest()->attributes()->group; if (empty($this->element) && empty($this->group)) { throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_PLG_INSTALL_NO_FILE', \JText::_('JLIB_INSTALLER_' . $this->route) ) ); } $this->parent->setPath('extension_root', JPATH_PLUGINS . '/' . $this->group . '/' . $this->element); } /** * Method to store the extension to the database * * @return void * * @since 3.4 * @throws \RuntimeException */ protected function storeExtension() { // Discover installs are stored a little differently if ($this->route === 'discover_install') { $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->extension->manifest_cache = json_encode($manifest_details); $this->extension->state = 0; $this->extension->name = $manifest_details['name']; $this->extension->enabled = 'editors' === $this->extension->folder ? 1 : 0; $this->extension->params = $this->parent->getParams(); if (!$this->extension->store()) { // Install failed, roll back changes throw new \RuntimeException(\JText::_('JLIB_INSTALLER_ERROR_PLG_DISCOVER_STORE_DETAILS')); } return; } // Was there a plugin with the same name already installed? if ($this->currentExtensionId) { if (!$this->parent->isOverwrite()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_PLG_INSTALL_ALLREADY_EXISTS', \JText::_('JLIB_INSTALLER_' . $this->route), $this->name ) ); } $this->extension->load($this->currentExtensionId); $this->extension->name = $this->name; $this->extension->manifest_cache = $this->parent->generateManifestCache(); // Update the manifest cache and name $this->extension->store(); } else { // Store in the extensions table (1.6) $this->extension->name = $this->name; $this->extension->type = 'plugin'; $this->extension->ordering = 0; $this->extension->element = $this->element; $this->extension->folder = $this->group; $this->extension->enabled = 0; $this->extension->protected = 0; $this->extension->access = 1; $this->extension->client_id = 0; $this->extension->params = $this->parent->getParams(); // Custom data $this->extension->custom_data = ''; // System data $this->extension->system_data = ''; $this->extension->manifest_cache = $this->parent->generateManifestCache(); // Editor plugins are published by default if ($this->group === 'editors') { $this->extension->enabled = 1; } if (!$this->extension->store()) { // Install failed, roll back changes throw new \RuntimeException( \JText::sprintf( 'JLIB_INSTALLER_ABORT_PLG_INSTALL_ROLLBACK', \JText::_('JLIB_INSTALLER_' . $this->route), $this->extension->getError() ) ); } // Since we have created a plugin item, we add it to the installation step stack // so that if we have to rollback the changes we can undo it. $this->parent->pushStep(array('type' => 'extension', 'id' => $this->extension->extension_id)); } } /** * Custom uninstall method * * @param integer $id The id of the plugin to uninstall * * @return boolean True on success * * @since 3.1 */ public function uninstall($id) { $this->route = 'uninstall'; $row = null; $retval = true; $db = $this->parent->getDbo(); // First order of business will be to load the plugin object table from the database. // This should give us the necessary information to proceed. $row = Table::getInstance('extension'); if (!$row->load((int) $id)) { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_PLG_UNINSTALL_ERRORUNKOWNEXTENSION'), \JLog::WARNING, 'jerror'); return false; } // Is the plugin we are trying to uninstall a core one? // Because that is not a good idea... if ($row->protected) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_PLG_UNINSTALL_WARNCOREPLUGIN', $row->name), \JLog::WARNING, 'jerror'); return false; } /* * Does this extension have a parent package? * If so, check if the package disallows individual extensions being uninstalled if the package is not being uninstalled */ if ($row->package_id && !$this->parent->isPackageUninstall() && !$this->canUninstallPackageChild($row->package_id)) { \JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_CANNOT_UNINSTALL_CHILD_OF_PACKAGE', $row->name), \JLog::WARNING, 'jerror'); return false; } // Get the plugin folder so we can properly build the plugin path if (trim($row->folder) === '') { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_PLG_UNINSTALL_FOLDER_FIELD_EMPTY'), \JLog::WARNING, 'jerror'); return false; } // Set the plugin root path $this->parent->setPath('extension_root', JPATH_PLUGINS . '/' . $row->folder . '/' . $row->element); $this->parent->setPath('source', $this->parent->getPath('extension_root')); $this->parent->findManifest(); $this->setManifest($this->parent->getManifest()); // Attempt to load the language file; might have uninstall strings $this->parent->setPath('source', JPATH_PLUGINS . '/' . $row->folder . '/' . $row->element); $this->loadLanguage(JPATH_PLUGINS . '/' . $row->folder . '/' . $row->element); /** * --------------------------------------------------------------------------------------------- * Installer Trigger Loading * --------------------------------------------------------------------------------------------- */ // If there is a manifest class file, let's load it; we'll copy it later (don't have dest yet) $manifestScript = (string) $this->getManifest()->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript; // If a dash is present in the folder, remove it $folderClass = str_replace('-', '', $row->folder); // Set the class name $classname = 'Plg' . $folderClass . $row->element . 'InstallerScript'; \JLoader::register($classname, $manifestScriptFile); if (class_exists($classname)) { // Create a new instance $this->parent->manifestClass = new $classname($this); // And set this so we can copy it later $this->set('manifest_script', $manifestScript); } } // Run preflight if possible (since we know we're not an update) ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight')) { if ($this->parent->manifestClass->preflight($this->route, $this) === false) { // Preflight failed, rollback changes $this->parent->abort(\JText::_('JLIB_INSTALLER_ABORT_PLG_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } // Create the $msg object and append messages from preflight $msg = ob_get_contents(); ob_end_clean(); // Let's run the queries for the plugin $utfresult = $this->parent->parseSQLFiles($this->getManifest()->uninstall->sql); if ($utfresult === false) { // Install failed, rollback changes $this->parent->abort(\JText::sprintf('JLIB_INSTALLER_ABORT_PLG_UNINSTALL_SQL_ERROR', $db->stderr(true))); return false; } // Run the custom uninstall method if possible ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'uninstall')) { $this->parent->manifestClass->uninstall($this); } // Append messages $msg .= ob_get_contents(); ob_end_clean(); // Remove the plugin files $this->parent->removeFiles($this->getManifest()->files, -1); // Remove all media and languages as well $this->parent->removeFiles($this->getManifest()->media); $this->parent->removeFiles($this->getManifest()->languages, 1); // Remove the schema version $query = $db->getQuery(true) ->delete('#__schemas') ->where('extension_id = ' . $row->extension_id); $db->setQuery($query); $db->execute(); // Now we will no longer need the plugin object, so let's delete it $row->delete($row->extension_id); unset($row); // Remove the plugin's folder \JFolder::delete($this->parent->getPath('extension_root')); if ($msg != '') { $this->parent->set('extension_message', $msg); } return $retval; } /** * Custom discover method * * @return array Extension) list of extensions available * * @since 3.1 */ public function discover() { $results = array(); $folder_list = \JFolder::folders(JPATH_SITE . '/plugins'); foreach ($folder_list as $folder) { $file_list = \JFolder::files(JPATH_SITE . '/plugins/' . $folder, '\.xml$'); foreach ($file_list as $file) { $manifest_details = Installer::parseXMLInstallFile(JPATH_SITE . '/plugins/' . $folder . '/' . $file); $file = \JFile::stripExt($file); // Ignore example plugins if ($file === 'example' || $manifest_details === false) { continue; } $element = empty($manifest_details['filename']) ? $file : $manifest_details['filename']; $extension = Table::getInstance('extension'); $extension->set('type', 'plugin'); $extension->set('client_id', 0); $extension->set('element', $element); $extension->set('folder', $folder); $extension->set('name', $manifest_details['name']); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $extension->set('params', '{}'); $results[] = $extension; } $folder_list = \JFolder::folders(JPATH_SITE . '/plugins/' . $folder); foreach ($folder_list as $plugin_folder) { $file_list = \JFolder::files(JPATH_SITE . '/plugins/' . $folder . '/' . $plugin_folder, '\.xml$'); foreach ($file_list as $file) { $manifest_details = Installer::parseXMLInstallFile( JPATH_SITE . '/plugins/' . $folder . '/' . $plugin_folder . '/' . $file ); $file = \JFile::stripExt($file); if ($file === 'example' || $manifest_details === false) { continue; } $element = empty($manifest_details['filename']) ? $file : $manifest_details['filename']; // Ignore example plugins $extension = Table::getInstance('extension'); $extension->set('type', 'plugin'); $extension->set('client_id', 0); $extension->set('element', $element); $extension->set('folder', $folder); $extension->set('name', $manifest_details['name']); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $extension->set('params', '{}'); $results[] = $extension; } } } return $results; } /** * Refreshes the extension table cache. * * @return boolean Result of operation, true if updated, false on failure. * * @since 3.1 */ public function refreshManifestCache() { /* * Plugins use the extensions table as their primary store * Similar to modules and templates, rather easy * If it's not in the extensions table we just add it */ $client = ApplicationHelper::getClientInfo($this->parent->extension->client_id); $manifestPath = $client->path . '/plugins/' . $this->parent->extension->folder . '/' . $this->parent->extension->element . '/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; if ($this->parent->extension->store()) { return true; } else { \JLog::add(\JText::_('JLIB_INSTALLER_ERROR_PLG_REFRESH_MANIFEST_CACHE'), \JLog::WARNING, 'jerror'); return false; } } } PK $r!]�:�{ Fopen.phpnu &1i� PK $r!]@�E.g g A AbstractAdapter.phpnu &1i� PK $r!]a��b b � Curl.phpnu &1i� PK �t!]`�ߍ� � �9 AdapterInstance.phpnu &1i� PK �t!] ��� � ^? Adapter.phpnu &1i� PK b�!]�g�5 5 ?Q LibraryAdapter.phpnu &1i� PK b�!]o,�Dg g �� LanguageAdapter.phpnu &1i� PK b�!]r^ɠQ Q � ModuleAdapter.phpnu &1i� PK b�!].h�jN N D? PackageAdapter.phpnu &1i� PK b�!] �� h@ h@ �� FileAdapter.phpnu &1i� PK b�!]^T��S� S� /� ComponentAdapter.phpnu &1i� PK b�!]��M��C �C �e TemplateAdapter.phpnu &1i� PK b�!]��LM M �� PluginAdapter.phpnu &1i� PK �
| ver. 1.4 |
Github
|
.
| PHP 8.1.34 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка