File Manager

Current Directory: /home/astoriaah/www/administrator/components/com_sh404sef/helpers
Viewing File: /home/astoriaah/www/administrator/components/com_sh404sef/helpers/updates.php
<?php /** * sh404SEF - SEO extension for Joomla! * * @author Yannick Gaultier * @copyright (c) Yannick Gaultier - Weeblr llc - 2022 * @package sh404SEF * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL * @version 4.24.1.4308 * @date 2022-05-31 */ use Joomla\Registry\Registry; // Security check to ensure this file is being included by a parent file. if (!defined('_JEXEC')) { die('Direct Access to this location is not allowed.'); } class Sh404sefHelperUpdates { private static $_endPoint = 'https://u1.weeblr.com/public/direct/sh404sef/legacy'; private static $_configEndPoint = 'https://u1.weeblr.com/public/direct/sh404sef/config'; private static $_product = 'sh404sef'; private static $_updateFile = 'sh404sef_updates_j3.xml'; private static $_config = 'sh404sef_config_j3.xml'; private static $_devConfig = 'sh404sef_config_dev_j3.xml'; // store whether doing a forced update. Reason to store it // is to keep _doCheck() method w/o any parameters // as this would otherwise prevent caching from operating // normally private static $_forced = array(); /** * Obtain update information, as stored in cache * by checkForUpdates * */ public static function getUpdatesInfos($forced = false) { // store whether doing a forced check for updates self::$_forced['updates'] = $forced; // get cache object $cache = JFactory::getCache('sh404sef_updates'); $cache->setLifetime(1440); // cache result for 24 hours $cache->setCaching(1); // force caching on // empty cache if we are going to look for updates if ($forced) { // clean our cache $cache->clean('sh404sef_updates'); } $response = $cache->call(array('Sh404sefHelperUpdates', '_doCheck')); // find out whether we should update $response = self::_updateRequired($response); // return response, either dummy or from cache return $response; } /** * Obtain remote configuration info * */ public static function getRemoteConfig($forced = false) { static $storedResponse = false; if ($storedResponse === false || $forced) { // store whether doing a forced check for updates self::$_forced['rconfig'] = $forced; // get cache object $cache = JFactory::getCache('sh404sef_rconfig'); $cache->setLifetime(60); // cache result for an hour $cache->setCaching(1); // force caching on // empty cache if we are going to look for updates if ($forced) { // clean our cache $cache->clean('sh404sef_rconfig'); } $storedResponse = $cache->call(array('Sh404sefHelperUpdates', '_doRemoteConfig')); } // return response, either dummy or from cache return $storedResponse; } public static function _doCheck() { // if not set to auto check and not forced to do so // when user click on "check updates" button // we don't actually try to get updates info $sefConfig = Sh404sefFactory::getConfig(); // prepare a default response object $response = new stdClass(); $response->status = true; $response->statusMessage = JText::_('COM_SH404SEF_CLICK_TO_CHECK_UPDATES'); $response->current = 0; $response->note = ''; $response->noteHtml = ''; $response->changelogLink = ''; $response->minVersionToUpgrade = 0; $response->maxVersionToUpgrade = 0; $response->shouldUpdate = false; $response->excludes = array(); // check if allowed to auto check, w/o user clicking on button if (!$sefConfig->autoCheckNewVersion && empty(self::$_forced['updates'])) { return $response; } // get an http client $hClient = JHttpFactory::getHttp( new Registry( array( 'follow_location' => true ) ) ); // find where to call ... $remoteConfig = self::getRemoteConfig($forced = false); // hardcoded default update server $defaultServers = array(array('url' => self::$_endPoint . '/' . self::$_updateFile)); // try to read from remote, central, configuration file $remoteServers = empty($remoteConfig->config['updateservers']) ? array() : $remoteConfig->config['updateservers']; // merge default and remote $servers = array_merge($remoteServers, $defaultServers); // check for urls in both defaults and remote $serverList = array(); foreach ($servers as $server) { if (!empty($server['url'])) { $serverList[] = JString::trim(($server['url'])); } } $serverList = array_unique($serverList); // now iterate over server list, until we find one that responds foreach ($serverList as $server) { $response->status = true; // request file content $rawResponse = null; try { $rawResponse = $hClient->get( $server, array(), 10 ); break; } catch (\Exception $e) { ShlSystem_Log::error('sh404sef', '%s::%d: %s', __METHOD__, __LINE__, 'Updates: fetching updates exception: ' . $e->getMessage()); $response->status = false; return $response; } // (un)set flag if we have a response if (empty($rawResponse)) { $response->status = false; $msg = 'unknown code'; $response->statusMessage = JText::sprintf('COM_SH404SEF_COULD_NOT_CHECK_FOR_NEW_VERSION', $msg); } else if (!is_object($rawResponse) || empty($rawResponse->code)) { $response->status = false; $msg = isset($rawResponse->code) ? $rawResponse->code : '-1'; $response->statusMessage = JText::sprintf('COM_SH404SEF_COULD_NOT_CHECK_FOR_NEW_VERSION', $msg); } else { // communication was fine, check the file type $type = wbArrayGet( $rawResponse->headers, 'Content-type' ); if (strtolower($type) != 'text/xml' && strtolower($type) != 'application/xml') { $response->status = false; $response->statusMessage = JText::sprintf('COM_SH404SEF_COULD_NOT_CHECK_FOR_NEW_VERSION', $rawResponse->code); } } // if there was a valid response, break out of // loop over available update servers if ($response->status) { break; } } // if we were not able to contact any update server // return this if (!$response->status) { return $response; } try { // get an xml object and parse the response $xml = new SimpleXMLElement($rawResponse->body); // into our response object // first version of version check used an xml file that could only hold one // version data set. So we only iterate over the "update" group if it exists if (empty($xml->update)) { $response = self::_readUpdateInformation($xml, $response); } else { foreach ($xml->update as $updateRecord) { $product = (string) $updateRecord->product[0]; // only use if this update record is for us if (strtolower($product) == strtolower(self::$_product)) { $response = self::_readUpdateInformation($updateRecord, $response); // find if user should update $response = self::_updateRequired($response); // if found an update, break out if ($response->shouldUpdate) { break; } } } } } catch (\Exception $e) { } // check if this is a valid information file return $response; } protected static function _readUpdateInformation($updateRecord, $response) { $response->current = (string) $updateRecord->current[0]; $response->note = (string) $updateRecord->note[0]; $response->noteHtml = (string) $updateRecord->noteHtml[0]; $response->changelogLink = (string) $updateRecord->changelogLink[0]; $response->downloadLink = (string) $updateRecord->downloadLink[0]; $response->minVersionToUpgrade = (string) $updateRecord->minVersionToUpgrade[0]; $response->maxVersionToUpgrade = (string) $updateRecord->maxVersionToUpgrade[0]; $rawExcludes = $updateRecord->exclude; $response->excludes = array(); if (!empty($rawExcludes)) { foreach ($rawExcludes as $exclude) { $response->excludes[] = (string) $exclude; } } return $response; } public static function _doRemoteConfig() { // if not set to auto check and not forced to do so // when user click on "check updates" button // we don't actually try to get updates info $sefConfig = Sh404sefFactory::getConfig(); // prepare a default response object $response = new stdClass(); $response->status = true; $response->config = array(); // check if allowed to read central configuration file if (!$sefConfig->canReadRemoteConfig) { return $response; } // get an http client $hClient = JHttpFactory::getHttp( new Registry( array( 'follow_location' => true ) ) ); // request file content $rawResponse = null; try { $rawResponse = $hClient->get( self::$_configEndPoint . '/' . self::$_config, array(), 5 ); } catch (\Exception $e) { ShlSystem_Log::error('sh404sef', '%s::%d: %s', __METHOD__, __LINE__, 'Remote config: fetching config exception: ' . $e->getMessage()); $response->status = false; return $response; } // return if error if (empty($rawResponse)) { $response->status = false; return $response; } if (!is_object($rawResponse) || empty($rawResponse->code)) { $response->status = false; return $response; } // check the file $type = wbArrayGet( $rawResponse->headers, 'Content-type' ); if (strtolower($type) != 'text/xml' && strtolower($type) != 'application/xml') { $response->status = false; return $response; } // should be OK then $response->status = true; // get an xml object and parse the response $rawConfig = simplexml_load_string( $rawResponse->body ); // into our response object $response->config = array(); if (!empty($rawConfig)) { foreach ($rawConfig->config as $configName => $configElement) { foreach ($configElement as $configKey => $values) { if (is_string($values)) { $response->config[$configKey] = $values; } else { $counter = 0; foreach ($values as $arrayName => $arrayValues) { $children = $arrayValues->children(); $attr = (string) $arrayValues->attributes(); $id = empty($attr) ? $counter : $attr; $count = count($children); if ($count > 0) { foreach ($arrayValues as $key => $value) { $response->config[$configKey][$id][$key] = (string) $value; } } else { $response->config[$configKey][] = (string) $arrayValues; } $counter++; } } } } } // check if this is a valid information file return $response; } /** * Use response object from request to update info server * to find if an update is required * * @param object $response */ private static function _updateRequired($response) { // get configuration $sefConfig = Sh404sefFactory::getConfig(); // compare versions $response->shouldUpdate = version_compare($sefConfig->version, $response->current, '<'); $response->shouldUpdate = $response->shouldUpdate && version_compare($sefConfig->version, $response->minVersionToUpgrade, 'ge'); $response->shouldUpdate = $response->shouldUpdate && (empty($response->maxVersionToUpgrade) || version_compare($sefConfig->version, $response->maxVersionToUpgrade, '<')); if ($response->shouldUpdate) { // check specific versions exclusion list $response->shouldUpdate = $response->shouldUpdate && !in_array($sefConfig->version, $response->excludes); } // build status message based on result of should update calculation $newVersionText = version_compare(JVERSION, '3.0.0', 'ge') ? 'COM_SH404SEF_NEW_VERSION_AVAILABLE_NO_HTML' : 'COM_SH404SEF_NEW_VERSION_AVAILABLE'; $response->statusMessage = $response->shouldUpdate ? JText::sprintf($newVersionText) : (JText::sprintf('COM_SH404SEF_YOU_ARE_UP_TO_DATE')); // return whatever we found return $response; } }