Файловый менеджер - Редактировать - /home/wuectly/www/03cbe/Update.tar
Назад
Collection.php 0000604 00000023604 15245530253 0007355 0 ustar 00 <?php /** * @package FOF * @copyright Copyright (c)2010-2020 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 2, or later */ namespace FOF30\Update; defined('_JEXEC') || die; use Exception; use FOF30\Container\Container; use FOF30\Download\Download; use SimpleXMLElement; class Collection { /** * Reads a "collection" XML update source and returns the complete tree of categories * and extensions applicable for platform version $jVersion * * @param string $url The collection XML update source URL to read from * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION * * @return array A list of update sources applicable to $jVersion */ public function getAllUpdates($url, $jVersion = null) { // Get the target platform if (is_null($jVersion)) { $jVersion = JVERSION; } // Initialise return value $updates = [ 'metadata' => [ 'name' => '', 'description' => '', ], 'categories' => [], 'extensions' => [], ]; // Download and parse the XML file $container = Container::getInstance('com_foobar'); $downloader = new Download($container); $xmlSource = $downloader->getFromURL($url); try { $xml = new SimpleXMLElement($xmlSource, LIBXML_NONET); } catch (Exception $e) { return $updates; } // Sanity check if (($xml->getName() != 'extensionset')) { unset($xml); return $updates; } // Initialise return value with the stream metadata (name, description) $rootAttributes = $xml->attributes(); foreach ($rootAttributes as $k => $v) { $updates['metadata'][$k] = (string) $v; } // Initialise the raw list of updates $rawUpdates = [ 'categories' => [], 'extensions' => [], ]; // Segregate the raw list to a hierarchy of extension and category entries /** @var SimpleXMLElement $extension */ foreach ($xml->children() as $extension) { switch ($extension->getName()) { case 'category': // These are the parameters we expect in a category $params = [ 'name' => '', 'description' => '', 'category' => '', 'ref' => '', 'targetplatformversion' => $jVersion, ]; // These are the attributes of the element $attributes = $extension->attributes(); // Merge them all foreach ($attributes as $k => $v) { $params[$k] = (string) $v; } // We can't have a category with an empty category name if (empty($params['category'])) { continue; } // We can't have a category with an empty ref if (empty($params['ref'])) { continue; } if (empty($params['description'])) { $params['description'] = $params['category']; } if (!array_key_exists($params['category'], $rawUpdates['categories'])) { $rawUpdates['categories'][$params['category']] = []; } $rawUpdates['categories'][$params['category']][] = $params; break; case 'extension': // These are the parameters we expect in a category $params = [ 'element' => '', 'type' => '', 'version' => '', 'name' => '', 'detailsurl' => '', 'targetplatformversion' => $jVersion, ]; // These are the attributes of the element $attributes = $extension->attributes(); // Merge them all foreach ($attributes as $k => $v) { $params[$k] = (string) $v; } // We can't have an extension with an empty element if (empty($params['element'])) { continue; } // We can't have an extension with an empty type if (empty($params['type'])) { continue; } // We can't have an extension with an empty version if (empty($params['version'])) { continue; } if (empty($params['name'])) { $params['name'] = $params['element'] . ' ' . $params['version']; } if (!array_key_exists($params['type'], $rawUpdates['extensions'])) { $rawUpdates['extensions'][$params['type']] = []; } if (!array_key_exists($params['element'], $rawUpdates['extensions'][$params['type']])) { $rawUpdates['extensions'][$params['type']][$params['element']] = []; } $rawUpdates['extensions'][$params['type']][$params['element']][] = $params; break; default: break; } } unset($xml); if (!empty($rawUpdates['categories'])) { foreach ($rawUpdates['categories'] as $category => $entries) { $update = $this->filterListByPlatform($entries, $jVersion); $updates['categories'][$category] = $update; } } if (!empty($rawUpdates['extensions'])) { foreach ($rawUpdates['extensions'] as $type => $extensions) { $updates['extensions'][$type] = []; if (!empty($extensions)) { foreach ($extensions as $element => $entries) { $update = $this->filterListByPlatform($entries, $jVersion); $updates['extensions'][$type][$element] = $update; } } } } return $updates; } /** * Returns only the category definitions of a collection * * @param string $url The URL of the collection update source * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION * * @return array An array of category update definitions */ public function getCategories($url, $jVersion = null) { $allUpdates = $this->getAllUpdates($url, $jVersion); return $allUpdates['categories']; } /** * Returns the update source for a specific category * * @param string $url The URL of the collection update source * @param string $category The category name you want to get the update source URL of * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION * * @return string|null The update stream URL, or null if it's not found */ public function getCategoryUpdateSource($url, $category, $jVersion = null) { $allUpdates = $this->getAllUpdates($url, $jVersion); if (array_key_exists($category, $allUpdates['categories'])) { return $allUpdates['categories'][$category]['ref']; } else { return null; } } /** * Get a list of updates for extensions only, optionally of a specific type * * @param string $url The URL of the collection update source * @param string $type The extension type you want to get the update source URL of, empty to get all * extension types * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION * * @return array|null An array of extension update definitions or null if none is found */ public function getExtensions($url, $type = null, $jVersion = null) { $allUpdates = $this->getAllUpdates($url, $jVersion); if (empty($type)) { return $allUpdates['extensions']; } elseif (array_key_exists($type, $allUpdates['extensions'])) { return $allUpdates['extensions'][$type]; } else { return null; } } /** * Get the update source URL for a specific extension, based on the type and element, e.g. * type=file and element=joomla is Joomla! itself. * * @param string $url The URL of the collection update source * @param string $type The extension type you want to get the update source URL of * @param string $element The extension element you want to get the update source URL of * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION * * @return string|null The update source URL or null if the extension is not found */ public function getExtensionUpdateSource($url, $type, $element, $jVersion = null) { $allUpdates = $this->getExtensions($url, $type, $jVersion); if (empty($allUpdates)) { return null; } elseif (array_key_exists($element, $allUpdates)) { return $allUpdates[$element]['detailsurl']; } else { return null; } } /** * Filters a list of updates, returning only those available for the * specified platform version $jVersion * * @param array $updates An array containing update definitions (categories or extensions) * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION * * @return array|null The update definition that is compatible, or null if none is compatible */ private function filterListByPlatform($updates, $jVersion = null) { // Get the target platform if (is_null($jVersion)) { $jVersion = JVERSION; } $versionParts = explode('.', $jVersion, 4); $platformVersionMajor = $versionParts[0]; $platformVersionMinor = (count($versionParts) > 1) ? $platformVersionMajor . '.' . $versionParts[1] : $platformVersionMajor; $platformVersionNormal = (count($versionParts) > 2) ? $platformVersionMinor . '.' . $versionParts[2] : $platformVersionMinor; $platformVersionFull = (count($versionParts) > 3) ? $platformVersionNormal . '.' . $versionParts[3] : $platformVersionNormal; $pickedExtension = null; $pickedSpecificity = -1; foreach ($updates as $update) { // Test the target platform $targetPlatform = (string) $update['targetplatformversion']; if ($targetPlatform === $platformVersionFull) { $pickedExtension = $update; $pickedSpecificity = 4; } elseif (($targetPlatform === $platformVersionNormal) && ($pickedSpecificity <= 3)) { $pickedExtension = $update; $pickedSpecificity = 3; } elseif (($targetPlatform === $platformVersionMinor) && ($pickedSpecificity <= 2)) { $pickedExtension = $update; $pickedSpecificity = 2; } elseif (($targetPlatform === $platformVersionMajor) && ($pickedSpecificity <= 1)) { $pickedExtension = $update; $pickedSpecificity = 1; } } return $pickedExtension; } } Extension.php 0000604 00000006654 15245530253 0007244 0 ustar 00 <?php /** * @package FOF * @copyright Copyright (c)2010-2020 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 2, or later */ namespace FOF30\Update; defined('_JEXEC') || die; use Exception; use FOF30\Container\Container; use FOF30\Download\Download; use SimpleXMLElement; /** * A helper class to read and parse "extension" update XML files over the web */ class Extension { /** * Reads an "extension" XML update source and returns all listed update entries. * * If you have a "collection" XML update source you should do something like this: * $collection = new F0FUtilsUpdateCollection(); * $extensionUpdateURL = $collection->getExtensionUpdateSource($url, 'component', 'com_foobar', JVERSION); * $extension = new F0FUtilsUpdateExtension(); * $updates = $extension->getUpdatesFromExtension($extensionUpdateURL); * * @param string $url The extension XML update source URL to read from * * @return array An array of update entries */ public function getUpdatesFromExtension($url) { // Initialise $ret = []; // Get and parse the XML source $container = Container::getInstance('com_FOOBAR'); $downloader = new Download($container); $xmlSource = $downloader->getFromURL($url); try { $xml = new SimpleXMLElement($xmlSource, LIBXML_NONET); } catch (Exception $e) { return $ret; } // Sanity check if (($xml->getName() != 'updates')) { unset($xml); return $ret; } // Let's populate the list of updates /** @var SimpleXMLElement $update */ foreach ($xml->children() as $update) { // Sanity check if ($update->getName() != 'update') { continue; } $entry = [ 'infourl' => ['title' => '', 'url' => ''], 'downloads' => [], 'tags' => [], 'targetplatform' => [], ]; $properties = get_object_vars($update); foreach ($properties as $nodeName => $nodeContent) { switch ($nodeName) { default: $entry[$nodeName] = $nodeContent; break; case 'infourl': case 'downloads': case 'tags': case 'targetplatform': break; } } $infourlNode = $update->xpath('infourl'); $entry['infourl']['title'] = (string) $infourlNode[0]['title']; $entry['infourl']['url'] = (string) $infourlNode[0]; $downloadNodes = $update->xpath('downloads/downloadurl'); foreach ($downloadNodes as $downloadNode) { $entry['downloads'][] = [ 'type' => (string) $downloadNode['type'], 'format' => (string) $downloadNode['format'], 'url' => (string) $downloadNode, ]; } $tagNodes = $update->xpath('tags/tag'); foreach ($tagNodes as $tagNode) { $entry['tags'][] = (string) $tagNode; } /** @var SimpleXMLElement[] $targetPlatformNode */ $targetPlatformNode = $update->xpath('targetplatform'); $entry['targetplatform']['name'] = (string) $targetPlatformNode[0]['name']; $entry['targetplatform']['version'] = (string) $targetPlatformNode[0]['version']; $client = $targetPlatformNode[0]->xpath('client'); $entry['targetplatform']['client'] = (is_array($client) && count($client)) ? (string) $client[0] : ''; $folder = $targetPlatformNode[0]->xpath('folder'); $entry['targetplatform']['folder'] = is_array($folder) && count($folder) ? (string) $folder[0] : ''; $ret[] = $entry; } unset($xml); return $ret; } } Update.php 0000604 00000061073 15245530253 0006506 0 ustar 00 <?php /** * @package FOF * @copyright Copyright (c)2010-2020 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 2, or later */ namespace FOF30\Update; defined('_JEXEC') || die; use Exception; use FOF30\Container\Container; use FOF30\Model\Model; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Updater\Updater; use SimpleXMLElement; /** * A helper Model to interact with Joomla!'s extensions update feature */ class Update extends Model { /** @var Updater The Joomla! updater object */ protected $updater = null; /** @var int The extension_id of this component */ protected $extension_id = 0; /** @var string The currently installed version, as reported by the #__extensions table */ protected $version = 'dev'; /** @var string The name of the component e.g. com_something */ protected $component = 'com_foobar'; /** @var string The URL to the component's update XML stream */ protected $updateSite = null; /** @var string The name to the component's update site (description of the update XML stream) */ protected $updateSiteName = null; /** @var string The extra query to append to (commercial) components' download URLs */ protected $extraQuery = null; /** @var string The component Options key which stores a copy of the Download ID */ protected $paramsKey = 'update_dlid'; /** * Public constructor. Initialises the protected members as well. Useful $config keys: * update_component The component name, e.g. com_foobar * update_version The default version if the manifest cache is unreadable * update_site The URL to the component's update XML stream * update_extraquery The extra query to append to (commercial) components' download URLs * update_sitename The update site's name (description) * update_paramskey The component parameters key which holds the license key in J3 (and a copy of it in J4) * * @param array $config */ public function __construct($config = []) { $container = Container::getInstance('com_FOOBAR'); if (isset($config['update_container']) && is_object($config['update_container']) && ($config['update_container'] instanceof Container)) { $container = $config['update_container']; } parent::__construct($container); // Get an instance of the updater class $this->updater = Updater::getInstance(); // Get the component name if (isset($config['update_component'])) { $this->component = $config['update_component']; } else { $this->component = $this->input->getCmd('option', ''); } // Get the component version if (isset($config['update_version'])) { $this->version = $config['update_version']; } // Get the update site if (isset($config['update_site'])) { $this->updateSite = $config['update_site']; } // Get the extra query if (isset($config['update_extraquery'])) { $this->extraQuery = $config['update_extraquery']; } // Get the extra query if (isset($config['update_sitename'])) { $this->updateSiteName = $config['update_sitename']; } // Get the extra query if (isset($config['update_paramskey'])) { $this->paramsKey = $config['update_paramskey']; } // Get the extension type $extension = $this->getExtensionObject(); if (is_object($extension)) { $this->extension_id = $extension->extension_id; if (empty($this->version) || ($this->version == 'dev')) { $data = json_decode($extension->manifest_cache, true); if (isset($data['version'])) { $this->version = $data['version']; } } } } /** * Gets the license key for a paid extension. * * On Joomla! 3 or when $forceLegacy is true we look in the component Options. * * On Joomla! 4 we use the information in the dlid element of the extension's XML manifest to parse the extra_query * fields of all configured update sites of the extension. This is the same thing Joomla does when it tries to * determine the license key of our extension when installing updates. If the extension is missing, it has no * associated update sites, the update sites are missing / rebuilt / disassociated from the extension or the * extra_query of all update site records is empty we parse the $extraQuery set in the constructor, if any. Also * note that on Joomla 4 mode if the extension does not exist, does not have a manifest or does not have a valid * dlid element in its manifest we will end up returning an empty string, just like Joomla! itself would have done * when installing updates. * * @param bool $forceLegacy Should I always retrieve the legacy license key, even in J4? * * @return string */ public function getLicenseKey($forceLegacy = false) { $legacyParamsKey = $this->getLegacyParamsKey(); // Joomla 3 (Legacy): Download ID stored in the component options if ($forceLegacy || !version_compare(JVERSION, '3.999.999', 'gt')) { return $this->container->params->get($legacyParamsKey, ''); } // Joomla! 4. We need to parse the extra_query of the update sites to get the correct Download ID. $updateSites = $this->getUpdateSites(); $extra_query = array_reduce($updateSites, function ($extra_query, $updateSite) { if (!empty($extra_query)) { return $extra_query; } return $updateSite['extra_query']; }, ''); // Fall back to legacy extra query if (empty($extra_query)) { $extra_query = $this->extraQuery; } // Return the parsed results. return $this->getLicenseKeyFromExtraQuery($extra_query); } /** * Get the contents of all the update sites of the configured extension * * @return array */ public function getUpdateSites() { $updateSiteIDs = $this->getUpdateSiteIds(); $db = $this->container->db; $query = $db->getQuery(true) ->select('*') ->from($db->qn('#__update_sites')) ->where($db->qn('update_site_id') . ' IN (' . implode(', ', $updateSiteIDs) . ')'); try { $db->setQuery($query); $ret = $db->loadAssocList('update_site_id'); } catch (Exception $e) { $ret = null; } return empty($ret) ? [] : $ret; } public function setLicenseKey($licenseKey) { $legacyParamsKey = $this->getLegacyParamsKey(); // Sanitize and validate the license key. If it's not valid we set an empty license key. $licenseKey = $this->sanitizeLicenseKey($licenseKey); if (!$this->isValidLicenseKey($licenseKey)) { $licenseKey = ''; } // Update $this->extraQuery. $this->extraQuery = $this->getExtraQueryString($licenseKey); // Save the license key in the component options ($legacyParamsKey) $this->container->params->set($legacyParamsKey, $licenseKey); $this->container->params->save(); // Apply the new extra_query to the update site $this->refreshUpdateSite(); } /** * Copies a Joomla 3 license key from the Options storage to Joomla 4 download key storage (the extra_query column * of the #__update_sites table). * * This method does nothing on Joomla 3. * * @return void */ public function upgradeLicenseKey() { // Only applies to Joomla! 4 if (!version_compare(JVERSION, '3.999.999', 'gt')) { return; } // Make sure we DO have a legacy license key $legacyKey = $this->getLicenseKey(true); if (empty($legacyKey)) { return; } // Make sure we DO NOT have a J4 key. If we do, the J4 key wins and gets backported to legacy storage. $licenseKey = $this->getLicenseKey(false); if (!empty($licenseKey)) { $this->backportLicenseKey(); return; } // Save the legacy key as non-legacy. This updates the #__update_sites record, applying the license key. $this->setLicenseKey($legacyKey); } /** * Copies a Joomla 4 license key from the download key storage (the extra_query column of the #__update_sites table) * to the legacy Options storage. * * This method does nothing on Joomla 3. * * @return void */ public function backportLicenseKey() { $legacyParamsKey = $this->getLegacyParamsKey(); // Only applies to Joomla! 4 if (!version_compare(JVERSION, '3.999.999', 'gt')) { return; } // Make sure we DO have a J4 key $licenseKey = $this->getLicenseKey(false); if (empty($licenseKey)) { return; } // Make sure that the legacy key is NOT the same as the J4 key $legacyKey = $this->getLicenseKey(true); if ($legacyKey == $licenseKey) { return; } // Save the license key to the legacy storage (component options) $this->container->params->set($legacyParamsKey, $licenseKey); $this->container->params->save(); } /** * Get an extra query string based on the dlid element of the XML manifest file of the extension. * * If the extension does not exist, the manifest does not exist or it does not have a dlid element we fall back to * the legacy implementation of extra_query (getExtraQueryStringLegacy) * * @param string $licenseKey * * @return string */ public function getExtraQueryString($licenseKey) { // Make sure the (sanitized) license key is valid. Otherwise we return an empty string. $licenseKey = $this->sanitizeLicenseKey($licenseKey); if (!$this->isValidLicenseKey($licenseKey)) { return ''; } // Get a fallback extra query using the legacy method $fallbackExtraQuery = $this->getExtraQueryStringLegacy($licenseKey); // Get the extension XML manifest. If the extension or the manifest don't exist use the fallback extra_query. $extension = $this->getExtensionObject(); if (!$extension) { return $fallbackExtraQuery; } $installXmlFile = $this->getManifestXML( $extension->element, $extension->type, (int) $extension->client_id, $extension->folder ); if (!$installXmlFile) { return $fallbackExtraQuery; } // If the manifest does not have the dlid element return the fallback extra_query. if (!isset($installXmlFile->dlid)) { return $fallbackExtraQuery; } $prefix = (string) $installXmlFile->dlid['prefix']; $suffix = (string) $installXmlFile->dlid['suffix']; return $prefix . $this->sanitizeLicenseKey($licenseKey) . $suffix; } /** * Retrieves the update information of the component, returning an array with the following keys: * * hasUpdate True if an update is available * version The version of the available update * infoURL The URL to the download page of the update * * @param bool $force Set to true if you want to forcibly reload the update information * * @return array See the method description for more information */ public function getUpdates($force = false) { $db = $this->container->db; // Default response (no update) $updateResponse = [ 'hasUpdate' => false, 'version' => '', 'infoURL' => '', ]; if (empty($this->extension_id)) { return $updateResponse; } // If we had to update the version number stored in the database then we should force reload the updates if ($this->updatedCachedVersionNumber()) { $force = true; } // If we are forcing the reload, set the last_check_timestamp to 0 // and remove cached component update info in order to force a reload if ($force) { // Find the update site IDs $updateSiteIds = $this->getUpdateSiteIds(); if (empty($updateSiteIds)) { return $updateResponse; } // Set the last_check_timestamp to 0 $query = $db->getQuery(true) ->update($db->qn('#__update_sites')) ->set($db->qn('last_check_timestamp') . ' = ' . $db->q('0')) ->where($db->qn('update_site_id') . ' IN (' . implode(', ', $updateSiteIds) . ')'); $db->setQuery($query); $db->execute(); // Remove cached component update info from #__updates $query = $db->getQuery(true) ->delete($db->qn('#__updates')) ->where($db->qn('update_site_id') . ' IN (' . implode(', ', $updateSiteIds) . ')'); $db->setQuery($query); $db->execute(); } // Use the update cache timeout specified in com_installer $comInstallerParams = ComponentHelper::getParams('com_installer', false); $timeout = 3600 * $comInstallerParams->get('cachetimeout', '6'); // Load any updates from the network into the #__updates table $this->updater->findUpdates($this->extension_id, $timeout); // Get the update record from the database $query = $db->getQuery(true) ->select('*') ->from($db->qn('#__updates')) ->where($db->qn('extension_id') . ' = ' . $db->q($this->extension_id)); $db->setQuery($query); $updateRecord = $db->loadObject(); // If we have an update record in the database return the information found there if (is_object($updateRecord)) { $updateResponse = [ 'hasUpdate' => true, 'version' => $updateRecord->version, 'infoURL' => $updateRecord->infourl, ]; } return $updateResponse; } /** * Gets the update site Ids for our extension. * * @return array An array of IDs */ public function getUpdateSiteIds() { $db = $this->container->db; $query = $db->getQuery(true) ->select($db->qn('update_site_id')) ->from($db->qn('#__update_sites_extensions')) ->where($db->qn('extension_id') . ' = ' . $db->q($this->extension_id)); $db->setQuery($query); try { $ret = $db->loadColumn(0); } catch (Exception $e) { $ret = null; } return is_array($ret) ? $ret : []; } /** * Get the currently installed version as reported by the #__extensions table * * @return string */ public function getVersion() { return $this->version; } /** * Override the currently installed version as reported by the #__extensions table * * @param string $version */ public function setVersion($version) { $this->version = $version; } /** * Refreshes the Joomla! update sites for this extension as needed * * @return void */ public function refreshUpdateSite() { if (empty($this->extension_id)) { return; } // Create the update site definition we want to store to the database $update_site = [ 'name' => $this->updateSiteName, 'type' => 'extension', 'location' => $this->updateSite, 'enabled' => 1, 'last_check_timestamp' => 0, 'extra_query' => $this->extraQuery, ]; // Get a reference to the db driver $db = $this->container->db; // Get the #__update_sites columns $columns = $db->getTableColumns('#__update_sites', true); if (version_compare(JVERSION, '3.0.0', 'lt') || !array_key_exists('extra_query', $columns)) { unset($update_site['extra_query']); } // Get the update sites for our extension $updateSiteIds = $this->getUpdateSiteIds(); if (empty($updateSiteIds)) { $updateSiteIds = []; } /** @var boolean $needNewUpdateSite Do I need to create a new update site? */ $needNewUpdateSite = true; /** @var int[] $deleteOldSites Old Site IDs to delete */ $deleteOldSites = []; // Loop through all update sites foreach ($updateSiteIds as $id) { $query = $db->getQuery(true) ->select('*') ->from($db->qn('#__update_sites')) ->where($db->qn('update_site_id') . ' = ' . $db->q($id)); $db->setQuery($query); $aSite = $db->loadObject(); if (empty($aSite)) { // Update site is now up-to-date, don't need to refresh it anymore. continue; } // We have an update site that looks like ours if ($needNewUpdateSite && ($aSite->name == $update_site['name']) && ($aSite->location == $update_site['location'])) { $needNewUpdateSite = false; $mustUpdate = false; // Is it enabled? If not, enable it. if (!$aSite->enabled) { $mustUpdate = true; $aSite->enabled = 1; } // Do we have the extra_query property (J 3.2+) and does it match? if (property_exists($aSite, 'extra_query') && isset($update_site['extra_query']) && ($aSite->extra_query != $update_site['extra_query'])) { $mustUpdate = true; $aSite->extra_query = $update_site['extra_query']; } // Update the update site if necessary if ($mustUpdate) { $db->updateObject('#__update_sites', $aSite, 'update_site_id', true); } continue; } // In any other case we need to delete this update site, it's obsolete $deleteOldSites[] = $aSite->update_site_id; } if (!empty($deleteOldSites)) { try { $obsoleteIDsQuoted = array_map([$db, 'quote'], $deleteOldSites); // Delete update sites $query = $db->getQuery(true) ->delete('#__update_sites') ->where($db->qn('update_site_id') . ' IN (' . implode(',', $obsoleteIDsQuoted) . ')'); $db->setQuery($query)->execute(); // Delete update sites to extension ID records $query = $db->getQuery(true) ->delete('#__update_sites_extensions') ->where($db->qn('update_site_id') . ' IN (' . implode(',', $obsoleteIDsQuoted) . ')'); $db->setQuery($query)->execute(); } catch (Exception $e) { // Do nothing on failure return; } } // Do we still need to create a new update site? if ($needNewUpdateSite) { // No update sites defined. Create a new one. $newSite = (object) $update_site; $db->insertObject('#__update_sites', $newSite); $id = $db->insertid(); $updateSiteExtension = (object) [ 'update_site_id' => $id, 'extension_id' => $this->extension_id, ]; $db->insertObject('#__update_sites_extensions', $updateSiteExtension); } } /** * Removes any update sites which go by the same name or the same location as our update site but do not match the * extension ID. */ public function removeObsoleteUpdateSites() { $db = $this->container->db; // Get update site IDs $updateSiteIDs = $this->getUpdateSiteIds(); // Find update sites where the name OR the location matches BUT they are not one of the update site IDs $query = $db->getQuery(true) ->select($db->qn('update_site_id')) ->from($db->qn('#__update_sites')) ->where( '((' . $db->qn('name') . ' = ' . $db->q($this->updateSiteName) . ') OR ' . '(' . $db->qn('location') . ' = ' . $db->q($this->updateSite) . '))' ); if (!empty($updateSiteIDs)) { $updateSitesQuoted = array_map([$db, 'quote'], $updateSiteIDs); $query->where($db->qn('update_site_id') . ' NOT IN (' . implode(',', $updateSitesQuoted) . ')'); } try { $ids = $db->setQuery($query)->loadColumn(); if (!empty($ids)) { $obsoleteIDsQuoted = array_map([$db, 'quote'], $ids); // Delete update sites $query = $db->getQuery(true) ->delete('#__update_sites') ->where($db->qn('update_site_id') . ' IN (' . implode(',', $obsoleteIDsQuoted) . ')'); $db->setQuery($query)->execute(); // Delete update sites to extension ID records $query = $db->getQuery(true) ->delete('#__update_sites_extensions') ->where($db->qn('update_site_id') . ' IN (' . implode(',', $obsoleteIDsQuoted) . ')'); $db->setQuery($query)->execute(); } } catch (Exception $e) { // Do nothing on failure return; } } /** * Makes sure that the version number cached in the #__extensions table is consistent with the version number set in * this model. * * @return bool True if we updated the version number cached in the #__extensions table. * * @since 3.1.2 */ public function updatedCachedVersionNumber() { $extension = $this->getExtensionObject(); if (!is_object($extension)) { return false; } $data = json_decode($extension->manifest_cache, true); $mustUpdate = true; if (isset($data['version'])) { $mustUpdate = $this->version != $data['version']; } if (!$mustUpdate) { return false; } // The cached version is wrong; let's update it $data['version'] = $this->version; $extension->manifest_cache = json_encode($data); $db = $this->container->db; return $db->updateObject('#__extensions', $extension, ['extension_id']); } /** * Returns an object with the #__extensions table record for the current extension. * * @return mixed */ public function getExtensionObject() { [$extensionPrefix, $extensionName] = explode('_', $this->component); switch ($extensionPrefix) { default: case 'com': $type = 'component'; $name = $this->component; break; case 'pkg': $type = 'package'; $name = $this->component; break; } // Find the extension ID $db = $this->container->db; $query = $db->getQuery(true) ->select('*') ->from($db->qn('#__extensions')) ->where($db->qn('type') . ' = ' . $db->q($type)) ->where($db->qn('element') . ' = ' . $db->q($name)); try { $db->setQuery($query); $extension = $db->loadObject(); } catch (Exception $e) { return null; } return $extension; } /** * Is the provided string a valid license key? * * YOU SHOULD OVERRIDE THIS METHOD. The default implementation checks for valid Download IDs in the format used by * Akeeba software. * * @param string $licenseKey * * @return bool */ public function isValidLicenseKey($licenseKey) { return preg_match('/^([0-9]{1,}:)?[0-9a-f]{32}$/i', $licenseKey) === 1; } /** * Sanitizes the license key. * * YOU SHOULD OVERRIDE THIS METHOD. The default implementation returns a lowercase string with all characters except * letters, numbers and colons removed. * * @param string $licenseKey * * @return string The sanitized license key */ public function sanitizeLicenseKey($licenseKey) { return strtolower(preg_replace("/[^a-zA-Z0-9:]/", "", $licenseKey)); } /** * Returns the component Options key which holds a copy of the license key * * @return string */ protected function getLegacyParamsKey() { if (!empty($this->paramsKey)) { return $this->paramsKey; } $this->paramsKey = 'update_dlid'; return $this->paramsKey; } /** * Extract the download ID from an extra_query based on the prefix and suffix information stored in the dlid element * of the extension's XML manifest file. * * @param string $extra_query * * @return string */ protected function getLicenseKeyFromExtraQuery($extra_query) { $extra_query = trim($extra_query); if (empty($extra_query)) { return ''; } // Get the extension XML manifest. If the extension or the manifest don't exist return an empty string. $extension = $this->getExtensionObject(); if (!$extension) { return ''; } $installXmlFile = $this->getManifestXML( $extension->element, $extension->type, (int) $extension->client_id, $extension->folder ); if (!$installXmlFile) { return ''; } // If the manifest does not have a dlid element return an empty string. if (!isset($installXmlFile->dlid)) { return ''; } // Naive parsing of the extra_query, the same way Joomla does. $prefix = (string) $installXmlFile->dlid['prefix']; $suffix = (string) $installXmlFile->dlid['suffix']; $licenseKey = substr($extra_query, strlen($prefix)); if ($licenseKey === false) { return ''; } if ($suffix) { $licenseKey = substr($licenseKey, 0, -strlen($suffix)); } return ($licenseKey === false) ? '' : $licenseKey; } /** * Get a legacy extra query string. Do NOT call this directly. Call getExtraQueryString() instead. * * YOU SHOULD OVERRIDE THIS METHOD. This returns dlid=SANITIZED_LICENSE_KEY which is what Akeeba Release System, * used to deliver all Akeeba extensions, expects. * * @param string $licenseKey The license key * * @return string The extra_query string to append to a downlaod URL to implement the license key */ protected function getExtraQueryStringLegacy($licenseKey) { if (empty($licenseKey) || !$this->isValidLicenseKey($licenseKey)) { return ''; } return 'dlid=' . $this->sanitizeLicenseKey($licenseKey); } /** * Get the manifest XML file of a given extension. * * @param string $element element of an extension * @param string $type type of an extension * @param integer $client_id client_id of an extension * @param string $folder folder of an extension * * @return SimpleXMLElement */ protected function getManifestXML($element, $type, $client_id = 1, $folder = null) { $path = $client_id ? JPATH_ADMINISTRATOR : JPATH_ROOT; switch ($type) { case 'component': $path .= '/components/' . $element . '/' . substr($element, 4) . '.xml'; break; case 'plugin': $path .= '/plugins/' . $folder . '/' . $element . '/' . $element . '.xml'; break; case 'module': $path .= '/modules/' . $element . '/' . $element . '.xml'; break; case 'template': $path .= '/templates/' . $element . '/templateDetails.xml'; break; case 'library': $path = JPATH_ADMINISTRATOR . '/manifests/libraries/' . $element . '.xml'; break; case 'file': $path = JPATH_ADMINISTRATOR . '/manifests/files/' . $element . '.xml'; break; case 'package': $path = JPATH_ADMINISTRATOR . '/manifests/packages/' . $element . '.xml'; } return simplexml_load_file($path); } } Joomla.php 0000604 00000031220 15245530253 0006474 0 ustar 00 <?php /** * @package FOF * @copyright Copyright (c)2010-2020 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 2, or later */ namespace FOF30\Update; defined('_JEXEC') || die; class Joomla extends Extension { /** * The source for LTS updates * * @var string */ protected static $lts_url = 'http://update.joomla.org/core/list.xml'; /** * The source for STS updates * * @var string */ protected static $sts_url = 'http://update.joomla.org/core/sts/list_sts.xml'; /** * The source for test release updates * * @var string */ protected static $test_url = 'http://update.joomla.org/core/test/list_test.xml'; /** * Reads a "collection" XML update source and picks the correct source URL * for the extension update source. * * @param string $url The collection XML update source URL to read from * @param string $jVersion Joomla! version to fetch updates for, or null to use JVERSION * * @return string The URL of the extension update source, or empty if no updates are provided / fetching failed */ public function getUpdateSourceFromCollection($url, $jVersion = null) { $provider = new Collection(); return $provider->getExtensionUpdateSource($url, 'file', 'joomla', $jVersion); } /** * Determines the properties of a version: STS/LTS, normal or testing * * @param string $jVersion The version number to check * @param string $currentVersion The current Joomla! version number * * @return array The properties analysis */ public function getVersionProperties($jVersion, $currentVersion = null) { // Initialise $ret = [ 'lts' => true, // Is this an LTS release? False means STS. 'current' => false, // Is this a release in the $currentVersion branch? 'upgrade' => 'none', // Upgrade relation of $jVersion to $currentVersion: 'none' (can't upgrade), 'lts' (next or current LTS), 'sts' (next or current STS) or 'current' (same release, no upgrade available) 'testing' => false, // Is this a testing (alpha, beta, RC) release? ]; // Get the current version if none is defined if (is_null($currentVersion)) { $currentVersion = JVERSION; } // Sanitise version numbers $sameVersion = $jVersion == $currentVersion; $jVersion = $this->sanitiseVersion($jVersion); $currentVersion = $this->sanitiseVersion($currentVersion); $sameVersion = $sameVersion || ($jVersion == $currentVersion); // Get the base version $baseVersion = substr($jVersion, 0, 3); // Get the minimum and maximum current version numbers $current_minimum = substr($currentVersion, 0, 3); $current_maximum = $current_minimum . '.9999'; // Initialise STS/LTS version numbers $sts_minimum = false; $sts_maximum = false; $lts_minimum = false; // Is it an LTS or STS release? switch ($baseVersion) { case '1.5': $ret['lts'] = true; break; case '1.6': $ret['lts'] = false; $sts_minimum = '1.7'; $sts_maximum = '1.7.999'; $lts_minimum = '2.5'; break; case '1.7': $ret['lts'] = false; $sts_minimum = false; $lts_minimum = '2.5'; break; case '2.5': $ret['lts'] = true; $sts_minimum = false; $lts_minimum = '2.5'; break; default: $majorVersion = (int) substr($jVersion, 0, 1); //$minorVersion = (int) substr($jVersion, 2, 1); $ret['lts'] = true; $sts_minimum = false; $lts_minimum = $majorVersion . '.0'; break; } // Is it a current release? if (version_compare($jVersion, $current_minimum, 'ge') && version_compare($jVersion, $current_maximum, 'le')) { $ret['current'] = true; } // Is this a testing release? $versionParts = explode('.', $jVersion); $lastVersionPart = array_pop($versionParts); if (in_array(substr($lastVersionPart, 0, 1), ['a', 'b'])) { $ret['testing'] = true; } elseif (substr($lastVersionPart, 0, 2) == 'rc') { $ret['testing'] = true; } elseif (substr($lastVersionPart, 0, 3) == 'dev') { $ret['testing'] = true; } // Find the upgrade relation of $jVersion to $currentVersion if (version_compare($jVersion, $currentVersion, 'eq')) { $ret['upgrade'] = 'current'; } elseif (($sts_minimum !== false) && version_compare($jVersion, $sts_minimum, 'ge') && version_compare($jVersion, $sts_maximum, 'le')) { $ret['upgrade'] = 'sts'; } elseif (($lts_minimum !== false) && version_compare($jVersion, $lts_minimum, 'ge')) { $ret['upgrade'] = 'lts'; } elseif ($baseVersion == $current_minimum) { $ret['upgrade'] = $ret['lts'] ? 'lts' : 'sts'; } else { $ret['upgrade'] = 'none'; } if ($sameVersion) { $ret['upgrade'] = 'none'; } return $ret; } /** * Filters a list of updates, making sure they apply to the specified CMS * release. * * @param array $updates A list of update records returned by the getUpdatesFromExtension method * @param string $jVersion The current Joomla! version number * * @return array A filtered list of updates. Each update record also includes version relevance information. */ public function filterApplicableUpdates($updates, $jVersion = null) { if (empty($jVersion)) { $jVersion = JVERSION; } $versionParts = explode('.', $jVersion, 4); $platformVersionMajor = $versionParts[0]; $platformVersionMinor = $platformVersionMajor . '.' . $versionParts[1]; //$platformVersionNormal = $platformVersionMinor . '.' . $versionParts[2]; //$platformVersionFull = (count($versionParts) > 3) ? $platformVersionNormal . '.' . $versionParts[3] : $platformVersionNormal; $ret = []; foreach ($updates as $update) { // Check each update for platform match if (strtolower($update['targetplatform']['name']) != 'joomla') { continue; } $targetPlatformVersion = $update['targetplatform']['version']; if (!preg_match('/' . $targetPlatformVersion . '/', $platformVersionMinor)) { continue; } // Get some information from the version number $updateVersion = $update['version']; $versionProperties = $this->getVersionProperties($updateVersion, $jVersion); if ($versionProperties['upgrade'] == 'none') { continue; } // The XML files are ill-maintained. Maybe we already have this update? if (!array_key_exists($updateVersion, $ret)) { $ret[$updateVersion] = array_merge($update, $versionProperties); } } return $ret; } /** * Joomla! has a lousy track record in naming its alpha, beta and release * candidate releases. The convention used seems to be "what the hell the * current package maintainer thinks looks better". This method tries to * figure out what was in the mind of the maintainer and translate the * funky version number to an actual PHP-format version string. * * @param string $version The whatever-format version number * * @return string A standard formatted version number */ public function sanitiseVersion($version) { $test = strtolower($version); $alphaQualifierPosition = strpos($test, 'alpha-'); $betaQualifierPosition = strpos($test, 'beta-'); $betaQualifierPosition2 = strpos($test, '-beta'); $rcQualifierPosition = strpos($test, 'rc-'); $rcQualifierPosition2 = strpos($test, '-rc'); $rcQualifierPosition3 = strpos($test, 'rc'); $devQualifiedPosition = strpos($test, 'dev'); if ($alphaQualifierPosition !== false) { $betaRevision = substr($test, $alphaQualifierPosition + 6); if (!$betaRevision) { $betaRevision = 1; } $test = substr($test, 0, $alphaQualifierPosition) . '.a' . $betaRevision; } elseif ($betaQualifierPosition !== false) { $betaRevision = substr($test, $betaQualifierPosition + 5); if (!$betaRevision) { $betaRevision = 1; } $test = substr($test, 0, $betaQualifierPosition) . '.b' . $betaRevision; } elseif ($betaQualifierPosition2 !== false) { $betaRevision = substr($test, $betaQualifierPosition2 + 5); if (!$betaRevision) { $betaRevision = 1; } $test = substr($test, 0, $betaQualifierPosition2) . '.b' . $betaRevision; } elseif ($rcQualifierPosition !== false) { $betaRevision = substr($test, $rcQualifierPosition + 5); if (!$betaRevision) { $betaRevision = 1; } $test = substr($test, 0, $rcQualifierPosition) . '.rc' . $betaRevision; } elseif ($rcQualifierPosition2 !== false) { $betaRevision = substr($test, $rcQualifierPosition2 + 3); if (!$betaRevision) { $betaRevision = 1; } $test = substr($test, 0, $rcQualifierPosition2) . '.rc' . $betaRevision; } elseif ($rcQualifierPosition3 !== false) { $betaRevision = substr($test, $rcQualifierPosition3 + 5); if (!$betaRevision) { $betaRevision = 1; } $test = substr($test, 0, $rcQualifierPosition3) . '.rc' . $betaRevision; } elseif ($devQualifiedPosition !== false) { $betaRevision = substr($test, $devQualifiedPosition + 6); if (!$betaRevision) { $betaRevision = ''; } $test = substr($test, 0, $devQualifiedPosition) . '.dev' . $betaRevision; } return $test; } /** * Reloads the list of all updates available for the specified Joomla! version * from the network. * * @param array $sources The enabled sources to look into * @param string $jVersion The Joomla! version we are checking updates for * * @return array A list of updates for the installed, current, lts and sts versions */ public function getUpdates($sources = [], $jVersion = null) { // Make sure we have a valid list of sources if (empty($sources) || !is_array($sources)) { $sources = []; } $defaultSources = ['lts' => true, 'sts' => true, 'test' => true, 'custom' => '']; $sources = array_merge($defaultSources, $sources); // Use the current JVERSION if none is specified if (empty($jVersion)) { $jVersion = JVERSION; } // Get the current branch' min/max versions $versionParts = explode('.', $jVersion, 4); $currentMinVersion = $versionParts[0] . '.' . $versionParts[1]; $currentMaxVersion = $versionParts[0] . '.' . $versionParts[1] . '.9999'; // Retrieve all updates $allUpdates = []; foreach ($sources as $source => $value) { if (($value === false) || empty($value)) { continue; } switch ($source) { default: case 'lts': $url = self::$lts_url; break; case 'sts': $url = self::$sts_url; break; case 'test': $url = self::$test_url; break; case 'custom': $url = $value; break; } $url = $this->getUpdateSourceFromCollection($url, $jVersion); if (!empty($url)) { $updates = $this->getUpdatesFromExtension($url); if (!empty($updates)) { $applicableUpdates = $this->filterApplicableUpdates($updates, $jVersion); if (!empty($applicableUpdates)) { $allUpdates = array_merge($allUpdates, $applicableUpdates); } } } } $ret = [ // Currently installed version (used to reinstall, if available) 'installed' => [ 'version' => '', 'package' => '', 'infourl' => '', ], // Current branch 'current' => [ 'version' => '', 'package' => '', 'infourl' => '', ], // Upgrade to STS release 'sts' => [ 'version' => '', 'package' => '', 'infourl' => '', ], // Upgrade to LTS release 'lts' => [ 'version' => '', 'package' => '', 'infourl' => '', ], // Upgrade to LTS release 'test' => [ 'version' => '', 'package' => '', 'infourl' => '', ], ]; foreach ($allUpdates as $update) { $sections = []; if ($update['upgrade'] == 'current') { $sections[0] = 'installed'; } elseif (version_compare($update['version'], $currentMinVersion, 'ge') && version_compare($update['version'], $currentMaxVersion, 'le')) { $sections[0] = 'current'; } else { $sections[0] = ''; } $sections[1] = $update['lts'] ? 'lts' : 'sts'; if ($update['testing']) { $sections = ['test']; } foreach ($sections as $section) { if (empty($section)) { continue; } $existingVersionForSection = $ret[$section]['version']; if (empty($existingVersionForSection)) { $existingVersionForSection = '0.0.0'; } if (version_compare($update['version'], $existingVersionForSection, 'ge')) { $ret[$section]['version'] = $update['version']; $ret[$section]['package'] = $update['downloads'][0]['url']; $ret[$section]['infourl'] = $update['infourl']['url']; } } } // Catch the case when the latest current branch version is the installed version (up to date site) if (empty($ret['current']['version']) && !empty($ret['installed']['version'])) { $ret['current'] = $ret['installed']; } return $ret; } }
| ver. 1.4 |
Github
|
.
| PHP 8.1.34 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка