diff --git a/administrator/language/en-GB/en-GB.lib_joomla.ini b/administrator/language/en-GB/en-GB.lib_joomla.ini
index b7929aa2d9d93..14b271b6cb0ea 100644
--- a/administrator/language/en-GB/en-GB.lib_joomla.ini
+++ b/administrator/language/en-GB/en-GB.lib_joomla.ini
@@ -539,11 +539,13 @@ JLIB_INSTALLER_ERROR_CREATE_DIRECTORY="JInstaller: :Install: Failed to create fo
JLIB_INSTALLER_ERROR_CREATE_FOLDER_FAILED="Failed to create folder [%s]"
JLIB_INSTALLER_ERROR_DEPRECATED_FORMAT="Deprecated install format (client="_QQ_"both"_QQ_"), use package installer in future."
JLIB_INSTALLER_ERROR_DISCOVER_INSTALL_UNSUPPORTED="A %s extension can not be installed using the discover method. Please install this extension from Extension Manager: Install."
+JLIB_INSTALLER_ERROR_DOWNGRADE="Sorry! You cannot downgrade from version %s to %s"
JLIB_INSTALLER_ERROR_DOWNLOAD_SERVER_CONNECT="Error connecting to the server: %s"
JLIB_INSTALLER_ERROR_FAIL_COPY_FILE="JInstaller: :Install: Failed to copy file %1$s to %2$s"
JLIB_INSTALLER_ERROR_FAIL_COPY_FOLDER="JInstaller: :Install: Failed to copy folder %1$s to %2$s"
JLIB_INSTALLER_ERROR_FAILED_READING_NETWORK_RESOURCES="Failed reading network resource: %s"
JLIB_INSTALLER_ERROR_FILE_EXISTS="JInstaller: :Install: File already exists %s"
+JLIB_INSTALLER_ERROR_FILE_FOLDER="Error on deleting file or folder %s"
JLIB_INSTALLER_ERROR_FILE_UNINSTALL_INVALID_MANIFEST="Files Uninstall: Invalid manifest file."
JLIB_INSTALLER_ERROR_FILE_UNINSTALL_INVALID_NOTFOUND_MANIFEST="Files Uninstall: Manifest file invalid or not found."
JLIB_INSTALLER_ERROR_FILE_UNINSTALL_LOAD_ENTRY="Files Uninstall: Could not load extension entry."
@@ -602,7 +604,10 @@ JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_DIRECTORY="Template Uninstall: Folde
JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_ID_EMPTY="Template Uninstall: Template ID is empty, can't uninstall files."
JLIB_INSTALLER_ERROR_TPL_UNINSTALL_WARNCORETEMPLATE="Template Uninstall: Trying to uninstall a core template: %s"
JLIB_INSTALLER_ERROR_UNKNOWN_CLIENT_TYPE="Unknown Client Type [%s]"
+JLIB_INSTALLER_FILE_ERROR_MOVE="Error on moving file %s"
JLIB_INSTALLER_INSTALL="Install"
+JLIB_INSTALLER_MINIMUM_JOOMLA="You don't have the minimum Joomla version requirement of J%s"
+JLIB_INSTALLER_MINIMUM_PHP="Your server doesn't meet the minimum PHP version requirement of %s"
JLIB_INSTALLER_NOTICE_LANG_RESET_USERS="Language set to Default for %d users."
JLIB_INSTALLER_NOTICE_LANG_RESET_USERS_1="Language set to Default for %d user."
JLIB_INSTALLER_UNINSTALL="Uninstall"
diff --git a/language/en-GB/en-GB.lib_joomla.ini b/language/en-GB/en-GB.lib_joomla.ini
index b7929aa2d9d93..14b271b6cb0ea 100644
--- a/language/en-GB/en-GB.lib_joomla.ini
+++ b/language/en-GB/en-GB.lib_joomla.ini
@@ -539,11 +539,13 @@ JLIB_INSTALLER_ERROR_CREATE_DIRECTORY="JInstaller: :Install: Failed to create fo
JLIB_INSTALLER_ERROR_CREATE_FOLDER_FAILED="Failed to create folder [%s]"
JLIB_INSTALLER_ERROR_DEPRECATED_FORMAT="Deprecated install format (client="_QQ_"both"_QQ_"), use package installer in future."
JLIB_INSTALLER_ERROR_DISCOVER_INSTALL_UNSUPPORTED="A %s extension can not be installed using the discover method. Please install this extension from Extension Manager: Install."
+JLIB_INSTALLER_ERROR_DOWNGRADE="Sorry! You cannot downgrade from version %s to %s"
JLIB_INSTALLER_ERROR_DOWNLOAD_SERVER_CONNECT="Error connecting to the server: %s"
JLIB_INSTALLER_ERROR_FAIL_COPY_FILE="JInstaller: :Install: Failed to copy file %1$s to %2$s"
JLIB_INSTALLER_ERROR_FAIL_COPY_FOLDER="JInstaller: :Install: Failed to copy folder %1$s to %2$s"
JLIB_INSTALLER_ERROR_FAILED_READING_NETWORK_RESOURCES="Failed reading network resource: %s"
JLIB_INSTALLER_ERROR_FILE_EXISTS="JInstaller: :Install: File already exists %s"
+JLIB_INSTALLER_ERROR_FILE_FOLDER="Error on deleting file or folder %s"
JLIB_INSTALLER_ERROR_FILE_UNINSTALL_INVALID_MANIFEST="Files Uninstall: Invalid manifest file."
JLIB_INSTALLER_ERROR_FILE_UNINSTALL_INVALID_NOTFOUND_MANIFEST="Files Uninstall: Manifest file invalid or not found."
JLIB_INSTALLER_ERROR_FILE_UNINSTALL_LOAD_ENTRY="Files Uninstall: Could not load extension entry."
@@ -602,7 +604,10 @@ JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_DIRECTORY="Template Uninstall: Folde
JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_ID_EMPTY="Template Uninstall: Template ID is empty, can't uninstall files."
JLIB_INSTALLER_ERROR_TPL_UNINSTALL_WARNCORETEMPLATE="Template Uninstall: Trying to uninstall a core template: %s"
JLIB_INSTALLER_ERROR_UNKNOWN_CLIENT_TYPE="Unknown Client Type [%s]"
+JLIB_INSTALLER_FILE_ERROR_MOVE="Error on moving file %s"
JLIB_INSTALLER_INSTALL="Install"
+JLIB_INSTALLER_MINIMUM_JOOMLA="You don't have the minimum Joomla version requirement of J%s"
+JLIB_INSTALLER_MINIMUM_PHP="Your server doesn't meet the minimum PHP version requirement of %s"
JLIB_INSTALLER_NOTICE_LANG_RESET_USERS="Language set to Default for %d users."
JLIB_INSTALLER_NOTICE_LANG_RESET_USERS_1="Language set to Default for %d user."
JLIB_INSTALLER_UNINSTALL="Uninstall"
diff --git a/libraries/cms/installer/script.php b/libraries/cms/installer/script.php
new file mode 100644
index 0000000000000..d6126635641f8
--- /dev/null
+++ b/libraries/cms/installer/script.php
@@ -0,0 +1,353 @@
+minimumPhp) && !version_compare(PHP_VERSION, $this->minimumPhp, '>'))
+ {
+ JLog::add(JText::sprintf('JLIB_INSTALLER_MINIMUM_PHP', $this->minimumPhp), JLog::WARNING, 'jerror');
+ }
+
+ // Check for the minimum Joomla version before continuing
+ if (!empty($this->minimumJoomla) && !version_compare(JVERSION, $this->minimumJoomla, '>'))
+ {
+ JLog::add(JText::sprintf('JLIB_INSTALLER_MINIMUM_JOOMLA', $this->minimumJoomla), JLog::WARNING, 'jerror');
+ }
+
+ // Extension manifest file version
+ $this->release = $parent->get("manifest")->version;
+ $extensionType = substr($this->extension, 0, 3);
+
+ // Modules parameters are located in the module table - else in the extension table
+ if ($extensionType === 'mod')
+ {
+ $this->paramTable = '#__modules';
+ }
+ else
+ {
+ $this->paramTable = '#__extensions';
+ }
+
+ // Abort if the extension being installed is not newer than the currently installed version
+ if (strtolower($type) == 'update' && !$this->allowDowngrades)
+ {
+ $manifest = $this->getItemArray('manifest_cache', '#__extensions', 'element', JFactory::getDbo()->quote($this->extension));
+ $oldRelease = $manifest['version'];
+
+ if (version_compare($this->release, $oldRelease, '<'))
+ {
+ JFactory::getApplication()->enqueueMessage(JText::sprintf('JLIB_INSTALLER_INCORRECT_SEQUENCE', $oldRelease, $this->release), 'error');
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Gets each instance of a module in the #__modules table
+ *
+ * @param boolean $isModule True if the extension is a module as this can have multiple instances
+ *
+ * @return array An array of ID's of the extension
+ *
+ * @since 3.6
+ */
+ public function getInstances($isModule)
+ {
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true);
+
+ // Select the item(s) and retrieve the id
+ $query->select($db->quoteName('id'));
+
+ if ($isModule)
+ {
+ $query->from($db->quoteName('#__modules'))
+ ->where($db->quoteName('module') . ' = ' . $db->quote($this->extension));
+ }
+ else
+ {
+ $query->from($db->quoteName('#__extensions'))
+ ->where($db->quoteName('element') . ' = ' . $db->quote($this->extension));
+ }
+
+ // Set the query and obtain an array of id's
+ return $db->setQuery($query)->loadColumn();
+ }
+
+ /**
+ * Gets parameter value in the extensions row of the extension table
+ *
+ * @param string $name The name of the parameter to be retrieved
+ * @param integer $id The id of the item in the Param Table
+ *
+ * @return string The parameter desired
+ *
+ * @since 3.6
+ */
+ public function getParam($name, $id = 0)
+ {
+ if (!is_int($id) || $id == 0)
+ {
+ // Return false if there is no item given
+ return false;
+ }
+
+ $params = $this->getItemArray('params', $this->paramTable, 'id', $id);
+
+ return $params[$name];
+ }
+
+ /**
+ * Sets parameter values in the extensions row of the extension table. Note that the
+ * this must be called separately for deleting and editing. Note if edit is called as a
+ * type then if the param doesn't exist it will be created
+ *
+ * @param array $param_array The array of parameters to be added/edited/removed
+ * @param string $type The type of change to be made to the param (edit/remove)
+ * @param integer $id The id of the item in the relevant table
+ *
+ * @return boolean True on success
+ *
+ * @since 3.6
+ */
+ public function setParams($param_array = null, $type = 'edit', $id = 0)
+ {
+ if (!is_int($id) || $id == 0)
+ {
+ // Return false if there is no valid item given
+ return false;
+ }
+
+ $params = $this->getItemArray('params', $this->paramTable, 'id', $id);
+
+ if ($param_array)
+ {
+ foreach ($param_array as $name => $value)
+ {
+ if ($type == 'edit')
+ {
+ // Add or edit the new variable(s) to the existing params
+ if (is_array($value))
+ {
+ // Convert an array into a json encoded string
+ $params[(string) $name] = array_values($value);
+ }
+ else
+ {
+ $params[(string) $name] = (string) $value;
+ }
+ }
+ elseif ($type == 'remove')
+ {
+ // Unset the parameter from the array
+ unset($params[(string) $name]);
+ }
+ }
+ }
+
+ // Store the combined new and existing values back as a JSON string
+ $paramsString = json_encode($params);
+
+ $db = JFactory::getDbo();
+ $query = $db->getQuery(true)
+ ->update($db->quoteName($this->paramTable))
+ ->set('params = ' . $db->quote($paramsString))
+ ->where('id = ' . $id);
+
+ // Update table
+ $db->setQuery($query)->execute();
+
+ return true;
+ }
+
+ /**
+ * Builds a standard select query to produce better DRY code in this script.
+ * This should produce a single unique cell which is json encoded - it will then
+ * return an associated array with this data in.
+ *
+ * @param string $element The element to get from the query
+ * @param string $table The table to search for the data in
+ * @param string $column The column of the database to search from
+ * @param mixed $identifier The integer id or the already quoted string
+ *
+ * @return array Associated array containing data from the cell
+ *
+ * @since 3.6
+ */
+ public function getItemArray($element, $table, $column, $identifier)
+ {
+ // Get the DB and query objects
+ $db = JFactory::getDbo();
+
+ // Build the query
+ $query = $db->getQuery(true)
+ ->select($db->quoteName($element))
+ ->from($db->quoteName($table))
+ ->where($db->quoteName($column) . ' = ' . $identifier);
+ $db->setQuery($query);
+
+ // Load the single cell and json_decode data
+ return json_decode($db->loadResult(), true);
+ }
+
+ /**
+ * Remove the files and folders in the given array from
+ *
+ * @return void
+ *
+ * @since 3.6
+ */
+ public function removeFiles()
+ {
+ if (!empty($this->deleteFiles))
+ {
+ foreach ($this->deleteFiles as $file)
+ {
+ if (file_exists(JPATH_ROOT . $file) && !JFile::delete(JPATH_ROOT . $file))
+ {
+ echo JText::sprintf('JLIB_INSTALLER_ERROR_FILE_FOLDER', $file) . '
';
+ }
+ }
+ }
+
+ if (!empty($this->deleteFolders))
+ {
+ foreach ($this->deleteFolders as $folder)
+ {
+ if (JFolder::exists(JPATH_ROOT . $folder) && !JFolder::delete(JPATH_ROOT . $folder))
+ {
+ echo JText::sprintf('JLIB_INSTALLER_ERROR_FILE_FOLDER', $folder) . '
';
+ }
+ }
+ }
+ }
+
+ /**
+ * Moves the CLI scripts into the CLI folder in the CMS
+ *
+ * @return void
+ *
+ * @since 3.6
+ */
+ public function moveCliFiles()
+ {
+ if (!empty($this->cliScriptFiles))
+ {
+ foreach ($this->cliScriptFiles as $file)
+ {
+ $name = basename($file);
+
+ if (file_exists(JPATH_ROOT . $file) && !JFile::move(JPATH_ROOT . $file, JPATH_ROOT . '/cli/' . $name))
+ {
+ echo JText::sprintf('JLIB_INSTALLER_FILE_ERROR_MOVE', $name);
+ }
+ }
+ }
+ }
+}