+
+warnings)) : ?>
+
+
+
+
diff --git a/administrator/components/com_joomlaupdate/views/default/view.html.php b/administrator/components/com_joomlaupdate/views/default/view.html.php
index 9401df1485e6f..0c8d41ea8e09f 100644
--- a/administrator/components/com_joomlaupdate/views/default/view.html.php
+++ b/administrator/components/com_joomlaupdate/views/default/view.html.php
@@ -16,6 +16,33 @@
*/
class JoomlaupdateViewDefault extends JViewLegacy
{
+ /**
+ * An array with the Joomla! update information.
+ *
+ * @var array
+ *
+ * @since 3.5.2
+ */
+ protected $updateInfo = null;
+
+ /**
+ * The form field for the extraction select
+ *
+ * @var string
+ *
+ * @since 3.5.2
+ */
+ protected $methodSelect = null;
+
+ /**
+ * The form field for the upload select
+ *
+ * @var string
+ *
+ * @since 3.5.2
+ */
+ protected $methodSelectUpload = null;
+
/**
* Renders the view
*
@@ -31,13 +58,17 @@ public function display($tpl = null)
$this->state = $this->get('State');
// Load useful classes.
+ /** @var JoomlaupdateModelDefault $model */
$model = $this->getModel();
$this->loadHelper('select');
// Assign view variables.
- $ftp = $model->getFTPOptions();
- $this->assign('updateInfo', $model->getUpdateInformation());
- $this->assign('methodSelect', JoomlaupdateHelperSelect::getMethods($ftp['enabled']));
+ $ftp = $model->getFTPOptions();
+ $defaultMethod = $ftp['enabled'] ? 'hybrid' : 'direct';
+
+ $this->updateInfo = $model->getUpdateInformation();
+ $this->methodSelect = JoomlaupdateHelperSelect::getMethods($defaultMethod);
+ $this->methodSelectUpload = JoomlaupdateHelperSelect::getMethods($defaultMethod, 'method', 'upload_method');
// Set the toolbar information.
JToolbarHelper::title(JText::_('COM_JOOMLAUPDATE_OVERVIEW'), 'loop install');
@@ -51,8 +82,8 @@ public function display($tpl = null)
JToolbarHelper::preferences('com_joomlaupdate');
}
- JToolBarHelper::divider();
- JToolBarHelper::help('JHELP_COMPONENTS_JOOMLA_UPDATE');
+ JToolbarHelper::divider();
+ JToolbarHelper::help('JHELP_COMPONENTS_JOOMLA_UPDATE');
if (!is_null($this->updateInfo['object']))
{
@@ -60,6 +91,61 @@ public function display($tpl = null)
JFactory::getApplication()->enqueueMessage(JText::_('COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATE_NOTICE'), 'notice');
}
+ $this->ftpFieldsDisplay = $this->ftp['enabled'] ? '' : 'style = "display: none"';
+ $params = JComponentHelper::getParams('com_joomlaupdate');
+
+ switch ($params->get('updatesource', 'default'))
+ {
+ // "Minor & Patch Release for Current version AND Next Major Release".
+ case 'sts':
+ case 'next':
+ $this->langKey = 'COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_NEXT';
+ $this->updateSourceKey = JText::_('COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_NEXT');
+ break;
+
+ // "Testing"
+ case 'testing':
+ $this->langKey = 'COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_TESTING';
+ $this->updateSourceKey = JText::_('COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_TESTING');
+ break;
+
+ // "Custom"
+ case 'custom':
+ $this->langKey = 'COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_CUSTOM';
+ $this->updateSourceKey = JText::_('COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_CUSTOM');
+ break;
+
+ /**
+ * "Minor & Patch Release for Current version (recommended and default)".
+ * The commented "case" below are for documenting where 'default' and legacy options falls
+ * case 'default':
+ * case 'lts':
+ * case 'nochange':
+ */
+ default:
+ $this->langKey = 'COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_DEFAULT';
+ $this->updateSourceKey = JText::_('COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_DEFAULT');
+ }
+
+ $this->warnings = array();
+ /** @var InstallerModelWarnings $warningsModel */
+ $warningsModel = $this->getModel('warnings');
+
+ if (is_object($warningsModel) && $warningsModel instanceof JModelLegacy)
+ {
+ $language = JFactory::getLanguage();
+ $language->load('com_installer', JPATH_ADMINISTRATOR, 'en-GB', false, true);
+ $language->load('com_installer', JPATH_ADMINISTRATOR, null, true);
+
+ $this->warnings = $warningsModel->getItems();
+ }
+
+ // Only Super Users have access to the Update & Install for obvious security reasons
+ $this->showUploadAndUpdate = JFactory::getUser()->authorise('core.admin');
+
+ // Remove temporary files
+ $model->removePackageFiles();
+
// Render the view.
parent::display($tpl);
}
diff --git a/administrator/components/com_joomlaupdate/views/upload/tmpl/captive.php b/administrator/components/com_joomlaupdate/views/upload/tmpl/captive.php
new file mode 100644
index 0000000000000..0ae0824514e74
--- /dev/null
+++ b/administrator/components/com_joomlaupdate/views/upload/tmpl/captive.php
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+ get('sitename')); ?>
+
+
+
+
+
+
diff --git a/administrator/components/com_joomlaupdate/views/upload/view.html.php b/administrator/components/com_joomlaupdate/views/upload/view.html.php
new file mode 100644
index 0000000000000..b4b600ffd307a
--- /dev/null
+++ b/administrator/components/com_joomlaupdate/views/upload/view.html.php
@@ -0,0 +1,49 @@
+load('com_installer', JPATH_ADMINISTRATOR, 'en-GB', false, true);
+ $language->load('com_installer', JPATH_ADMINISTRATOR, null, true);
+
+ // Import com_login's model
+ if (!class_exists('LoginModelLogin'))
+ {
+ @include_once JPATH_ADMINISTRATOR . '/components/com_login/models/login.php';
+ }
+
+ // Render the view.
+ parent::display($tpl);
+ }
+}
diff --git a/administrator/language/en-GB/en-GB.com_joomlaupdate.ini b/administrator/language/en-GB/en-GB.com_joomlaupdate.ini
index e3a3c721e74b7..a36d1527058e0 100644
--- a/administrator/language/en-GB/en-GB.com_joomlaupdate.ini
+++ b/administrator/language/en-GB/en-GB.com_joomlaupdate.ini
@@ -12,42 +12,50 @@ COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_CUSTOM_ERROR="The custom URL field is empty
COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_DEFAULT="Default"
COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_DESC="The update channel Joomla will use to find out if there is an update available."
COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_LABEL="Update Channel"
-COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_NEXT="Joomla! Next"
+COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_NEXT="Joomla Next"
COM_JOOMLAUPDATE_CONFIG_UPDATESOURCE_TESTING="Testing"
-COM_JOOMLAUPDATE_CONFIGURATION="Joomla! Update: Options"
-COM_JOOMLAUPDATE_OVERVIEW="Joomla! Update"
+COM_JOOMLAUPDATE_CONFIGURATION="Joomla Update: Options"
+COM_JOOMLAUPDATE_OVERVIEW="Joomla Update"
COM_JOOMLAUPDATE_UPDATE_LOG_CLEANUP="Cleaning up after installation."
COM_JOOMLAUPDATE_UPDATE_LOG_COMPLETE="Update to version %s is complete."
COM_JOOMLAUPDATE_UPDATE_LOG_DELETE_FILES="Deleting removed files and folders."
COM_JOOMLAUPDATE_UPDATE_LOG_FILE="File %s successfully downloaded."
COM_JOOMLAUPDATE_UPDATE_LOG_FINALISE="Finalising installation."
-COM_JOOMLAUPDATE_UPDATE_LOG_START="Update started by user %2$s (%1$s). Old version is %3$s."
COM_JOOMLAUPDATE_UPDATE_LOG_INSTALL="Starting installation of new version."
+COM_JOOMLAUPDATE_UPDATE_LOG_START="Update started by user %2$s (%1$s). Old version is %3$s."
COM_JOOMLAUPDATE_UPDATE_LOG_URL="Downloading update file from %s."
COM_JOOMLAUPDATE_VIEW_COMPLETE_HEADING="Joomla Version Update Status"
COM_JOOMLAUPDATE_VIEW_COMPLETE_MESSAGE="Your site has been successfully updated. Your Joomla version is now %s."
COM_JOOMLAUPDATE_VIEW_DEFAULT_DOWNLOAD_IN_PROGRESS="Downloading update file. Please wait ..."
+COM_JOOMLAUPDATE_VIEW_DEFAULT_NO_DOWNLOAD_URL="We can't find a download URL"
+COM_JOOMLAUPDATE_VIEW_DEFAULT_NO_DOWNLOAD_URL_DESC="An update to Joomla %1$s was found, but it wasn't possible to fetch the download URL for that update. There are two possibilities why this happens: - Your host doesn't support the minimum requirements for Joomla %1$s and there is no alternative download for your configuration available. - There is a problem with Joomla Update Server.
Please try to download the update package from the official Joomla download page and use the Upload and Install tab."
COM_JOOMLAUPDATE_VIEW_DEFAULT_FTP_DIRECTORY="FTP Root"
COM_JOOMLAUPDATE_VIEW_DEFAULT_FTP_HOSTNAME="FTP Host"
COM_JOOMLAUPDATE_VIEW_DEFAULT_FTP_PASSWORD="FTP Password"
COM_JOOMLAUPDATE_VIEW_DEFAULT_FTP_PORT="FTP Port"
COM_JOOMLAUPDATE_VIEW_DEFAULT_FTP_USERNAME="FTP Username"
COM_JOOMLAUPDATE_VIEW_DEFAULT_INFOURL="Additional Information"
+COM_JOOMLAUPDATE_VIEW_DEFAULT_INSTALLAGAIN="Reinstall Joomla core files"
COM_JOOMLAUPDATE_VIEW_DEFAULT_INSTALLED="Installed Joomla version"
COM_JOOMLAUPDATE_VIEW_DEFAULT_INSTALLUPDATE="Install the Update"
COM_JOOMLAUPDATE_VIEW_DEFAULT_LATEST="Latest Joomla version"
COM_JOOMLAUPDATE_VIEW_DEFAULT_METHOD_DIRECT="Write files directly"
COM_JOOMLAUPDATE_VIEW_DEFAULT_METHOD_FTP="Write files using FTP"
+COM_JOOMLAUPDATE_VIEW_DEFAULT_METHOD_HYBRID="Hybrid (use FTP only if needed)"
COM_JOOMLAUPDATE_VIEW_DEFAULT_METHOD="Installation method"
COM_JOOMLAUPDATE_VIEW_DEFAULT_NOUPDATES="No updates available."
COM_JOOMLAUPDATE_VIEW_DEFAULT_NOUPDATESNOTICE="You already have the latest Joomla version, %s."
COM_JOOMLAUPDATE_VIEW_DEFAULT_PACKAGE="Update package URL"
-COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATEFOUND="A Joomla update was found."
+COM_JOOMLAUPDATE_VIEW_DEFAULT_PACKAGE_REINSTALL="Reinstall package URL"
+COM_JOOMLAUPDATE_VIEW_DEFAULT_TAB_ONLINE="Live Update"
+COM_JOOMLAUPDATE_VIEW_DEFAULT_TAB_UPLOAD="Upload & Update"
COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATE_NOTICE="Before you update Joomla, ensure that the installed extensions are available for the new Joomla version."
-COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_CUSTOM="You are on the "%s" update channel. This is not an official Joomla! update channel."
-COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_DEFAULT="You are on the "%s" update channel. Through this channel you'll receive notifications for all updates of the current Joomla! release (3.x)"
-COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_NEXT="You are on the "%s" update channel. Through this channel you'll receive notifications for all updates of the current Joomla! release (3.x) and you will also be notified when the future major release (4.x) will be available. Before upgrading to 4.x you'll need to assess its compatibility with your environment."
-COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_TESTING="You are on the "%s" update channel. This channel is designed for testing new releases and fixes in Joomla. It is only intended for JBS (Joomla! Bug Squad™) members and others within the Joomla community who are testing. Do not use this setting on a production site."
+COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATEFOUND="A Joomla update was found."
+COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_CUSTOM="You are on the "%s" update channel. This is not an official Joomla update channel."
+COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_DEFAULT="You are on the "%s" update channel. Through this channel you'll receive notifications for all updates of the current Joomla release (3.x)"
+COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_NEXT="You are on the "%s" update channel. Through this channel you'll receive notifications for all updates of the current Joomla release (3.x) and you will also be notified when the future major release (4.x) will be available. Before upgrading to 4.x you'll need to assess its compatibility with your environment."
+COM_JOOMLAUPDATE_VIEW_DEFAULT_UPDATES_INFO_TESTING="You are on the "%s" update channel. This channel is designed for testing new releases and fixes in Joomla. It is only intended for JBS (Joomla Bug Squad™) members and others within the Joomla community who are testing. Do not use this setting on a production site."
+COM_JOOMLAUPDATE_VIEW_DEFAULT_UPLOAD_INTRO="You can use this feature to update Joomla if your server is behind a firewall or otherwise unable to contact the update servers. First download the Joomla Upgrade Package in ZIP format from the official Joomla download page. Then use the fields below to upload and install it."
COM_JOOMLAUPDATE_VIEW_PROGRESS="Update progress"
COM_JOOMLAUPDATE_VIEW_UPDATE_BYTESEXTRACTED="Bytes extracted"
COM_JOOMLAUPDATE_VIEW_UPDATE_BYTESREAD="Bytes read"
@@ -55,4 +63,7 @@ COM_JOOMLAUPDATE_VIEW_UPDATE_DOWNLOADFAILED="Download of update package failed."
COM_JOOMLAUPDATE_VIEW_UPDATE_FILESEXTRACTED="Files extracted"
COM_JOOMLAUPDATE_VIEW_UPDATE_INPROGRESS="Updating your Joomla files. Please wait ..."
COM_JOOMLAUPDATE_VIEW_UPDATE_PERCENT="Percent complete"
+COM_JOOMLAUPDATE_VIEW_UPLOAD_CAPTIVE_INTRO_BODY="Make sure that the update file you have uploaded comes from the official Joomla download page. Afterwards, please confirm that you want to install it by re-entering the login information for your site "%s" below."
+COM_JOOMLAUPDATE_VIEW_UPLOAD_CAPTIVE_INTRO_HEAD="Are you sure you want to install the file you uploaded?"
+COM_JOOMLAUPDATE_VIEW_UPLOAD_PACKAGE_FILE="Joomla package file"
COM_JOOMLAUPDATE_XML_DESCRIPTION="Updates Joomla to the latest version with one click."
diff --git a/build.xml b/build.xml
index 8760b18d01e86..0fbf1c0272936 100644
--- a/build.xml
+++ b/build.xml
@@ -149,7 +149,14 @@
-
+
+
+
+
+
+
+
+
diff --git a/libraries/joomla/updater/updater.php b/libraries/joomla/updater/updater.php
index 7249d7684a6c5..3f2eb1078fd23 100644
--- a/libraries/joomla/updater/updater.php
+++ b/libraries/joomla/updater/updater.php
@@ -98,25 +98,116 @@ public static function getInstance()
}
/**
- * Finds an update for an extension
+ * Finds the update for an extension. Any discovered updates are stored in the #__updates table.
*
- * @param int|array $eid Extension Identifier or list of Extension Identifiers; if zero use all sites
- * @param integer $cacheTimeout How many seconds to cache update information; if zero, force reload the update information
- * @param integer $minimum_stability Minimum stability for the updates; 0=dev, 1=alpha, 2=beta, 3=rc, 4=stable
+ * @param int|array $eid Extension Identifier or list of Extension Identifiers; if zero use all
+ * sites
+ * @param integer $cacheTimeout How many seconds to cache update information; if zero, force reload the
+ * update information
+ * @param integer $minimum_stability Minimum stability for the updates; 0=dev, 1=alpha, 2=beta, 3=rc,
+ * 4=stable
+ * @param boolean $includeCurrent Should I include the current version in the results?
*
* @return boolean True if there are updates
*
* @since 11.1
*/
- public function findUpdates($eid = 0, $cacheTimeout = 0, $minimum_stability = self::STABILITY_STABLE)
+ public function findUpdates($eid = 0, $cacheTimeout = 0, $minimum_stability = self::STABILITY_STABLE, $includeCurrent = false)
{
- $db = $this->getDbo();
- $query = $db->getQuery(true);
-
$retval = false;
+ $results = $this->getUpdateSites($eid);
+
+ if (empty($results))
+ {
+ return $retval;
+ }
+
+ $now = time();
+ $earliestTime = $now - $cacheTimeout;
+ $sitesWithUpdates = array();
+
+ if ($cacheTimeout > 0)
+ {
+ $sitesWithUpdates = $this->getSitesWithUpdates($earliestTime);
+ }
+
+ foreach ($results as $result)
+ {
+ /**
+ * If we have already checked for updates within the cache timeout period we will report updates available
+ * only if there are update records matching this update site. Then we skip processing of the update site
+ * since it's already processed within the cache timeout period.
+ */
+ if (($cacheTimeout > 0)
+ && isset($result['last_check_timestamp'])
+ && ($result['last_check_timestamp'] >= $earliestTime))
+ {
+ $retval = $retval || in_array($result['update_site_id'], $sitesWithUpdates);
+
+ continue;
+ }
+
+ $updateObjects = $this->getUpdateObjectsForSite($result, $minimum_stability, $includeCurrent);
+
+ if (!empty($updateObjects))
+ {
+ $retval = true;
+
+ /** @var JTableUpdate $update */
+ foreach ($updateObjects as $update)
+ {
+ $update->store();
+ }
+ }
+
+ // Finally, update the last update check timestamp
+ $this->updateLastCheckTimestamp($result['update_site_id']);
+ }
+
+ return $retval;
+ }
+
+ /**
+ * Finds an update for an extension
+ *
+ * @param integer $id Id of the extension
+ *
+ * @return mixed
+ *
+ * @since 3.5.2
+ */
+ public function update($id)
+ {
+ $updaterow = JTable::getInstance('update');
+ $updaterow->load($id);
+ $update = new JUpdate;
+
+ if ($update->loadFromXml($updaterow->detailsurl))
+ {
+ return $update->install();
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the update site records for an extension with ID $eid. If $eid is zero all enabled update sites records
+ * will be returned.
+ *
+ * @param int $eid The extension ID to fetch.
+ *
+ * @return array
+ *
+ * @since 3.5.2
+ */
+ private function getUpdateSites($eid = 0)
+ {
+ $db = $this->getDbo();
+ $query = $db->getQuery(true);
+
$query->select('DISTINCT a.update_site_id, a.type, a.location, a.last_check_timestamp, a.extra_query')
- ->from('#__update_sites AS a')
+ ->from($db->quoteName('#__update_sites', 'a'))
->where('a.enabled = 1');
if ($eid)
@@ -134,139 +225,207 @@ public function findUpdates($eid = 0, $cacheTimeout = 0, $minimum_stability = se
}
$db->setQuery($query);
- $results = $db->loadAssocList();
- $result_count = count($results);
- $now = time();
- for ($i = 0; $i < $result_count; $i++)
+ $result = $db->loadAssocList();
+
+ if (!is_array($result))
{
- $result = &$results[$i];
- $this->setAdapter($result['type']);
+ return array();
+ }
- if (!isset($this->_adapters[$result['type']]))
- {
- // Ignore update sites requiring adapters we don't have installed
- continue;
- }
+ return $result;
+ }
- if ($cacheTimeout > 0)
- {
- if (isset($result['last_check_timestamp']) && ($now - $result['last_check_timestamp'] <= $cacheTimeout))
- {
- // Ignore update sites whose information we have fetched within
- // the cache time limit
- $retval = true;
- continue;
- }
- }
+ /**
+ * Loads the contents of an update site record $updateSite and returns the update objects
+ *
+ * @param array $updateSite The update site record to process
+ * @param int $minimum_stability Minimum stability for the returned update records
+ * @param bool $includeCurrent Should I also include the current version?
+ *
+ * @return array The update records. Empty array if no updates are found.
+ *
+ * @since 3.5.2
+ */
+ private function getUpdateObjectsForSite($updateSite, $minimum_stability = self::STABILITY_STABLE, $includeCurrent = false)
+ {
+ $retVal = array();
- $result['minimum_stability'] = $minimum_stability;
+ $this->setAdapter($updateSite['type']);
- /** @var JUpdateAdapter $adapter */
- $adapter = $this->_adapters[$result['type']];
- $update_result = $adapter->findUpdate($result);
+ if (!isset($this->_adapters[$updateSite['type']]))
+ {
+ // Ignore update sites requiring adapters we don't have installed
+ return $retVal;
+ }
- if (is_array($update_result))
+ $updateSite['minimum_stability'] = $minimum_stability;
+
+ // Get the update information from the remote update XML document
+ /** @var JUpdateAdapter $adapter */
+ $adapter = $this->_adapters[ $updateSite['type']];
+ $update_result = $adapter->findUpdate($updateSite);
+
+ // Version comparison operator.
+ $operator = $includeCurrent ? 'ge' : 'gt';
+
+ if (is_array($update_result))
+ {
+ // If we have additional update sites in the remote (collection) update XML document, parse them
+ if (array_key_exists('update_sites', $update_result) && count($update_result['update_sites']))
{
- if (array_key_exists('update_sites', $update_result) && count($update_result['update_sites']))
+ $thisUrl = trim($updateSite['location']);
+ $thisId = (int) $updateSite['update_site_id'];
+
+ foreach ($update_result['update_sites'] as $extraUpdateSite)
{
- $results = JArrayHelper::arrayUnique(array_merge($results, $update_result['update_sites']));
- $result_count = count($results);
+ $extraUrl = trim($extraUpdateSite['location']);
+ $extraId = (int) $extraUpdateSite['update_site_id'];
+
+ // Do not try to fetch the same update site twice
+ if (($thisId == $extraId) || ($thisUrl == $extraUrl))
+ {
+ continue;
+ }
+
+ $extraUpdates = $this->getUpdateObjectsForSite($extraUpdateSite, $minimum_stability);
+
+ if (count($extraUpdates))
+ {
+ $retVal = array_merge($retVal, $extraUpdates);
+ }
}
+ }
- if (array_key_exists('updates', $update_result) && count($update_result['updates']))
+ if (array_key_exists('updates', $update_result) && count($update_result['updates']))
+ {
+ /** @var JUpdate $current_update */
+ foreach ($update_result['updates'] as $current_update)
{
- for ($k = 0, $count = count($update_result['updates']); $k < $count; $k++)
- {
- $current_update = &$update_result['updates'][$k];
- $current_update->extra_query = $result['extra_query'];
- $update = JTable::getInstance('update');
- $extension = JTable::getInstance('extension');
- $uid = $update
- ->find(
+ $current_update->extra_query = $updateSite['extra_query'];
+
+ /** @var JTableUpdate $update */
+ $update = JTable::getInstance('update');
+
+ /** @var JTableExtension $extension */
+ $extension = JTable::getInstance('extension');
+
+ $uid = $update
+ ->find(
array(
- 'element' => $current_update->get('element'), 'type' => $current_update->get('type'),
+ 'element' => $current_update->get('element'),
+ 'type' => $current_update->get('type'),
'client_id' => $current_update->get('client_id'),
- 'folder' => $current_update->get('folder')
+ 'folder' => $current_update->get('folder')
)
);
- $eid = $extension
- ->find(
+ $eid = $extension
+ ->find(
array(
- 'element' => $current_update->get('element'), 'type' => $current_update->get('type'),
+ 'element' => $current_update->get('element'),
+ 'type' => $current_update->get('type'),
'client_id' => $current_update->get('client_id'),
- 'folder' => $current_update->get('folder')
+ 'folder' => $current_update->get('folder')
)
);
- if (!$uid)
+ if (!$uid)
+ {
+ // Set the extension id
+ if ($eid)
{
- // Set the extension id
- if ($eid)
- {
- // We have an installed extension, check the update is actually newer
- $extension->load($eid);
- $data = json_decode($extension->manifest_cache, true);
-
- if (version_compare($current_update->version, $data['version'], '>') == 1)
- {
- $current_update->extension_id = $eid;
- $current_update->store();
- }
- }
- else
+ // We have an installed extension, check the update is actually newer
+ $extension->load($eid);
+ $data = json_decode($extension->manifest_cache, true);
+
+ if (version_compare($current_update->version, $data['version'], $operator) == 1)
{
- // A potentially new extension to be installed
- $current_update->store();
+ $current_update->extension_id = $eid;
+ $retVal[] = $current_update;
}
}
else
{
- $update->load($uid);
+ // A potentially new extension to be installed
+ $retVal[] = $current_update;
+ }
+ }
+ else
+ {
+ $update->load($uid);
- // If there is an update, check that the version is newer then replaces
- if (version_compare($current_update->version, $update->version, '>') == 1)
- {
- $current_update->store();
- }
+ // If there is an update, check that the version is newer then replaces
+ if (version_compare($current_update->version, $update->version, $operator) == 1)
+ {
+ $retVal[] = $current_update;
}
}
}
}
-
- // Finally, update the last update check timestamp
- $query = $db->getQuery(true)
- ->update($db->quoteName('#__update_sites'))
- ->set($db->quoteName('last_check_timestamp') . ' = ' . $db->quote($now))
- ->where($db->quoteName('update_site_id') . ' = ' . $db->quote($result['update_site_id']));
- $db->setQuery($query);
- $db->execute();
}
- return $retval;
+ return $retVal;
}
/**
- * Finds an update for an extension
+ * Returns the IDs of the update sites with cached updates
*
- * @param integer $id Id of the extension
+ * @param int $timestamp Optional. If set, only update sites checked before $timestamp will be taken into
+ * account.
*
- * @return mixed
+ * @return array The IDs of the update sites with cached updates
*
- * @since 11.1
+ * @since 3.5.2
*/
- public function update($id)
+ private function getSitesWithUpdates($timestamp = 0)
{
- $updaterow = JTable::getInstance('update');
- $updaterow->load($id);
- $update = new JUpdate;
+ $db = JFactory::getDbo();
- if ($update->loadFromXml($updaterow->detailsurl))
+ $query = $db->getQuery(true)
+ ->select('DISTINCT update_site_id')
+ ->from('#__updates');
+
+ if ($timestamp)
{
- return $update->install();
+ $subQuery = $db->getQuery(true)
+ ->select('update_site_id')
+ ->from('#__update_sites')
+ ->where($db->qn('last_check_timestamp') . ' IS NULL', 'OR')
+ ->where($db->qn('last_check_timestamp') . ' <= ' . $db->q($timestamp), 'OR');
+
+ $query->where($db->qn('update_site_id') . ' IN (' . $subQuery . ')');
}
- return false;
+ $retVal = $db->setQuery($query)->loadColumn(0);
+
+ if (empty($retVal))
+ {
+ return array();
+ }
+
+ return $retVal;
+ }
+
+ /**
+ * Update the last check timestamp of an update site
+ *
+ * @param int $updateSiteId The update site ID to mark as just checked
+ *
+ * @return void
+ *
+ * @since 3.5.2
+ */
+ private function updateLastCheckTimestamp($updateSiteId)
+ {
+ $timestamp = time();
+ $db = JFactory::getDbo();
+
+ $query = $db->getQuery(true)
+ ->update($db->quoteName('#__update_sites'))
+ ->set($db->quoteName('last_check_timestamp') . ' = ' . $db->quote($timestamp))
+ ->where($db->quoteName('update_site_id') . ' = ' . $db->quote($updateSiteId));
+ $db->setQuery($query);
+ $db->execute();
}
}
diff --git a/media/com_joomlaupdate/js/default.js b/media/com_joomlaupdate/js/default.js
index caf896f70165c..86cc3c5cde755 100644
--- a/media/com_joomlaupdate/js/default.js
+++ b/media/com_joomlaupdate/js/default.js
@@ -1,24 +1,13 @@
-jQuery(function ($) {
- $em = $('#extraction_method');
- if ($em.length) {
- $em.on('change', function () {
- if ($em.val() === 'direct') {
- document.getElementById('row_ftp_hostname').style.display = 'none';
- document.getElementById('row_ftp_port').style.display = 'none';
- document.getElementById('row_ftp_username').style.display = 'none';
- document.getElementById('row_ftp_password').style.display = 'none';
- document.getElementById('row_ftp_directory').style.display = 'none';
- } else {
- document.getElementById('row_ftp_hostname').style.display = 'table-row';
- document.getElementById('row_ftp_port').style.display = 'table-row';
- document.getElementById('row_ftp_username').style.display = 'table-row';
- document.getElementById('row_ftp_password').style.display = 'table-row';
- document.getElementById('row_ftp_directory').style.display = 'table-row';
- }
- });
- }
+function extractionMethodHandler(target, prefix)
+{
+ jQuery(function ($) {
+ $em = $(target);
+ displayStyle = ($em.val() === 'direct') ? 'none' : 'table-row';
- $('button.submit').on('click', function() {
- $('div.download_message').show();
- })
-});
+ document.getElementById(prefix + '_hostname').style.display = displayStyle;
+ document.getElementById(prefix + '_port').style.display = displayStyle;
+ document.getElementById(prefix + '_username').style.display = displayStyle;
+ document.getElementById(prefix + '_password').style.display = displayStyle;
+ document.getElementById(prefix + '_directory').style.display = displayStyle;
+ });
+}
diff --git a/media/com_joomlaupdate/js/default.min.js b/media/com_joomlaupdate/js/default.min.js
new file mode 100644
index 0000000000000..40a79b2220b6a
--- /dev/null
+++ b/media/com_joomlaupdate/js/default.min.js
@@ -0,0 +1 @@
+function extractionMethodHandler(e,t){jQuery(function(l){$em=l(e),displayStyle="direct"===$em.val()?"none":"table-row",document.getElementById(t+"_hostname").style.display=displayStyle,document.getElementById(t+"_port").style.display=displayStyle,document.getElementById(t+"_username").style.display=displayStyle,document.getElementById(t+"_password").style.display=displayStyle,document.getElementById(t+"_directory").style.display=displayStyle})}
diff --git a/media/com_joomlaupdate/js/encryption.min.js b/media/com_joomlaupdate/js/encryption.min.js
new file mode 100644
index 0000000000000..3389ec9531283
--- /dev/null
+++ b/media/com_joomlaupdate/js/encryption.min.js
@@ -0,0 +1 @@
+var Aes={};Aes.Cipher=function(r,e){for(var o=4,n=e.length/o-1,a=[[],[],[],[]],t=0;4*o>t;t++)a[t%4][Math.floor(t/4)]=r[t];a=Aes.AddRoundKey(a,e,0,o);for(var f=1;n>f;f++)a=Aes.SubBytes(a,o),a=Aes.ShiftRows(a,o),a=Aes.MixColumns(a,o),a=Aes.AddRoundKey(a,e,f,o);a=Aes.SubBytes(a,o),a=Aes.ShiftRows(a,o),a=Aes.AddRoundKey(a,e,n,o);for(var c=new Array(4*o),t=0;4*o>t;t++)c[t]=a[t%4][Math.floor(t/4)];return c},Aes.KeyExpansion=function(r){for(var e=4,o=r.length/4,n=o+6,a=new Array(e*(n+1)),t=new Array(4),f=0;o>f;f++){var c=[r[4*f],r[4*f+1],r[4*f+2],r[4*f+3]];a[f]=c}for(var f=o;e*(n+1)>f;f++){a[f]=new Array(4);for(var A=0;4>A;A++)t[A]=a[f-1][A];if(f%o==0){t=Aes.SubWord(Aes.RotWord(t));for(var A=0;4>A;A++)t[A]^=Aes.Rcon[f/o][A]}else o>6&&f%o==4&&(t=Aes.SubWord(t));for(var A=0;4>A;A++)a[f][A]=a[f-o][A]^t[A]}return a},Aes.SubBytes=function(r,e){for(var o=0;4>o;o++)for(var n=0;e>n;n++)r[o][n]=Aes.Sbox[r[o][n]];return r},Aes.ShiftRows=function(r,e){for(var o=new Array(4),n=1;4>n;n++){for(var a=0;4>a;a++)o[a]=r[n][(a+n)%e];for(var a=0;4>a;a++)r[n][a]=o[a]}return r},Aes.MixColumns=function(r,e){for(var o=0;4>o;o++){for(var n=new Array(4),a=new Array(4),t=0;4>t;t++)n[t]=r[t][o],a[t]=128&r[t][o]?r[t][o]<<1^283:r[t][o]<<1;r[0][o]=a[0]^n[1]^a[1]^n[2]^n[3],r[1][o]=n[0]^a[1]^n[2]^a[2]^n[3],r[2][o]=n[0]^n[1]^a[2]^n[3]^a[3],r[3][o]=n[0]^a[0]^n[1]^n[2]^a[3]}return r},Aes.AddRoundKey=function(r,e,o,n){for(var a=0;4>a;a++)for(var t=0;n>t;t++)r[a][t]^=e[4*o+t][a];return r},Aes.SubWord=function(r){for(var e=0;4>e;e++)r[e]=Aes.Sbox[r[e]];return r},Aes.RotWord=function(r){for(var e=r[0],o=0;3>o;o++)r[o]=r[o+1];return r[3]=e,r},Aes.Sbox=[99,124,119,123,242,107,111,197,48,1,103,43,254,215,171,118,202,130,201,125,250,89,71,240,173,212,162,175,156,164,114,192,183,253,147,38,54,63,247,204,52,165,229,241,113,216,49,21,4,199,35,195,24,150,5,154,7,18,128,226,235,39,178,117,9,131,44,26,27,110,90,160,82,59,214,179,41,227,47,132,83,209,0,237,32,252,177,91,106,203,190,57,74,76,88,207,208,239,170,251,67,77,51,133,69,249,2,127,80,60,159,168,81,163,64,143,146,157,56,245,188,182,218,33,16,255,243,210,205,12,19,236,95,151,68,23,196,167,126,61,100,93,25,115,96,129,79,220,34,42,144,136,70,238,184,20,222,94,11,219,224,50,58,10,73,6,36,92,194,211,172,98,145,149,228,121,231,200,55,109,141,213,78,169,108,86,244,234,101,122,174,8,186,120,37,46,28,166,180,198,232,221,116,31,75,189,139,138,112,62,181,102,72,3,246,14,97,53,87,185,134,193,29,158,225,248,152,17,105,217,142,148,155,30,135,233,206,85,40,223,140,161,137,13,191,230,66,104,65,153,45,15,176,84,187,22],Aes.Rcon=[[0,0,0,0],[1,0,0,0],[2,0,0,0],[4,0,0,0],[8,0,0,0],[16,0,0,0],[32,0,0,0],[64,0,0,0],[128,0,0,0],[27,0,0,0],[54,0,0,0]];var AesCtr={};AesCtr.encrypt=function(r,e,o){var n=16;if(128!=o&&192!=o&&256!=o)return"";r=Utf8.encode(r),e=Utf8.encode(e);for(var a=o/8,t=new Array(a),f=0;a>f;f++)t[f]=isNaN(e.charCodeAt(f))?0:e.charCodeAt(f);var c=Aes.Cipher(t,Aes.KeyExpansion(t));c=c.concat(c.slice(0,a-16));for(var A=new Array(n),d=(new Date).getTime(),i=Math.floor(d/1e3),u=d%1e3,f=0;4>f;f++)A[f]=i>>>8*f&255;for(var f=0;4>f;f++)A[f+4]=255&u;for(var s="",f=0;8>f;f++)s+=String.fromCharCode(A[f]);for(var h=Aes.KeyExpansion(c),v=Math.ceil(r.length/n),C=new Array(v),y=0;v>y;y++){for(var l=0;4>l;l++)A[15-l]=y>>>8*l&255;for(var l=0;4>l;l++)A[15-l-4]=y/4294967296>>>8*l;for(var g=Aes.Cipher(A,h),S=v-1>y?n:(r.length-1)%n+1,w=new Array(S),f=0;S>f;f++)w[f]=g[f]^r.charCodeAt(y*n+f),w[f]=String.fromCharCode(w[f]);C[y]=w.join("")}var p=s+C.join("");return p=Base64.encode(p)},AesCtr.decrypt=function(r,e,o){var n=16;if(128!=o&&192!=o&&256!=o)return"";r=Base64.decode(r),e=Utf8.encode(e);for(var a=o/8,t=new Array(a),f=0;a>f;f++)t[f]=isNaN(e.charCodeAt(f))?0:e.charCodeAt(f);var c=Aes.Cipher(t,Aes.KeyExpansion(t));c=c.concat(c.slice(0,a-16));var A=new Array(8);ctrTxt=r.slice(0,8);for(var f=0;8>f;f++)A[f]=ctrTxt.charCodeAt(f);for(var d=Aes.KeyExpansion(c),i=Math.ceil((r.length-8)/n),u=new Array(i),s=0;i>s;s++)u[s]=r.slice(8+s*n,8+s*n+n);r=u;for(var h=new Array(r.length),s=0;i>s;s++){for(var v=0;4>v;v++)A[15-v]=s>>>8*v&255;for(var v=0;4>v;v++)A[15-v-4]=(s+1)/4294967296-1>>>8*v&255;for(var C=Aes.Cipher(A,d),y=new Array(r[s].length),f=0;f0)for(;i++<3;)v+="=",u+="\x00";for(i=0;i>18&63,c=t>>12&63,A=t>>6&63,d=63&t,h[i/3]=C.charAt(f)+C.charAt(c)+C.charAt(A)+C.charAt(d);return s=h.join(""),s=s.slice(0,s.length-v.length)+v},Base64.decode=function(r,e){e="undefined"==typeof e?!1:e;var o,n,a,t,f,c,A,d,i,u,s=[],h=Base64.code;u=e?r.decodeUTF8():r;for(var v=0;v>>16&255,n=d>>>8&255,a=255&d,s[v/4]=String.fromCharCode(o,n,a),64==A&&(s[v/4]=String.fromCharCode(o,n)),64==c&&(s[v/4]=String.fromCharCode(o));return i=s.join(""),e?i.decodeUTF8():i};var Utf8={};Utf8.encode=function(r){var e=r.replace(/[\u0080-\u07ff]/g,function(r){var e=r.charCodeAt(0);return String.fromCharCode(192|e>>6,128|63&e)});return e=e.replace(/[\u0800-\uffff]/g,function(r){var e=r.charCodeAt(0);return String.fromCharCode(224|e>>12,128|e>>6&63,128|63&e)})},Utf8.decode=function(r){var e=r.replace(/[\u00c0-\u00df][\u0080-\u00bf]/g,function(r){var e=(31&r.charCodeAt(0))<<6|63&r.charCodeAt(1);return String.fromCharCode(e)});return e=e.replace(/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g,function(r){var e=(15&r.charCodeAt(0))<<12|(63&r.charCodeAt(1))<<6|63&r.charCodeAt(2);return String.fromCharCode(e)})};
diff --git a/media/com_joomlaupdate/js/json2.min.js b/media/com_joomlaupdate/js/json2.min.js
new file mode 100644
index 0000000000000..09d5975413848
--- /dev/null
+++ b/media/com_joomlaupdate/js/json2.min.js
@@ -0,0 +1 @@
+"object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(t){return 10>t?"0"+t:t}function quote(t){return escapable.lastIndex=0,escapable.test(t)?'"'+t.replace(escapable,function(t){var e=meta[t];return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'}function str(t,e){var n,r,o,f,u,p=gap,a=e[t];switch(a&&"object"==typeof a&&"function"==typeof a.toJSON&&(a=a.toJSON(t)),"function"==typeof rep&&(a=rep.call(e,t,a)),typeof a){case"string":return quote(a);case"number":return isFinite(a)?String(a):"null";case"boolean":case"null":return String(a);case"object":if(!a)return"null";if(gap+=indent,u=[],"[object Array]"===Object.prototype.toString.apply(a)){for(f=a.length,n=0;f>n;n+=1)u[n]=str(n,a)||"null";return o=0===u.length?"[]":gap?"[\n"+gap+u.join(",\n"+gap)+"\n"+p+"]":"["+u.join(",")+"]",gap=p,o}if(rep&&"object"==typeof rep)for(f=rep.length,n=0;f>n;n+=1)"string"==typeof rep[n]&&(r=rep[n],o=str(r,a),o&&u.push(quote(r)+(gap?": ":":")+o));else for(r in a)Object.prototype.hasOwnProperty.call(a,r)&&(o=str(r,a),o&&u.push(quote(r)+(gap?": ":":")+o));return o=0===u.length?"{}":gap?"{\n"+gap+u.join(",\n"+gap)+"\n"+p+"}":"{"+u.join(",")+"}",gap=p,o}}"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()});var e,escapable,gap,indent,meta,rep;"function"!=typeof JSON.stringify&&(escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},JSON.stringify=function(t,e,n){var r;if(gap="",indent="","number"==typeof n)for(r=0;n>r;r+=1)indent+=" ";else"string"==typeof n&&(indent=n);if(rep=e,e&&"function"!=typeof e&&("object"!=typeof e||"number"!=typeof e.length))throw new Error("JSON.stringify");return str("",{"":t})}),"function"!=typeof JSON.parse&&(e=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,JSON.parse=function(c,d){function walk(t,e){var n,r,o=t[e];if(o&&"object"==typeof o)for(n in o)Object.prototype.hasOwnProperty.call(o,n)&&(r=walk(o,n),void 0!==r?o[n]=r:delete o[n]);return d.call(t,e,o)}var j;if(c=String(c),e.lastIndex=0,e.test(c)&&(c=c.replace(e,function(t){return"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})),/^[\],:{}\s]*$/.test(c.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return j=eval("("+c+")"),"function"==typeof d?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}();
diff --git a/media/com_joomlaupdate/js/update.min.js b/media/com_joomlaupdate/js/update.min.js
new file mode 100644
index 0000000000000..b1b614f30075e
--- /dev/null
+++ b/media/com_joomlaupdate/js/update.min.js
@@ -0,0 +1 @@
+function error_callback(t){alert("ERROR:\n"+t)}function empty(t){var r;if(""===t||0===t||"0"===t||null===t||t===!1||"undefined"==typeof t)return!0;if("object"==typeof t){for(r in t)return!1;return!0}return!1}function is_array(t){var r="",e=function(t){var r=/\W*function\s+([\w\$]+)\s*\(/.exec(t);return r?r[1]:"(Anonymous)"};if(!t)return!1;if(this.php_js=this.php_js||{},this.php_js.ini=this.php_js.ini||{},"object"==typeof t){if(this.php_js.ini["phpjs.objectsAsArrays"]&&(this.php_js.ini["phpjs.objectsAsArrays"].local_value.toLowerCase&&"off"===this.php_js.ini["phpjs.objectsAsArrays"].local_value.toLowerCase()||0===parseInt(this.php_js.ini["phpjs.objectsAsArrays"].local_value,10)))return t.hasOwnProperty("length")&&!t.propertyIsEnumerable("length")&&"String"!==e(t.constructor);if(t.hasOwnProperty)for(r in t)if(!1===t.hasOwnProperty(r))return!1;return!0}return!1}var stat_total=0,stat_files=0,stat_inbytes=0,stat_outbytes=0;doEncryptedAjax=function(t,r,e){var s=JSON.stringify(t);joomlaupdate_password.length>0&&(s=AesCtr.encrypt(s,joomlaupdate_password,128));var a={json:s},n={type:"POST",url:joomlaupdate_ajax_url,cache:!1,data:a,timeout:6e5,success:function(t,s){var a=null,n="",o=t.indexOf("###");if(-1==o)return t="Invalid AJAX data:\n"+t,void(null==e?null!=error_callback&&error_callback(t):e(t));0!=o?(a=t.substr(0,o),n=t.substr(o)):n=t,n=n.substr(3);var o=n.lastIndexOf("###");n=n.substr(0,o);var i=null;if(joomlaupdate_password.length>0)try{var i=JSON.parse(n)}catch(c){n=AesCtr.decrypt(n,joomlaupdate_password,128)}try{empty(i)&&(i=JSON.parse(n))}catch(c){var t=c.message+"\n \n