AAAAadapters/.htaccess000066600000000177151372561050010163 0ustar00 Order allow,deny Deny from all adapters/index.html000066600000000037151372561050010355 0ustar00 adapters/template.php000066600000042426151372561050010714 0ustar00parent->getPath('source'); if (!$source) { $this->parent ->setPath( 'source', ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/templates/' . $this->parent->extension->element ); } $clientId = isset($this->parent->extension) ? $this->parent->extension->client_id : 0; $this->manifest = $this->parent->getManifest(); $name = strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd')); $client = (string) $this->manifest->attributes()->client; // Load administrator language if not set. if (!$client) { $client = 'ADMINISTRATOR'; } $extension = "tpl_$name"; $lang = JFactory::getLanguage(); $source = $path ? $path : ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/templates/' . $name; $lang->load($extension . '.sys', $source, null, false, true) || $lang->load($extension . '.sys', constant('JPATH_' . strtoupper($client)), null, false, true); } /** * Custom install method * * @return boolean True on success * * @since 11.1 */ public function install() { // Get a database connector object $db = $this->parent->getDbo(); $lang = JFactory::getLanguage(); $xml = $this->parent->getManifest(); // Get the client application target if ($cname = (string) $xml->attributes()->client) { // Attempt to map the client to a base path $client = JApplicationHelper::getClientInfo($cname, true); if ($client === false) { $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_UNKNOWN_CLIENT', $cname)); return false; } $basePath = $client->path; $clientId = $client->id; } else { // No client attribute was found so we assume the site as the client $cname = 'site'; $basePath = JPATH_SITE; $clientId = 0; } // Set the extension's name $name = JFilterInput::getInstance()->clean((string) $xml->name, 'cmd'); $element = strtolower(str_replace(" ", "_", $name)); $this->set('name', $name); $this->set('element', $element); // Check to see if a template by the same name is already installed. $query = $db->getQuery(true); $query->select($query->qn('extension_id'))->from($query->qn('#__extensions')); $query->where($query->qn('type') . ' = ' . $query->q('template')); $query->where($query->qn('element') . ' = ' . $query->q($element)); $db->setQuery($query); try { $id = $db->loadResult(); } catch (RuntimeException $e) { // Install failed, roll back changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_ROLLBACK'), $e->getMessage()); return false; } // Legacy error handling switch based on the JError::$legacy switch. // @deprecated 12.1 if (JError::$legacy && $db->getErrorNum()) { // Install failed, roll back changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_ROLLBACK', $db->stderr(true))); return false; } // Set the template root path $this->parent->setPath('extension_root', $basePath . '/templates/' . $element); // if it's on the fs... if (file_exists($this->parent->getPath('extension_root')) && (!$this->parent->isOverwrite() || $this->parent->isUpgrade())) { $updateElement = $xml->update; // Upgrade manually set or // Update function available or // Update tag detected if ($this->parent->isUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'update')) || $updateElement) { // Force this one $this->parent->setOverwrite(true); $this->parent->setUpgrade(true); if ($id) { // if there is a matching extension mark this as an update; semantics really $this->route = 'update'; } } elseif (!$this->parent->isOverwrite()) { // Overwrite is not set // If we didn't have overwrite set, find an update function or find an update tag so let's call it safe $this->parent ->abort( JText::sprintf( 'JLIB_INSTALLER_ABORT_TPL_INSTALL_ANOTHER_TEMPLATE_USING_DIRECTORY', JText::_('JLIB_INSTALLER_' . $this->route), $this->parent->getPath('extension_root') ) ); return false; } } /* * If the template directory already exists, then we will assume that the template is already * installed or another template is using that directory. */ if (file_exists($this->parent->getPath('extension_root')) && !$this->parent->isOverwrite()) { JError::raiseWarning( 100, JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_ANOTHER_TEMPLATE_USING_DIRECTORY', $this->parent->getPath('extension_root')) ); return false; } // If the template directory does not exist, let's create it $created = false; if (!file_exists($this->parent->getPath('extension_root'))) { if (!$created = JFolder::create($this->parent->getPath('extension_root'))) { $this->parent ->abort(JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_FAILED_CREATE_DIRECTORY', $this->parent->getPath('extension_root'))); return false; } } // If we created the template directory and will want to remove it if we have to roll back // the installation, let's add it to the installation step stack if ($created) { $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_root'))); } // Copy all the necessary files if ($this->parent->parseFiles($xml->files, -1) === false) { // Install failed, rollback changes $this->parent->abort(); return false; } if ($this->parent->parseFiles($xml->images, -1) === false) { // Install failed, rollback changes $this->parent->abort(); return false; } if ($this->parent->parseFiles($xml->css, -1) === false) { // Install failed, rollback changes $this->parent->abort(); return false; } // Parse optional tags $this->parent->parseMedia($xml->media); $this->parent->parseLanguages($xml->languages, $clientId); // Get the template description $this->parent->set('message', JText::_((string) $xml->description)); // Lastly, we will copy the manifest file to its appropriate place. if (!$this->parent->copyManifest(-1)) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_TPL_INSTALL_COPY_SETUP')); return false; } // Extension Registration $row = JTable::getInstance('extension'); if ($this->route == 'update' && $id) { $row->load($id); } else { $row->type = 'template'; $row->element = $this->get('element'); // There is no folder for templates $row->folder = ''; $row->enabled = 1; $row->protected = 0; $row->access = 1; $row->client_id = $clientId; $row->params = $this->parent->getParams(); $row->custom_data = ''; // custom data } $row->name = $this->get('name'); // name might change in an update $row->manifest_cache = $this->parent->generateManifestCache(); if (!$row->store()) { // Install failed, roll back changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_ROLLBACK', $db->stderr(true))); return false; } if ($this->route == 'install') { //insert record in #__template_styles $query = $db->getQuery(true); $query->insert($db->quoteName('#__template_styles')); $debug = $lang->setDebug(false); $columns = array($db->quoteName('template'), $db->quoteName('client_id'), $db->quoteName('home'), $db->quoteName('title'), $db->quoteName('params') ); $query->columns($columns); $query->values( $db->Quote($row->element) . ',' . $db->Quote($clientId) . ',' . $db->Quote(0) . ',' . $db->Quote(JText::sprintf('JLIB_INSTALLER_DEFAULT_STYLE', JText::_($this->get('name')))) . ',' . $db->Quote($row->params) ); $lang->setDebug($debug); $db->setQuery($query); // There is a chance this could fail but we don't care... $db->execute(); } return $row->get('extension_id'); } /** * Custom update method for components * * @return boolean True on success * * @since 11.1 */ public function update() { return $this->install(); } /** * Custom uninstall method * * @param integer $id The extension ID * * @return boolean True on success * * @since 11.1 */ public function uninstall($id) { // Initialise variables. $retval = true; // First order of business will be to load the template object table from the database. // This should give us the necessary information to proceed. $row = JTable::getInstance('extension'); if (!$row->load((int) $id) || !strlen($row->element)) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_ERRORUNKOWNEXTENSION')); return false; } // Is the template we are trying to uninstall a core one? // Because that is not a good idea... if ($row->protected) { JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_WARNCORETEMPLATE', $row->name)); return false; } $name = $row->element; $clientId = $row->client_id; // For a template the id will be the template name which represents the subfolder of the templates folder that the template resides in. if (!$name) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_ID_EMPTY')); return false; } // Deny remove default template $db = $this->parent->getDbo(); $query = 'SELECT COUNT(*) FROM #__template_styles' . ' WHERE home = 1 AND template = ' . $db->Quote($name); $db->setQuery($query); if ($db->loadResult() != 0) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_DEFAULT')); return false; } // Get the template root path $client = JApplicationHelper::getClientInfo($clientId); if (!$client) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_INVALID_CLIENT')); return false; } $this->parent->setPath('extension_root', $client->path . '/templates/' . strtolower($name)); $this->parent->setPath('source', $this->parent->getPath('extension_root')); // We do findManifest to avoid problem when uninstalling a list of extensions: getManifest cache its manifest file $this->parent->findManifest(); $manifest = $this->parent->getManifest(); if (!($manifest instanceof SimpleXMLElement)) { // Kill the extension entry $row->delete($row->extension_id); unset($row); // Make sure we delete the folders JFolder::delete($this->parent->getPath('extension_root')); JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_INVALID_NOTFOUND_MANIFEST')); return false; } // Remove files $this->parent->removeFiles($manifest->media); $this->parent->removeFiles($manifest->languages, $clientId); // Delete the template directory if (JFolder::exists($this->parent->getPath('extension_root'))) { $retval = JFolder::delete($this->parent->getPath('extension_root')); } else { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_DIRECTORY')); $retval = false; } // Set menu that assigned to the template back to default template $query = 'UPDATE #__menu INNER JOIN #__template_styles' . ' ON #__template_styles.id = #__menu.template_style_id' . ' SET #__menu.template_style_id = 0' . ' WHERE #__template_styles.template = ' . $db->Quote(strtolower($name)) . ' AND #__template_styles.client_id = ' . $db->Quote($clientId); $db->setQuery($query); $db->execute(); $query = 'DELETE FROM #__template_styles' . ' WHERE template = ' . $db->Quote($name) . ' AND client_id = ' . $db->Quote($clientId); $db->setQuery($query); $db->execute(); $row->delete($row->extension_id); unset($row); return $retval; } /** * Discover existing but uninstalled templates * * @return array JExtensionTable list */ public function discover() { $results = array(); $site_list = JFolder::folders(JPATH_SITE . '/templates'); $admin_list = JFolder::folders(JPATH_ADMINISTRATOR . '/templates'); $site_info = JApplicationHelper::getClientInfo('site', true); $admin_info = JApplicationHelper::getClientInfo('administrator', true); foreach ($site_list as $template) { if ($template == 'system') { continue; // Ignore special system template } $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_SITE . "/templates/$template/templateDetails.xml"); $extension = JTable::getInstance('extension'); $extension->set('type', 'template'); $extension->set('client_id', $site_info->id); $extension->set('element', $template); $extension->set('name', $template); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $results[] = $extension; } foreach ($admin_list as $template) { if ($template == 'system') { continue; // Ignore special system template } $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_ADMINISTRATOR . "/templates/$template/templateDetails.xml"); $extension = JTable::getInstance('extension'); $extension->set('type', 'template'); $extension->set('client_id', $admin_info->id); $extension->set('element', $template); $extension->set('name', $template); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $results[] = $extension; } return $results; } /** * Discover_install * Perform an install for a discovered extension * * @return boolean * * @since 11.1 */ public function discover_install() { // Templates are one of the easiest // If its not in the extensions table we just add it $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id); $lang = JFactory::getLanguage(); $manifestPath = $client->path . '/templates/' . $this->parent->extension->element . '/templateDetails.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $description = (string) $this->parent->manifest->description; if ($description) { $this->parent->set('message', JText::_($description)); } else { $this->parent->set('message', ''); } $this->parent->setPath('manifest', $manifestPath); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->state = 0; $this->parent->extension->name = $manifest_details['name']; $this->parent->extension->enabled = 1; $data = new JObject; foreach ($manifest_details as $key => $value) { $data->set($key, $value); } $this->parent->extension->params = $this->parent->getParams(); if ($this->parent->extension->store()) { //insert record in #__template_styles $db = $this->parent->getDbo(); $query = $db->getQuery(true); $query->insert($db->quoteName('#__template_styles')); $debug = $lang->setDebug(false); $columns = array($db->quoteName('template'), $db->quoteName('client_id'), $db->quoteName('home'), $db->quoteName('title'), $db->quoteName('params') ); $query->columns($columns); $query->values( $db->Quote($this->parent->extension->element) . ',' . $db->Quote($this->parent->extension->client_id) . ',' . $db->Quote(0) . ',' . $db->Quote(JText::sprintf('JLIB_INSTALLER_DEFAULT_STYLE', $this->parent->extension->name)) . ',' . $db->Quote($this->parent->extension->params) ); $lang->setDebug($debug); $db->setQuery($query); $db->execute(); return $this->parent->extension->get('extension_id'); } else { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_TPL_DISCOVER_STORE_DETAILS')); return false; } } /** * Refreshes the extension table cache * * @return boolean Result of operation, true if updated, false on failure * * @since 11.1 */ public function refreshManifestCache() { // Need to find to find where the XML file is since we don't store this normally. $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id); $manifestPath = $client->path . '/templates/' . $this->parent->extension->element . '/templateDetails.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; try { return $this->parent->extension->store(); } catch (JException $e) { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_TPL_REFRESH_MANIFEST_CACHE')); return false; } } } adapters/component.php000066600000166374151372561050011114 0ustar00parent->getPath('source'); if (!$source) { $this->parent ->setPath( 'source', ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/components/' . $this->parent->extension->element ); } $this->manifest = $this->parent->getManifest(); $name = strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd')); if (substr($name, 0, 4) == "com_") { $extension = $name; } else { $extension = "com_$name"; } $lang = JFactory::getLanguage(); $source = $path ? $path : ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/components/' . $extension; if ($this->manifest->administration->files) { $element = $this->manifest->administration->files; } elseif ($this->manifest->files) { $element = $this->manifest->files; } else { $element = null; } if ($element) { $folder = (string) $element->attributes()->folder; if ($folder && file_exists("$path/$folder")) { $source = "$path/$folder"; } } $lang->load($extension . '.sys', $source, null, false, true) || $lang->load($extension . '.sys', JPATH_ADMINISTRATOR, null, false, true); } /** * Custom install method for components * * @return boolean True on success * * @since 11.1 */ public function install() { // Get a database connector object $db = $this->parent->getDbo(); // Get the extension manifest object $this->manifest = $this->parent->getManifest(); // Manifest Document Setup Section // Set the extension's name $name = strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd')); if (substr($name, 0, 4) == "com_") { $element = $name; } else { $element = "com_$name"; } $this->set('name', $name); $this->set('element', $element); // Get the component description $this->parent->set('message', JText::_((string) $this->manifest->description)); // Set the installation target paths $this->parent->setPath('extension_site', JPath::clean(JPATH_SITE . '/components/' . $this->get('element'))); $this->parent->setPath('extension_administrator', JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $this->get('element'))); // copy this as its used as a common base $this->parent->setPath('extension_root', $this->parent->getPath('extension_administrator')); // Basic Checks Section // Make sure that we have an admin element if (!$this->manifest->administration) { JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ERROR_COMP_INSTALL_ADMIN_ELEMENT')); return false; } // Filesystem Processing Section // If the component site or admin directory already exists, then we will assume that the component is already // installed or another component is using that directory. if (file_exists($this->parent->getPath('extension_site')) || file_exists($this->parent->getPath('extension_administrator'))) { // Look for an update function or update tag $updateElement = $this->manifest->update; // Upgrade manually set or // Update function available or // Update tag detected if ($this->parent->isUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'update')) || $updateElement) { return $this->update(); // transfer control to the update function } elseif (!$this->parent->isOverwrite()) { // Overwrite is set. // We didn't have overwrite set, find an update function or find an update tag so lets call it safe if (file_exists($this->parent->getPath('extension_site'))) { // If the site exists say so. JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_COMP_INSTALL_DIR_SITE', $this->parent->getPath('extension_site'))); } else { // If the admin exists say so JError::raiseWarning( 1, JText::sprintf('JLIB_INSTALLER_ERROR_COMP_INSTALL_DIR_ADMIN', $this->parent->getPath('extension_administrator')) ); } return false; } } // Installer Trigger Loading // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet) $manifestScript = (string) $this->manifest->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript; if (is_file($manifestScriptFile)) { // Load the file include_once $manifestScriptFile; } // Set the class name $classname = $this->get('element') . 'InstallerScript'; if (class_exists($classname)) { // Create a new instance $this->parent->manifestClass = new $classname($this); // And set this so we can copy it later $this->set('manifest_script', $manifestScript); // Note: if we don't find the class, don't bother to copy the file } } // Run preflight if possible (since we know we're not an update) ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight')) { if ($this->parent->manifestClass->preflight('install', $this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } // Create msg object; first use here $msg = ob_get_contents(); ob_end_clean(); // If the component directory does not exist, let's create it $created = false; if (!file_exists($this->parent->getPath('extension_site'))) { if (!$created = JFolder::create($this->parent->getPath('extension_site'))) { JError::raiseWarning( 1, JText::sprintf('JLIB_INSTALLER_ERROR_COMP_INSTALL_FAILED_TO_CREATE_DIRECTORY_SITE', $this->parent->getPath('extension_site')) ); return false; } } // Since we created the component directory and will want to remove it if we have to roll back // the installation, let's add it to the installation step stack if ($created) { $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_site'))); } // If the component admin directory does not exist, let's create it $created = false; if (!file_exists($this->parent->getPath('extension_administrator'))) { if (!$created = JFolder::create($this->parent->getPath('extension_administrator'))) { JError::raiseWarning( 1, JText::sprintf( 'JLIB_INSTALLER_ERROR_COMP_INSTALL_FAILED_TO_CREATE_DIRECTORY_ADMIN', $this->parent->getPath('extension_administrator') ) ); // Install failed, rollback any changes $this->parent->abort(); return false; } } /* * Since we created the component admin directory and we will want to remove it if we have to roll * back the installation, let's add it to the installation step stack */ if ($created) { $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_administrator'))); } // Copy site files if ($this->manifest->files) { if ($this->parent->parseFiles($this->manifest->files) === false) { // Install failed, rollback any changes $this->parent->abort(); return false; } } // Copy admin files if ($this->manifest->administration->files) { if ($this->parent->parseFiles($this->manifest->administration->files, 1) === false) { // Install failed, rollback any changes $this->parent->abort(); return false; } } // Parse optional tags $this->parent->parseMedia($this->manifest->media); $this->parent->parseLanguages($this->manifest->languages); $this->parent->parseLanguages($this->manifest->administration->languages, 1); // Deprecated install, remove after 1.6 // If there is an install file, lets copy it. $installFile = (string) $this->manifest->installfile; if ($installFile) { // Make sure it hasn't already been copied (this would be an error in the XML install file) if (!file_exists($this->parent->getPath('extension_administrator') . '/' . $installFile) || $this->parent->isOverwrite()) { $path['src'] = $this->parent->getPath('source') . '/' . $installFile; $path['dest'] = $this->parent->getPath('extension_administrator') . '/' . $installFile; if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_PHP_INSTALL')); return false; } } $this->set('install_script', $installFile); } // Deprecated uninstall, remove after 1.6 // If there is an uninstall file, let's copy it. $uninstallFile = (string) $this->manifest->uninstallfile; if ($uninstallFile) { // Make sure it hasn't already been copied (this would be an error in the XML install file) if (!file_exists($this->parent->getPath('extension_administrator') . '/' . $uninstallFile) || $this->parent->isOverwrite()) { $path['src'] = $this->parent->getPath('source') . '/' . $uninstallFile; $path['dest'] = $this->parent->getPath('extension_administrator') . '/' . $uninstallFile; if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_PHP_UNINSTALL')); return false; } } } // If there is a manifest script, let's copy it. if ($this->get('manifest_script')) { $path['src'] = $this->parent->getPath('source') . '/' . $this->get('manifest_script'); $path['dest'] = $this->parent->getPath('extension_administrator') . '/' . $this->get('manifest_script'); if (!file_exists($path['dest']) || $this->parent->isOverwrite()) { if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_MANIFEST')); return false; } } } /** * --------------------------------------------------------------------------------------------- * Database Processing Section * --------------------------------------------------------------------------------------------- */ /* * Let's run the install queries for the component * If Joomla 1.5 compatible, with discreet sql files - execute appropriate * file for utf-8 support or non-utf-8 support */ // Try for Joomla 1.5 type queries // Second argument is the utf compatible version attribute if (isset($this->manifest->install->sql)) { $utfresult = $this->parent->parseSQLFiles($this->manifest->install->sql); if ($utfresult === false) { // Install failed, rollback changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_INSTALL_SQL_ERROR', $db->stderr(true))); return false; } } /** * --------------------------------------------------------------------------------------------- * Custom Installation Script Section * --------------------------------------------------------------------------------------------- */ /* * If we have an install script, let's include it, execute the custom * install method, and append the return value from the custom install * method to the installation message. */ // Start legacy support if ($this->get('install_script')) { if (is_file($this->parent->getPath('extension_administrator') . '/' . $this->get('install_script')) || $this->parent->isOverwrite()) { $notdef = false; $ranwell = false; ob_start(); ob_implicit_flush(false); require_once $this->parent->getPath('extension_administrator') . '/' . $this->get('install_script'); if (function_exists('com_install')) { if (com_install() === false) { $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } $msg .= ob_get_contents(); // append messages ob_end_clean(); } } // End legacy support // Start Joomla! 1.6 ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'install')) { if ($this->parent->manifestClass->install($this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } // Append messages $msg .= ob_get_contents(); ob_end_clean(); /** * --------------------------------------------------------------------------------------------- * Finalization and Cleanup Section * --------------------------------------------------------------------------------------------- */ // Add an entry to the extension table with a whole heap of defaults $row = JTable::getInstance('extension'); $row->set('name', $this->get('name')); $row->set('type', 'component'); $row->set('element', $this->get('element')); $row->set('folder', ''); // There is no folder for components $row->set('enabled', 1); $row->set('protected', 0); $row->set('access', 0); $row->set('client_id', 1); $row->set('params', $this->parent->getParams()); $row->set('manifest_cache', $this->parent->generateManifestCache()); if (!$row->store()) { // Install failed, roll back changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_INSTALL_ROLLBACK', $db->stderr(true))); return false; } $eid = $db->insertid(); // Clobber any possible pending updates $update = JTable::getInstance('update'); $uid = $update->find(array('element' => $this->get('element'), 'type' => 'component', 'client_id' => '', 'folder' => '')); if ($uid) { $update->delete($uid); } // We will copy the manifest file to its appropriate place. if (!$this->parent->copyManifest()) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_COPY_SETUP')); return false; } // Time to build the admin menus if (!$this->_buildAdminMenus($row->extension_id)) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ABORT_COMP_BUILDADMINMENUS_FAILED')); //$this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_INSTALL_ROLLBACK', $db->stderr(true))); //return false; } // Set the schema version to be the latest update version if ($this->manifest->update) { $this->parent->setSchemaVersion($this->manifest->update->schemas, $eid); } // Register the component container just under root in the assets table. $asset = JTable::getInstance('Asset'); $asset->name = $row->element; $asset->parent_id = 1; $asset->rules = '{}'; $asset->title = $row->name; $asset->setLocation(1, 'last-child'); if (!$asset->store()) { // Install failed, roll back changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_INSTALL_ROLLBACK', $db->stderr(true))); return false; } // And now we run the postflight ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'postflight')) { $this->parent->manifestClass->postflight('install', $this); } // Append messages $msg .= ob_get_contents(); ob_end_clean(); if ($msg != '') { $this->parent->set('extension_message', $msg); } return $row->extension_id; } /** * Custom update method for components * * @return boolean True on success * * @since 11.1 */ public function update() { // Get a database connector object $db = $this->parent->getDbo(); // Set the overwrite setting $this->parent->setOverwrite(true); // Get the extension manifest object $this->manifest = $this->parent->getManifest(); /** * --------------------------------------------------------------------------------------------- * Manifest Document Setup Section * --------------------------------------------------------------------------------------------- */ // Set the extension's name $name = strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd')); if (substr($name, 0, 4) == "com_") { $element = $name; } else { $element = "com_$name"; } $this->set('name', $name); $this->set('element', $element); // Get the component description $description = (string) $this->manifest->description; if ($description) { $this->parent->set('message', JText::_($description)); } else { $this->parent->set('message', ''); } // Set the installation target paths $this->parent->setPath('extension_site', JPath::clean(JPATH_SITE . '/components/' . $this->get('element'))); $this->parent->setPath('extension_administrator', JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $this->get('element'))); $this->parent->setPath('extension_root', $this->parent->getPath('extension_administrator')); // copy this as its used as a common base /** * Hunt for the original XML file */ $old_manifest = null; // Create a new installer because findManifest sets stuff // Look in the administrator first $tmpInstaller = new JInstaller; $tmpInstaller->setPath('source', $this->parent->getPath('extension_administrator')); if (!$tmpInstaller->findManifest()) { // Then the site $tmpInstaller->setPath('source', $this->parent->getPath('extension_site')); if ($tmpInstaller->findManifest()) { $old_manifest = $tmpInstaller->getManifest(); } } else { $old_manifest = $tmpInstaller->getManifest(); } // Should do this above perhaps? if ($old_manifest) { $this->oldAdminFiles = $old_manifest->administration->files; $this->oldFiles = $old_manifest->files; } else { $this->oldAdminFiles = null; $this->oldFiles = null; } /** * --------------------------------------------------------------------------------------------- * Basic Checks Section * --------------------------------------------------------------------------------------------- */ // Make sure that we have an admin element if (!$this->manifest->administration) { JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ABORT_COMP_UPDATE_ADMIN_ELEMENT')); return false; } /** * --------------------------------------------------------------------------------------------- * Installer Trigger Loading * --------------------------------------------------------------------------------------------- */ // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet) $manifestScript = (string) $this->manifest->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript; if (is_file($manifestScriptFile)) { // Load the file include_once $manifestScriptFile; } // Set the class name $classname = $element . 'InstallerScript'; if (class_exists($classname)) { // Create a new instance $this->parent->manifestClass = new $classname($this); // And set this so we can copy it later $this->set('manifest_script', $manifestScript); // Note: if we don't find the class, don't bother to copy the file } } // Run preflight if possible (since we know we're not an update) ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight')) { if ($this->parent->manifestClass->preflight('update', $this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } // Create msg object; first use here $msg = ob_get_contents(); ob_end_clean(); /** * --------------------------------------------------------------------------------------------- * Filesystem Processing Section * --------------------------------------------------------------------------------------------- */ // If the component directory does not exist, let's create it $created = false; if (!file_exists($this->parent->getPath('extension_site'))) { if (!$created = JFolder::create($this->parent->getPath('extension_site'))) { JError::raiseWarning( 1, JText::sprintf('JLIB_INSTALLER_ERROR_COMP_UPDATE_FAILED_TO_CREATE_DIRECTORY_SITE', $this->parent->getPath('extension_site')) ); return false; } } /* * Since we created the component directory and will want to remove it if we have to roll back * the installation, lets add it to the installation step stack */ if ($created) { $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_site'))); } // If the component admin directory does not exist, let's create it $created = false; if (!file_exists($this->parent->getPath('extension_administrator'))) { if (!$created = JFolder::create($this->parent->getPath('extension_administrator'))) { JError::raiseWarning( 1, JText::sprintf( 'JLIB_INSTALLER_ERROR_COMP_UPDATE_FAILED_TO_CREATE_DIRECTORY_ADMIN', $this->parent->getPath('extension_administrator') ) ); // Install failed, rollback any changes $this->parent->abort(); return false; } } /* * Since we created the component admin directory and we will want to remove it if we have to roll * back the installation, let's add it to the installation step stack */ if ($created) { $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_administrator'))); } // Find files to copy if ($this->manifest->files) { if ($this->parent->parseFiles($this->manifest->files, 0, $this->oldFiles) === false) { // Install failed, rollback any changes $this->parent->abort(); return false; } } if ($this->manifest->administration->files) { if ($this->parent->parseFiles($this->manifest->administration->files, 1, $this->oldAdminFiles) === false) { // Install failed, rollback any changes $this->parent->abort(); return false; } } // Parse optional tags $this->parent->parseMedia($this->manifest->media); $this->parent->parseLanguages($this->manifest->languages); $this->parent->parseLanguages($this->manifest->administration->languages, 1); // Deprecated install, remove after 1.6 // If there is an install file, lets copy it. $installFile = (string) $this->manifest->installfile; if ($installFile) { // Make sure it hasn't already been copied (this would be an error in the XML install file) if (!file_exists($this->parent->getPath('extension_administrator') . '/' . $installFile) || $this->parent->isOverwrite()) { $path['src'] = $this->parent->getPath('source') . '/' . $installFile; $path['dest'] = $this->parent->getPath('extension_administrator') . '/' . $installFile; if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_UPDATE_PHP_INSTALL')); return false; } } $this->set('install_script', $installFile); } // Deprecated uninstall, remove after 1.6 // If there is an uninstall file, lets copy it. $uninstallFile = (string) $this->manifest->uninstallfile; if ($uninstallFile) { // Make sure it hasn't already been copied (this would be an error in the XML install file) if (!file_exists($this->parent->getPath('extension_administrator') . '/' . $uninstallFile) || $this->parent->isOverwrite()) { $path['src'] = $this->parent->getPath('source') . '/' . $uninstallFile; $path['dest'] = $this->parent->getPath('extension_administrator') . '/' . $uninstallFile; if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_UPDATE_PHP_UNINSTALL')); return false; } } } // If there is a manifest script, let's copy it. if ($this->get('manifest_script')) { $path['src'] = $this->parent->getPath('source') . '/' . $this->get('manifest_script'); $path['dest'] = $this->parent->getPath('extension_administrator') . '/' . $this->get('manifest_script'); if (!file_exists($path['dest']) || $this->parent->isOverwrite()) { if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_UPDATE_MANIFEST')); return false; } } } /** * --------------------------------------------------------------------------------------------- * Database Processing Section * --------------------------------------------------------------------------------------------- */ /* * Let's run the update queries for the component */ $row = JTable::getInstance('extension'); $eid = $row->find(array('element' => strtolower($this->get('element')), 'type' => 'component')); if ($this->manifest->update) { $result = $this->parent->parseSchemaUpdates($this->manifest->update->schemas, $eid); if ($result === false) { // Install failed, rollback changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_UPDATE_SQL_ERROR', $db->stderr(true))); return false; } } // Time to build the admin menus if (!$this->_buildAdminMenus($eid)) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ABORT_COMP_BUILDADMINMENUS_FAILED')); // $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_INSTALL_ROLLBACK', $db->stderr(true))); // Return false; } /** * --------------------------------------------------------------------------------------------- * Custom Installation Script Section * --------------------------------------------------------------------------------------------- */ /* * If we have an install script, let's include it, execute the custom * install method, and append the return value from the custom install * method to the installation message. */ // Start legacy support if ($this->get('install_script')) { if (is_file($this->parent->getPath('extension_administrator') . '/' . $this->get('install_script')) || $this->parent->isOverwrite()) { $notdef = false; $ranwell = false; ob_start(); ob_implicit_flush(false); require_once $this->parent->getPath('extension_administrator') . '/' . $this->get('install_script'); if (function_exists('com_install')) { if (com_install() === false) { $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } $msg .= ob_get_contents(); // append messages ob_end_clean(); } } /* * If we have an update script, let's include it, execute the custom * update method, and append the return value from the custom update * method to the installation message. */ // Start Joomla! 1.6 ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'update')) { if ($this->parent->manifestClass->update($this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } // Append messages $msg .= ob_get_contents(); ob_end_clean(); /** * --------------------------------------------------------------------------------------------- * Finalization and Cleanup Section * --------------------------------------------------------------------------------------------- */ // Clobber any possible pending updates $update = JTable::getInstance('update'); $uid = $update->find(array('element' => $this->get('element'), 'type' => 'component', 'client_id' => '', 'folder' => '')); if ($uid) { $update->delete($uid); } // Update an entry to the extension table if ($eid) { $row->load($eid); } else { // Set the defaults // There is no folder for components $row->folder = ''; $row->enabled = 1; $row->protected = 0; $row->access = 1; $row->client_id = 1; $row->params = $this->parent->getParams(); } $row->name = $this->get('name'); $row->type = 'component'; $row->element = $this->get('element'); $row->manifest_cache = $this->parent->generateManifestCache(); if (!$row->store()) { // Install failed, roll back changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_UPDATE_ROLLBACK', $db->stderr(true))); return false; } // We will copy the manifest file to its appropriate place. if (!$this->parent->copyManifest()) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_UPDATE_COPY_SETUP')); return false; } // And now we run the postflight ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'postflight')) { $this->parent->manifestClass->postflight('update', $this); } // Append messages $msg .= ob_get_contents(); ob_end_clean(); if ($msg != '') { $this->parent->set('extension_message', $msg); } return $row->extension_id; } /** * Custom uninstall method for components * * @param integer $id The unique extension id of the component to uninstall * * @return mixed Return value for uninstall method in component uninstall file * * @since 11.1 */ public function uninstall($id) { // Initialise variables. $db = $this->parent->getDbo(); $row = null; $retval = true; // First order of business will be to load the component object table from the database. // This should give us the necessary information to proceed. $row = JTable::getInstance('extension'); if (!$row->load((int) $id)) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_ERRORUNKOWNEXTENSION')); return false; } // Is the component we are trying to uninstall a core one? // Because that is not a good idea... if ($row->protected) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_WARNCORECOMPONENT')); return false; } // Get the admin and site paths for the component $this->parent->setPath('extension_administrator', JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $row->element)); $this->parent->setPath('extension_site', JPath::clean(JPATH_SITE . '/components/' . $row->element)); $this->parent->setPath('extension_root', $this->parent->getPath('extension_administrator')); // copy this as its used as a common base /** * --------------------------------------------------------------------------------------------- * Manifest Document Setup Section * --------------------------------------------------------------------------------------------- */ // Find and load the XML install file for the component $this->parent->setPath('source', $this->parent->getPath('extension_administrator')); // Get the package manifest object // We do findManifest to avoid problem when uninstalling a list of extension: getManifest cache its manifest file $this->parent->findManifest(); $this->manifest = $this->parent->getManifest(); if (!$this->manifest) { // Make sure we delete the folders if no manifest exists JFolder::delete($this->parent->getPath('extension_administrator')); JFolder::delete($this->parent->getPath('extension_site')); // Remove the menu $this->_removeAdminMenus($row); // Raise a warning JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_ERRORREMOVEMANUALLY')); // Return return false; } // Set the extensions name $name = strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd')); if (substr($name, 0, 4) == "com_") { $element = $name; } else { $element = "com_$name"; } $this->set('name', $name); $this->set('element', $element); // Attempt to load the admin language file; might have uninstall strings $this->loadLanguage(JPATH_ADMINISTRATOR . '/components/' . $element); /** * --------------------------------------------------------------------------------------------- * Installer Trigger Loading and Uninstall * --------------------------------------------------------------------------------------------- */ // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet) $scriptFile = (string) $this->manifest->scriptfile; if ($scriptFile) { $manifestScriptFile = $this->parent->getPath('source') . '/' . $scriptFile; if (is_file($manifestScriptFile)) { // load the file include_once $manifestScriptFile; } // Set the class name $classname = $row->element . 'InstallerScript'; if (class_exists($classname)) { // create a new instance $this->parent->manifestClass = new $classname($this); // and set this so we can copy it later $this->set('manifest_script', $scriptFile); // Note: if we don't find the class, don't bother to copy the file } } ob_start(); ob_implicit_flush(false); // run uninstall if possible if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'uninstall')) { $this->parent->manifestClass->uninstall($this); } $msg = ob_get_contents(); ob_end_clean(); /** * --------------------------------------------------------------------------------------------- * Custom Uninstallation Script Section; Legacy CMS 1.5 Support * --------------------------------------------------------------------------------------------- */ // Now let's load the uninstall file if there is one and execute the uninstall function if it exists. $uninstallFile = (string) $this->manifest->uninstallfile; if ($uninstallFile) { // Element exists, does the file exist? if (is_file($this->parent->getPath('extension_administrator') . '/' . $uninstallFile)) { ob_start(); ob_implicit_flush(false); require_once $this->parent->getPath('extension_administrator') . '/' . $uninstallFile; if (function_exists('com_uninstall')) { if (com_uninstall() === false) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_CUSTOM')); $retval = false; } } // append this in case there was something else $msg .= ob_get_contents(); ob_end_clean(); } } if ($msg != '') { $this->parent->set('extension_message', $msg); } /** * --------------------------------------------------------------------------------------------- * Database Processing Section * --------------------------------------------------------------------------------------------- */ /* * Let's run the uninstall queries for the component * If Joomla CMS 1.5 compatible, with discrete sql files - execute appropriate * file for utf-8 support or non-utf support */ // Try for Joomla 1.5 type queries // Second argument is the utf compatible version attribute if (isset($this->manifest->uninstall->sql)) { $utfresult = $this->parent->parseSQLFiles($this->manifest->uninstall->sql); if ($utfresult === false) { // Install failed, rollback changes JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_SQL_ERROR', $db->stderr(true))); $retval = false; } } $this->_removeAdminMenus($row); /** * --------------------------------------------------------------------------------------------- * Filesystem Processing Section * --------------------------------------------------------------------------------------------- */ // Let's remove those language files and media in the JROOT/images/ folder that are // associated with the component we are uninstalling $this->parent->removeFiles($this->manifest->media); $this->parent->removeFiles($this->manifest->languages); $this->parent->removeFiles($this->manifest->administration->languages, 1); // Remove the schema version $query = $db->getQuery(true); $query->delete()->from('#__schemas')->where('extension_id = ' . $id); $db->setQuery($query); $db->execute(); // Remove the component container in the assets table. $asset = JTable::getInstance('Asset'); if ($asset->loadByName($element)) { $asset->delete(); } // Remove categories for this component $query = $db->getQuery(true); $query->delete()->from('#__categories')->where('extension=' . $db->quote($element), 'OR') ->where('extension LIKE ' . $db->quote($element . '.%')); $db->setQuery($query); $db->execute(); // Check for errors. if ($db->getErrorNum()) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_FAILED_DELETE_CATEGORIES')); $this->setError($db->getErrorMsg()); $retval = false; } // Clobber any possible pending updates $update = JTable::getInstance('update'); $uid = $update->find(array('element' => $row->element, 'type' => 'component', 'client_id' => '', 'folder' => '')); if ($uid) { $update->delete($uid); } // Now we need to delete the installation directories. This is the final step in uninstalling the component. if (trim($row->element)) { // Delete the component site directory if (is_dir($this->parent->getPath('extension_site'))) { if (!JFolder::delete($this->parent->getPath('extension_site'))) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_FAILED_REMOVE_DIRECTORY_SITE')); $retval = false; } } // Delete the component admin directory if (is_dir($this->parent->getPath('extension_administrator'))) { if (!JFolder::delete($this->parent->getPath('extension_administrator'))) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_FAILED_REMOVE_DIRECTORY_ADMIN')); $retval = false; } } // Now we will no longer need the extension object, so let's delete it and free up memory $row->delete($row->extension_id); unset($row); return $retval; } else { // No component option defined... cannot delete what we don't know about JError::raiseWarning(100, 'JLIB_INSTALLER_ERROR_COMP_UNINSTALL_NO_OPTION'); return false; } } /** * Method to build menu database entries for a component * * @return boolean True if successful * * @since 11.1 */ protected function _buildAdminMenus() { // Initialise variables. $db = $this->parent->getDbo(); $table = JTable::getInstance('menu'); $option = $this->get('element'); // If a component exists with this option in the table then we don't need to add menus $query = $db->getQuery(true); $query->select('m.id, e.extension_id'); $query->from('#__menu AS m'); $query->leftJoin('#__extensions AS e ON m.component_id = e.extension_id'); $query->where('m.parent_id = 1'); $query->where("m.client_id = 1"); $query->where('e.element = ' . $db->quote($option)); $db->setQuery($query); $componentrow = $db->loadObject(); // Check if menu items exist if ($componentrow) { // Don't do anything if overwrite has not been enabled if (!$this->parent->isOverwrite()) { return true; } // Remove existing menu items if overwrite has been enabled if ($option) { $this->_removeAdminMenus($componentrow); // If something goes wrong, theres no way to rollback TODO: Search for better solution } $component_id = $componentrow->extension_id; } else { // Lets Find the extension id $query->clear(); $query->select('e.extension_id'); $query->from('#__extensions AS e'); $query->where('e.element = ' . $db->quote($option)); $db->setQuery($query); $component_id = $db->loadResult(); // TODO Find Some better way to discover the component_id } // Ok, now its time to handle the menus. Start with the component root menu, then handle submenus. $menuElement = $this->manifest->administration->menu; if ($menuElement) { $data = array(); $data['menutype'] = 'main'; $data['client_id'] = 1; $data['title'] = (string) $menuElement; $data['alias'] = (string) $menuElement; $data['link'] = 'index.php?option=' . $option; $data['type'] = 'component'; $data['published'] = 0; $data['parent_id'] = 1; $data['component_id'] = $component_id; $data['img'] = ((string) $menuElement->attributes()->img) ? (string) $menuElement->attributes()->img : 'class:component'; $data['home'] = 0; if (!$table->setLocation(1, 'last-child') || !$table->bind($data) || !$table->check() || !$table->store()) { // The menu item already exists. Delete it and retry instead of throwing an error. $query = $db->getQuery(true); $query->select('id'); $query->from('#__menu'); $query->where('menutype = '.$db->quote('main')); $query->where('client_id = 1'); $query->where('link = '.$db->quote('index.php?option='.$option)); $query->where('type = '.$db->quote('component')); $query->where('parent_id = 1'); $query->where('home = 0'); $db->setQuery($query); $menu_id = $db->loadResult(); if(!$menu_id) { // Oops! Could not get the menu ID. Go back and rollback changes. JError::raiseWarning(1, $table->getError()); return false; } else { // Remove the old menu item $query = $db->getQuery(true); $query->delete('#__menu'); $query->where('id = '.(int)$menu_id); $db->setQuery($query); $db->query(); // Retry creating the menu item if (!$table->setLocation(1, 'last-child') || !$table->bind($data) || !$table->check() || !$table->store()) { // Install failed, rollback changes return false; } } } /* * Since we have created a menu item, we add it to the installation step stack * so that if we have to rollback the changes we can undo it. */ $this->parent->pushStep(array('type' => 'menu', 'id' => $component_id)); } // No menu element was specified, Let's make a generic menu item else { $data = array(); $data['menutype'] = 'main'; $data['client_id'] = 1; $data['title'] = $option; $data['alias'] = $option; $data['link'] = 'index.php?option=' . $option; $data['type'] = 'component'; $data['published'] = 0; $data['parent_id'] = 1; $data['component_id'] = $component_id; $data['img'] = 'class:component'; $data['home'] = 0; if (!$table->setLocation(1, 'last-child') || !$table->bind($data) || !$table->check() || !$table->store()) { // Install failed, warn user and rollback changes JError::raiseWarning(1, $table->getError()); return false; } /* * Since we have created a menu item, we add it to the installation step stack * so that if we have to rollback the changes we can undo it. */ $this->parent->pushStep(array('type' => 'menu', 'id' => $component_id)); } $parent_id = $table->id; /* * Process SubMenus */ if (!$this->manifest->administration->submenu) { return true; } $parent_id = $table->id; foreach ($this->manifest->administration->submenu->menu as $child) { $data = array(); $data['menutype'] = 'main'; $data['client_id'] = 1; $data['title'] = (string) $child; $data['alias'] = (string) $child; $data['type'] = 'component'; $data['published'] = 0; $data['parent_id'] = $parent_id; $data['component_id'] = $component_id; $data['img'] = ((string) $child->attributes()->img) ? (string) $child->attributes()->img : 'class:component'; $data['home'] = 0; // Set the sub menu link if ((string) $child->attributes()->link) { $data['link'] = 'index.php?' . $child->attributes()->link; } else { $request = array(); if ((string) $child->attributes()->act) { $request[] = 'act=' . $child->attributes()->act; } if ((string) $child->attributes()->task) { $request[] = 'task=' . $child->attributes()->task; } if ((string) $child->attributes()->controller) { $request[] = 'controller=' . $child->attributes()->controller; } if ((string) $child->attributes()->view) { $request[] = 'view=' . $child->attributes()->view; } if ((string) $child->attributes()->layout) { $request[] = 'layout=' . $child->attributes()->layout; } if ((string) $child->attributes()->sub) { $request[] = 'sub=' . $child->attributes()->sub; } $qstring = (count($request)) ? '&' . implode('&', $request) : ''; $data['link'] = 'index.php?option=' . $option . $qstring; } $table = JTable::getInstance('menu'); if (!$table->setLocation($parent_id, 'last-child') || !$table->bind($data) || !$table->check() || !$table->store()) { // Install failed, rollback changes return false; } /* * Since we have created a menu item, we add it to the installation step stack * so that if we have to rollback the changes we can undo it. */ $this->parent->pushStep(array('type' => 'menu', 'id' => $component_id)); } return true; } /** * Method to remove admin menu references to a component * * @param object &$row Component table object. * * @return boolean True if successful. * * @since 11.1 */ protected function _removeAdminMenus(&$row) { // Initialise Variables $db = $this->parent->getDbo(); $table = JTable::getInstance('menu'); $id = $row->extension_id; // Get the ids of the menu items $query = $db->getQuery(true); $query->select('id'); $query->from('#__menu'); $query->where($query->qn('client_id') . ' = 1'); $query->where($query->qn('component_id') . ' = ' . (int) $id); $db->setQuery($query); $ids = $db->loadColumn(); // Check for error if ($error = $db->getErrorMsg()) { JError::raiseWarning('', JText::_('JLIB_INSTALLER_ERROR_COMP_REMOVING_ADMIN_MENUS_FAILED')); if ($error && $error != 1) { JError::raiseWarning(100, $error); } return false; } elseif (!empty($ids)) { // Iterate the items to delete each one. foreach ($ids as $menuid) { if (!$table->delete((int) $menuid)) { $this->setError($table->getError()); return false; } } // Rebuild the whole tree $table->rebuild(); } return true; } /** * Custom rollback method * - Roll back the component menu item * * @param array $step Installation step to rollback. * * @return boolean True on success * * @since 11.1 */ protected function _rollback_menu($step) { return $this->_removeAdminMenus((object) array('extension_id' => $step['id'])); } /** * Discover unregistered extensions. * * @return array A list of extensions. * * @since 11.1 */ public function discover() { $results = array(); $site_components = JFolder::folders(JPATH_SITE . '/components'); $admin_components = JFolder::folders(JPATH_ADMINISTRATOR . '/components'); foreach ($site_components as $component) { if (file_exists(JPATH_SITE . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml')) { $manifest_details = JApplicationHelper::parseXMLInstallFile( JPATH_SITE . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml' ); $extension = JTable::getInstance('extension'); $extension->set('type', 'component'); $extension->set('client_id', 0); $extension->set('element', $component); $extension->set('name', $component); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $results[] = $extension; } } foreach ($admin_components as $component) { if (file_exists(JPATH_ADMINISTRATOR . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml')) { $manifest_details = JApplicationHelper::parseXMLInstallFile( JPATH_ADMINISTRATOR . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml' ); $extension = JTable::getInstance('extension'); $extension->set('type', 'component'); $extension->set('client_id', 1); $extension->set('element', $component); $extension->set('name', $component); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $results[] = $extension; } } return $results; } /** * Install unregistered extensions that have been discovered. * * @return mixed * * @since 11.1 */ public function discover_install() { // Need to find to find where the XML file is since we don't store this normally $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id); $short_element = str_replace('com_', '', $this->parent->extension->element); $manifestPath = $client->path . '/components/' . $this->parent->extension->element . '/' . $short_element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $this->parent->setPath('source', $client->path . '/components/' . $this->parent->extension->element); $this->parent->setPath('extension_root', $this->parent->getPath('source')); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->state = 0; $this->parent->extension->name = $manifest_details['name']; $this->parent->extension->enabled = 1; $this->parent->extension->params = $this->parent->getParams(); try { $this->parent->extension->store(); } catch (JException $e) { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_COMP_DISCOVER_STORE_DETAILS')); return false; } // now we need to run any SQL it has, languages, media or menu stuff // Get a database connector object $db = $this->parent->getDbo(); // Get the extension manifest object $this->manifest = $this->parent->getManifest(); /** * --------------------------------------------------------------------------------------------- * Manifest Document Setup Section * --------------------------------------------------------------------------------------------- */ // Set the extensions name $name = strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd')); if (substr($name, 0, 4) == "com_") { $element = $name; } else { $element = "com_$name"; } $this->set('name', $name); $this->set('element', $element); // Get the component description $description = (string) $this->manifest->description; if ($description) { $this->parent->set('message', JText::_((string) $description)); } else { $this->parent->set('message', ''); } // Set the installation target paths $this->parent->setPath('extension_site', JPath::clean(JPATH_SITE . '/components/' . $this->get('element'))); $this->parent->setPath('extension_administrator', JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $this->get('element'))); $this->parent->setPath('extension_root', $this->parent->getPath('extension_administrator')); // copy this as its used as a common base /** * --------------------------------------------------------------------------------------------- * Basic Checks Section * --------------------------------------------------------------------------------------------- */ // Make sure that we have an admin element if (!$this->manifest->administration) { JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ERROR_COMP_INSTALL_ADMIN_ELEMENT')); return false; } /** * --------------------------------------------------------------------------------------------- * Installer Trigger Loading * --------------------------------------------------------------------------------------------- */ // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet) $manifestScript = (string) $this->manifest->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript; if (is_file($manifestScriptFile)) { // load the file include_once $manifestScriptFile; } // Set the class name $classname = $element . 'InstallerScript'; if (class_exists($classname)) { // create a new instance $this->parent->manifestClass = new $classname($this); // and set this so we can copy it later $this->set('manifest_script', $manifestScript); // Note: if we don't find the class, don't bother to copy the file } } // Run preflight if possible (since we know we're not an update) ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight')) { if ($this->parent->manifestClass->preflight('discover_install', $this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } $msg = ob_get_contents(); // create msg object; first use here ob_end_clean(); // Normally we would copy files and create directories, lets skip to the optional files // Note: need to dereference things! // Parse optional tags //$this->parent->parseMedia($this->manifest->media); // We don't do language because 1.6 suggests moving to extension based languages //$this->parent->parseLanguages($this->manifest->languages); //$this->parent->parseLanguages($this->manifest->administration->languages, 1); /** * --------------------------------------------------------------------------------------------- * Database Processing Section * --------------------------------------------------------------------------------------------- */ /* * Let's run the install queries for the component * If Joomla 1.5 compatible, with discreet sql files - execute appropriate * file for utf-8 support or non-utf-8 support */ // Try for Joomla 1.5 type queries // second argument is the utf compatible version attribute if (isset($this->manifest->install->sql)) { $utfresult = $this->parent->parseSQLFiles($this->manifest->install->sql); if ($utfresult === false) { // Install failed, rollback changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_INSTALL_SQL_ERROR', $db->stderr(true))); return false; } } // Time to build the admin menus if (!$this->_buildAdminMenus($this->parent->extension->extension_id)) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ABORT_COMP_BUILDADMINMENUS_FAILED')); //$this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_INSTALL_ROLLBACK', $db->stderr(true))); //return false; } /** * --------------------------------------------------------------------------------------------- * Custom Installation Script Section * --------------------------------------------------------------------------------------------- */ /* * If we have an install script, lets include it, execute the custom * install method, and append the return value from the custom install * method to the installation message. */ // start legacy support if ($this->get('install_script')) { if (is_file($this->parent->getPath('extension_administrator') . '/' . $this->get('install_script'))) { ob_start(); ob_implicit_flush(false); require_once $this->parent->getPath('extension_administrator') . '/' . $this->get('install_script'); if (function_exists('com_install')) { if (com_install() === false) { $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } // Append messages $msg .= ob_get_contents(); ob_end_clean(); } } // End legacy support // Start Joomla! 1.6 ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'install')) { if ($this->parent->manifestClass->install($this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } $msg .= ob_get_contents(); // append messages ob_end_clean(); /** * --------------------------------------------------------------------------------------------- * Finalization and Cleanup Section * --------------------------------------------------------------------------------------------- */ // Clobber any possible pending updates $update = JTable::getInstance('update'); $uid = $update->find(array('element' => $this->get('element'), 'type' => 'component', 'client_id' => '', 'folder' => '')); if ($uid) { $update->delete($uid); } // And now we run the postflight ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'postflight')) { $this->parent->manifestClass->postflight('discover_install', $this); } $msg .= ob_get_contents(); // append messages ob_end_clean(); if ($msg != '') { $this->parent->set('extension_message', $msg); } return $this->parent->extension->extension_id; } /** * Refreshes the extension table cache * * @return boolean Result of operation, true if updated, false on failure * * @since 11.1 */ public function refreshManifestCache() { // Need to find to find where the XML file is since we don't store this normally $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id); $short_element = str_replace('com_', '', $this->parent->extension->element); $manifestPath = $client->path . '/components/' . $this->parent->extension->element . '/' . $short_element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; try { return $this->parent->extension->store(); } catch (JException $e) { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_COMP_REFRESH_MANIFEST_CACHE')); return false; } } } adapters/language.php000066600000047303151372561050010663 0ustar00parent->getPath('source'); if (!$source) { $this->parent ->setPath( 'source', ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/language/' . $this->parent->extension->element ); } $this->manifest = $this->parent->getManifest(); $root = $this->manifest->document; // Get the client application target if ((string) $this->manifest->attributes()->client == 'both') { JError::raiseWarning(42, JText::_('JLIB_INSTALLER_ERROR_DEPRECATED_FORMAT')); $element = $this->manifest->site->files; if (!$this->_install('site', JPATH_SITE, 0, $element)) { return false; } $element = $this->manifest->administration->files; if (!$this->_install('administrator', JPATH_ADMINISTRATOR, 1, $element)) { return false; } // This causes an issue because we have two eid's, *sigh* nasty hacks! return true; } elseif ($cname = (string) $this->manifest->attributes()->client) { // Attempt to map the client to a base path $client = JApplicationHelper::getClientInfo($cname, true); if ($client === null) { $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_UNKNOWN_CLIENT_TYPE', $cname))); return false; } $basePath = $client->path; $clientId = $client->id; $element = $this->manifest->files; return $this->_install($cname, $basePath, $clientId, $element); } else { // No client attribute was found so we assume the site as the client $cname = 'site'; $basePath = JPATH_SITE; $clientId = 0; $element = $this->manifest->files; return $this->_install($cname, $basePath, $clientId, $element); } } /** * Install function that is designed to handle individual clients * * @param string $cname Cname @todo: not used * @param string $basePath The base name. * @param integer $clientId The client id. * @param object &$element The XML element. * * @return boolean * * @since 11.1 */ protected function _install($cname, $basePath, $clientId, &$element) { $this->manifest = $this->parent->getManifest(); // Get the language name // Set the extensions name $name = JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd'); $this->set('name', $name); // Get the Language tag [ISO tag, eg. en-GB] $tag = (string) $this->manifest->tag; // Check if we found the tag - if we didn't, we may be trying to install from an older language package if (!$tag) { $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::_('JLIB_INSTALLER_ERROR_NO_LANGUAGE_TAG'))); return false; } $this->set('tag', $tag); // Set the language installation path $this->parent->setPath('extension_site', $basePath . '/language/' . $tag); // Do we have a meta file in the file list? In other words... is this a core language pack? if ($element && count($element->children())) { $files = $element->children(); foreach ($files as $file) { if ((string) $file->attributes()->file == 'meta') { $this->_core = true; break; } } } // Either we are installing a core pack or a core pack must exist for the language we are installing. if (!$this->_core) { if (!JFile::exists($this->parent->getPath('extension_site') . '/' . $this->get('tag') . '.xml')) { $this->parent ->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_NO_CORE_LANGUAGE', $this->get('tag')))); return false; } } // If the language directory does not exist, let's create it $created = false; if (!file_exists($this->parent->getPath('extension_site'))) { if (!$created = JFolder::create($this->parent->getPath('extension_site'))) { $this->parent ->abort( JText::sprintf( 'JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_FOLDER_FAILED', $this->parent->getPath('extension_site')) ) ); return false; } } else { // Look for an update function or update tag $updateElement = $this->manifest->update; // Upgrade manually set or // Update function available or // Update tag detected if ($this->parent->isUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'update')) || $updateElement) { return $this->update(); // transfer control to the update function } elseif (!$this->parent->isOverwrite()) { // Overwrite is set // We didn't have overwrite set, find an update function or find an update tag so lets call it safe if (file_exists($this->parent->getPath('extension_site'))) { // If the site exists say so. JError::raiseWarning( 1, JText::sprintf( 'JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_FOLDER_IN_USE', $this->parent->getPath('extension_site')) ) ); } else { // If the admin exists say so. JError::raiseWarning( 1, JText::sprintf( 'JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_FOLDER_IN_USE', $this->parent->getPath('extension_administrator')) ) ); } return false; } } /* * If we created the language directory we will want to remove it if we * have to roll back the installation, so let's add it to the installation * step stack */ if ($created) { $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_site'))); } // Copy all the necessary files if ($this->parent->parseFiles($element) === false) { // Install failed, rollback changes $this->parent->abort(); return false; } // Parse optional tags $this->parent->parseMedia($this->manifest->media); // Copy all the necessary font files to the common pdf_fonts directory $this->parent->setPath('extension_site', $basePath . '/language/pdf_fonts'); $overwrite = $this->parent->setOverwrite(true); if ($this->parent->parseFiles($this->manifest->fonts) === false) { // Install failed, rollback changes $this->parent->abort(); return false; } $this->parent->setOverwrite($overwrite); // Get the language description $description = (string) $this->manifest->description; if ($description) { $this->parent->set('message', JText::_($description)); } else { $this->parent->set('message', ''); } // Add an entry to the extension table with a whole heap of defaults $row = JTable::getInstance('extension'); $row->set('name', $this->get('name')); $row->set('type', 'language'); $row->set('element', $this->get('tag')); // There is no folder for languages $row->set('folder', ''); $row->set('enabled', 1); $row->set('protected', 0); $row->set('access', 0); $row->set('client_id', $clientId); $row->set('params', $this->parent->getParams()); $row->set('manifest_cache', $this->parent->generateManifestCache()); if (!$row->store()) { // Install failed, roll back changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', $row->getError())); return false; } // Clobber any possible pending updates $update = JTable::getInstance('update'); $uid = $update->find(array('element' => $this->get('tag'), 'type' => 'language', 'client_id' => '', 'folder' => '')); if ($uid) { $update->delete($uid); } return $row->get('extension_id'); } /** * Custom update method * * @return boolean True on success, false on failure * * @since 11.1 */ public function update() { $xml = $this->parent->getManifest(); $this->manifest = $xml; $cname = $xml->attributes()->client; // Attempt to map the client to a base path $client = JApplicationHelper::getClientInfo($cname, true); if ($client === null || (empty($cname) && $cname !== 0)) { $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_UNKNOWN_CLIENT_TYPE', $cname))); return false; } $basePath = $client->path; $clientId = $client->id; // Get the language name // Set the extensions name $name = (string) $this->manifest->name; $name = JFilterInput::getInstance()->clean($name, 'cmd'); $this->set('name', $name); // Get the Language tag [ISO tag, eg. en-GB] $tag = (string) $xml->tag; // Check if we found the tag - if we didn't, we may be trying to install from an older language package if (!$tag) { $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::_('JLIB_INSTALLER_ERROR_NO_LANGUAGE_TAG'))); return false; } $this->set('tag', $tag); $folder = $tag; // Set the language installation path $this->parent->setPath('extension_site', $basePath . '/language/' . $this->get('tag')); // Do we have a meta file in the file list? In other words... is this a core language pack? if (count($xml->files->children())) { foreach ($xml->files->children() as $file) { if ((string) $file->attributes()->file == 'meta') { $this->_core = true; break; } } } // Either we are installing a core pack or a core pack must exist for the language we are installing. if (!$this->_core) { if (!JFile::exists($this->parent->getPath('extension_site') . '/' . $this->get('tag') . '.xml')) { $this->parent ->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_NO_CORE_LANGUAGE', $this->get('tag')))); return false; } } // Copy all the necessary files if ($this->parent->parseFiles($xml->files) === false) { // Install failed, rollback changes $this->parent->abort(); return false; } // Parse optional tags $this->parent->parseMedia($xml->media); // Copy all the necessary font files to the common pdf_fonts directory $this->parent->setPath('extension_site', $basePath . '/language/pdf_fonts'); $overwrite = $this->parent->setOverwrite(true); if ($this->parent->parseFiles($xml->fonts) === false) { // Install failed, rollback changes $this->parent->abort(); return false; } $this->parent->setOverwrite($overwrite); // Get the language description and set it as message $this->parent->set('message', (string) $xml->description); // Finalization and Cleanup Section // Clobber any possible pending updates $update = JTable::getInstance('update'); $uid = $update->find(array('element' => $this->get('tag'), 'type' => 'language', 'client_id' => $clientId)); if ($uid) { $update->delete($uid); } // Update an entry to the extension table $row = JTable::getInstance('extension'); $eid = $row->find(array('element' => strtolower($this->get('tag')), 'type' => 'language', 'client_id' => $clientId)); if ($eid) { $row->load($eid); } else { // set the defaults $row->set('folder', ''); // There is no folder for language $row->set('enabled', 1); $row->set('protected', 0); $row->set('access', 0); $row->set('client_id', $clientId); $row->set('params', $this->parent->getParams()); } $row->set('name', $this->get('name')); $row->set('type', 'language'); $row->set('element', $this->get('tag')); $row->set('manifest_cache', $this->parent->generateManifestCache()); if (!$row->store()) { // Install failed, roll back changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', $row->getError())); return false; } // And now we run the postflight ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'postflight')) { $this->parent->manifestClass->postflight('update', $this); } $msg = ob_get_contents(); // append messages ob_end_clean(); if ($msg != '') { $this->parent->set('extension_message', $msg); } return $row->get('extension_id'); } /** * Custom uninstall method * * @param string $eid The tag of the language to uninstall * * @return mixed Return value for uninstall method in component uninstall file * * @since 11.1 */ public function uninstall($eid) { // Load up the extension details $extension = JTable::getInstance('extension'); $extension->load($eid); // Grab a copy of the client details $client = JApplicationHelper::getClientInfo($extension->get('client_id')); // Check the element isn't blank to prevent nuking the languages directory...just in case $element = $extension->get('element'); if (empty($element)) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_ELEMENT_EMPTY')); return false; } // Check that the language is not protected, Normally en-GB. $protected = $extension->get('protected'); if ($protected == 1) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_PROTECTED')); return false; } // Verify that it's not the default language for that client $params = JComponentHelper::getParams('com_languages'); if ($params->get($client->name) == $element) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_DEFAULT')); return false; } // Construct the path from the client, the language and the extension element name $path = $client->path . '/language/' . $element; // Get the package manifest object and remove media $this->parent->setPath('source', $path); // We do findManifest to avoid problem when uninstalling a list of extension: getManifest cache its manifest file $this->parent->findManifest(); $this->manifest = $this->parent->getManifest(); $this->parent->removeFiles($this->manifest->media); // Check it exists if (!JFolder::exists($path)) { // If the folder doesn't exist lets just nuke the row as well and presume the user killed it for us $extension->delete(); JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_PATH_EMPTY')); return false; } if (!JFolder::delete($path)) { // If deleting failed we'll leave the extension entry in tact just in case JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_DIRECTORY')); return false; } // Remove the extension table entry $extension->delete(); // Setting the language of users which have this language as the default language $db = JFactory::getDbo(); $query = $db->getQuery(true); $query->from('#__users'); $query->select('*'); $db->setQuery($query); $users = $db->loadObjectList(); if ($client->name == 'administrator') { $param_name = 'admin_language'; } else { $param_name = 'language'; } $count = 0; foreach ($users as $user) { $registry = new JRegistry; $registry->loadString($user->params); if ($registry->get($param_name) == $element) { $registry->set($param_name, ''); $query = $db->getQuery(true); $query->update('#__users'); $query->set('params=' . $db->quote($registry)); $query->where('id=' . (int) $user->id); $db->setQuery($query); $db->execute(); $count = $count + 1; } } if (!empty($count)) { JError::raiseNotice(500, JText::plural('JLIB_INSTALLER_NOTICE_LANG_RESET_USERS', $count)); } // All done! return true; } /** * Custom discover method * Finds language files * * @return boolean True on success * * @since 11.1 */ public function discover() { $results = array(); $site_languages = JFolder::folders(JPATH_SITE . '/language'); $admin_languages = JFolder::folders(JPATH_ADMINISTRATOR . '/language'); foreach ($site_languages as $language) { if (file_exists(JPATH_SITE . '/language/' . $language . '/' . $language . '.xml')) { $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_SITE . '/language/' . $language . '/' . $language . '.xml'); $extension = JTable::getInstance('extension'); $extension->set('type', 'language'); $extension->set('client_id', 0); $extension->set('element', $language); $extension->set('name', $language); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $results[] = $extension; } } foreach ($admin_languages as $language) { if (file_exists(JPATH_ADMINISTRATOR . '/language/' . $language . '/' . $language . '.xml')) { $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_ADMINISTRATOR . '/language/' . $language . '/' . $language . '.xml'); $extension = JTable::getInstance('extension'); $extension->set('type', 'language'); $extension->set('client_id', 1); $extension->set('element', $language); $extension->set('name', $language); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $results[] = $extension; } } return $results; } /** * Custom discover install method * Basically updates the manifest cache and leaves everything alone * * @return integer The extension id * * @since 11.1 */ public function discover_install() { // Need to find to find where the XML file is since we don't store this normally $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id); $short_element = $this->parent->extension->element; $manifestPath = $client->path . '/language/' . $short_element . '/' . $short_element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $this->parent->setPath('source', $client->path . '/language/' . $short_element); $this->parent->setPath('extension_root', $this->parent->getPath('source')); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->state = 0; $this->parent->extension->name = $manifest_details['name']; $this->parent->extension->enabled = 1; //$this->parent->extension->params = $this->parent->getParams(); try { $this->parent->extension->store(); } catch (JException $e) { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_LANG_DISCOVER_STORE_DETAILS')); return false; } return $this->parent->extension->get('extension_id'); } /** * Refreshes the extension table cache * * @return boolean result of operation, true if updated, false on failure * * @since 11.1 */ public function refreshManifestCache() { $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id); $manifestPath = $client->path . '/language/' . $this->parent->extension->element . '/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; if ($this->parent->extension->store()) { return true; } else { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_MOD_REFRESH_MANIFEST_CACHE')); return false; } } } adapters/module.php000066600000062441151372561050010365 0ustar00parent->getPath('source'); if (!$source) { $this->parent ->setPath( 'source', ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/modules/' . $this->parent->extension->element ); } $this->manifest = $this->parent->getManifest(); if ($this->manifest->files) { $element = $this->manifest->files; $extension = ''; if (count($element->children())) { foreach ($element->children() as $file) { if ((string) $file->attributes()->module) { $extension = strtolower((string) $file->attributes()->module); break; } } } if ($extension) { $lang = JFactory::getLanguage(); $source = $path ? $path : ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/modules/' . $extension; $folder = (string) $element->attributes()->folder; if ($folder && file_exists("$path/$folder")) { $source = "$path/$folder"; } $client = (string) $this->manifest->attributes()->client; $lang->load($extension . '.sys', $source, null, false, true) || $lang->load($extension . '.sys', constant('JPATH_' . strtoupper($client)), null, false, true); } } } /** * Custom install method * * @return boolean True on success * * @since 11.1 */ public function install() { // Get a database connector object $db = $this->parent->getDbo(); // Get the extension manifest object $this->manifest = $this->parent->getManifest(); // Manifest Document Setup Section // Set the extensions name $name = (string) $this->manifest->name; $name = JFilterInput::getInstance()->clean($name, 'string'); $this->set('name', $name); // Get the component description $description = (string) $this->manifest->description; if ($description) { $this->parent->set('message', JText::_($description)); } else { $this->parent->set('message', ''); } // Target Application Section // Get the target application if ($cname = (string) $this->manifest->attributes()->client) { // Attempt to map the client to a base path $client = JApplicationHelper::getClientInfo($cname, true); if ($client === false) { $this->parent ->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_UNKNOWN_CLIENT', JText::_('JLIB_INSTALLER_' . $this->route), $client->name)); return false; } $basePath = $client->path; $clientId = $client->id; } else { // No client attribute was found so we assume the site as the client $cname = 'site'; $basePath = JPATH_SITE; $clientId = 0; } // Set the installation path $element = ''; if (count($this->manifest->files->children())) { foreach ($this->manifest->files->children() as $file) { if ((string) $file->attributes()->module) { $element = (string) $file->attributes()->module; $this->set('element', $element); break; } } } if (!empty($element)) { $this->parent->setPath('extension_root', $basePath . '/modules/' . $element); } else { $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_INSTALL_NOFILE', JText::_('JLIB_INSTALLER_' . $this->route))); return false; } // Check to see if a module by the same name is already installed // If it is, then update the table because if the files aren't there // we can assume that it was (badly) uninstalled // If it isn't, add an entry to extensions $query = $db->getQuery(true); $query->select($query->qn('extension_id'))->from($query->qn('#__extensions')); $query->where($query->qn('element') . ' = ' . $query->q($element))->where($query->qn('client_id') . ' = ' . (int) $clientId); $db->setQuery($query); try { $db->execute(); } catch (JException $e) { // Install failed, roll back changes $this->parent ->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_ROLLBACK', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true))); return false; } $id = $db->loadResult(); // If the module directory already exists, then we will assume that the // module is already installed or another module is using that // directory. // Check that this is either an issue where its not overwriting or it is // set to upgrade anyway if (file_exists($this->parent->getPath('extension_root')) && (!$this->parent->isOverwrite() || $this->parent->isUpgrade())) { // Look for an update function or update tag $updateElement = $this->manifest->update; // Upgrade manually set or // Update function available or // Update tag detected if ($this->parent->isUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'update')) || $updateElement) { // Force this one $this->parent->setOverwrite(true); $this->parent->setUpgrade(true); if ($id) { // If there is a matching extension mark this as an update; semantics really $this->route = 'Update'; } } elseif (!$this->parent->isOverwrite()) { // Overwrite is set // We didn't have overwrite set, find an update function or find an update tag so lets call it safe $this->parent ->abort( JText::sprintf( 'JLIB_INSTALLER_ABORT_MOD_INSTALL_DIRECTORY', JText::_('JLIB_INSTALLER_' . $this->route), $this->parent->getPath('extension_root') ) ); return false; } } // Installer Trigger Loading // If there is an manifest class file, let's load it; we'll copy it later (don't have destination yet) $this->scriptElement = $this->manifest->scriptfile; $manifestScript = (string) $this->manifest->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript; if (is_file($manifestScriptFile)) { // Load the file include_once $manifestScriptFile; } // Set the class name $classname = $element . 'InstallerScript'; if (class_exists($classname)) { // Create a new instance. $this->parent->manifestClass = new $classname($this); // And set this so we can copy it later. $this->set('manifest_script', $manifestScript); // Note: if we don't find the class, don't bother to copy the file. } } // Run preflight if possible (since we know we're not an update) ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight')) { if ($this->parent->manifestClass->preflight($this->route, $this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_MOD_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } // Create msg object; first use here $msg = ob_get_contents(); ob_end_clean(); // Filesystem Processing Section // If the module directory does not exist, lets create it $created = false; if (!file_exists($this->parent->getPath('extension_root'))) { if (!$created = JFolder::create($this->parent->getPath('extension_root'))) { $this->parent ->abort( JText::sprintf( 'JLIB_INSTALLER_ABORT_MOD_INSTALL_CREATE_DIRECTORY', JText::_('JLIB_INSTALLER_' . $this->route), $this->parent->getPath('extension_root') ) ); return false; } } // Since we created the module directory and will want to remove it if // we have to roll back the installation, let's add it to the // installation step stack if ($created) { $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_root'))); } // Copy all necessary files if ($this->parent->parseFiles($this->manifest->files, -1) === false) { // Install failed, roll back changes $this->parent->abort(); return false; } // If there is a manifest script, let's copy it. if ($this->get('manifest_script')) { $path['src'] = $this->parent->getPath('source') . '/' . $this->get('manifest_script'); $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->get('manifest_script'); if (!file_exists($path['dest']) || $this->parent->isOverwrite()) { if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_MOD_INSTALL_MANIFEST')); return false; } } } // Parse optional tags $this->parent->parseMedia($this->manifest->media, $clientId); $this->parent->parseLanguages($this->manifest->languages, $clientId); // Parse deprecated tags $this->parent->parseFiles($this->manifest->images, -1); // Database Processing Section $row = JTable::getInstance('extension'); // Was there a module already installed with the same name? if ($id) { // Load the entry and update the manifest_cache $row->load($id); $row->name = $this->get('name'); // update name $row->manifest_cache = $this->parent->generateManifestCache(); // update manifest if (!$row->store()) { // Install failed, roll back changes $this->parent ->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_ROLLBACK', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true))); return false; } } else { $row->set('name', $this->get('name')); $row->set('type', 'module'); $row->set('element', $this->get('element')); $row->set('folder', ''); // There is no folder for modules $row->set('enabled', 1); $row->set('protected', 0); $row->set('access', $clientId == 1 ? 2 : 0); $row->set('client_id', $clientId); $row->set('params', $this->parent->getParams()); $row->set('custom_data', ''); // custom data $row->set('manifest_cache', $this->parent->generateManifestCache()); if (!$row->store()) { // Install failed, roll back changes $this->parent ->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_ROLLBACK', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true))); return false; } // Set the insert id $row->extension_id = $db->insertid(); // Since we have created a module item, we add it to the installation step stack // so that if we have to rollback the changes we can undo it. $this->parent->pushStep(array('type' => 'extension', 'extension_id' => $row->extension_id)); // Create unpublished module in jos_modules $name = preg_replace('#[\*?]#', '', JText::_($this->get('name'))); $module = JTable::getInstance('module'); $module->set('title', $name); $module->set('module', $this->get('element')); $module->set('access', '1'); $module->set('showtitle', '1'); $module->set('client_id', $clientId); $module->set('language', '*'); $module->store(); } // Let's run the queries for the module // If Joomla 1.5 compatible, with discrete sql files, execute appropriate // file for utf-8 support or non-utf-8 support // Try for Joomla 1.5 type queries // Second argument is the utf compatible version attribute if (strtolower($this->route) == 'install') { $utfresult = $this->parent->parseSQLFiles($this->manifest->install->sql); if ($utfresult === false) { // Install failed, rollback changes $this->parent ->abort( JText::sprintf('JLIB_INSTALLER_ABORT_MOD_INSTALL_SQL_ERROR', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true)) ); return false; } // Set the schema version to be the latest update version if ($this->manifest->update) { $this->parent->setSchemaVersion($this->manifest->update->schemas, $row->extension_id); } } elseif (strtolower($this->route) == 'update') { if ($this->manifest->update) { $result = $this->parent->parseSchemaUpdates($this->manifest->update->schemas, $row->extension_id); if ($result === false) { // Install failed, rollback changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_UPDATE_SQL_ERROR', $db->stderr(true))); return false; } } } // Start Joomla! 1.6 ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, $this->route)) { if ($this->parent->manifestClass->{$this->route}($this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_MOD_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } // Append messages $msg .= ob_get_contents(); ob_end_clean(); // Finalization and Cleanup Section // Lastly, we will copy the manifest file to its appropriate place. if (!$this->parent->copyManifest(-1)) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_MOD_INSTALL_COPY_SETUP')); return false; } // And now we run the postflight ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'postflight')) { $this->parent->manifestClass->postflight($this->route, $this); } // Append messages $msg .= ob_get_contents(); ob_end_clean(); if ($msg != '') { $this->parent->set('extension_message', $msg); } return $row->get('extension_id'); } /** * Custom update method * * This is really a shell for the install system * * @return boolean True on success. * * @since 11.1 */ public function update() { // Set the overwrite setting $this->parent->setOverwrite(true); $this->parent->setUpgrade(true); // Set the route for the install $this->route = 'Update'; // Go to install which handles updates properly return $this->install(); } /** * Custom discover method * * @return array JExtension list of extensions available * * @since 11.1 */ public function discover() { $results = array(); $site_list = JFolder::folders(JPATH_SITE . '/modules'); $admin_list = JFolder::folders(JPATH_ADMINISTRATOR . '/modules'); $site_info = JApplicationHelper::getClientInfo('site', true); $admin_info = JApplicationHelper::getClientInfo('administrator', true); foreach ($site_list as $module) { $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_SITE . "/modules/$module/$module.xml"); $extension = JTable::getInstance('extension'); $extension->set('type', 'module'); $extension->set('client_id', $site_info->id); $extension->set('element', $module); $extension->set('name', $module); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $results[] = clone $extension; } foreach ($admin_list as $module) { $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_ADMINISTRATOR . "/modules/$module/$module.xml"); $extension = JTable::getInstance('extension'); $extension->set('type', 'module'); $extension->set('client_id', $admin_info->id); $extension->set('element', $module); $extension->set('name', $module); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $results[] = clone $extension; } return $results; } /** * Custom discover_install method * * @return mixed Extension ID on success, boolean false on failure * * @since 11.1 */ public function discover_install() { // Modules are like templates, and are one of the easiest // If its not in the extensions table we just add it $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id); $manifestPath = $client->path . '/modules/' . $this->parent->extension->element . '/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $description = (string) $this->parent->manifest->description; if ($description) { $this->parent->set('message', JText::_($description)); } else { $this->parent->set('message', ''); } $this->parent->setPath('manifest', $manifestPath); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); // TODO: Re-evaluate this; should we run installation triggers? postflight perhaps? $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->state = 0; $this->parent->extension->name = $manifest_details['name']; $this->parent->extension->enabled = 1; $this->parent->extension->params = $this->parent->getParams(); if ($this->parent->extension->store()) { return $this->parent->extension->get('extension_id'); } else { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_MOD_DISCOVER_STORE_DETAILS')); return false; } } /** * Refreshes the extension table cache * * @return boolean Result of operation, true if updated, false on failure. * * @since 11.1 */ public function refreshManifestCache() { $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id); $manifestPath = $client->path . '/modules/' . $this->parent->extension->element . '/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; if ($this->parent->extension->store()) { return true; } else { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_MOD_REFRESH_MANIFEST_CACHE')); return false; } } /** * Custom uninstall method * * @param integer $id The id of the module to uninstall * * @return boolean True on success * * @since 11.1 */ public function uninstall($id) { // Initialise variables. $row = null; $retval = true; $db = $this->parent->getDbo(); // First order of business will be to load the module object table from the database. // This should give us the necessary information to proceed. $row = JTable::getInstance('extension'); if (!$row->load((int) $id) || !strlen($row->element)) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_ERRORUNKOWNEXTENSION')); return false; } // Is the module we are trying to uninstall a core one? // Because that is not a good idea... if ($row->protected) { JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_WARNCOREMODULE', $row->name)); return false; } // Get the extension root path $element = $row->element; $client = JApplicationHelper::getClientInfo($row->client_id); if ($client === false) { $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_UNKNOWN_CLIENT', $row->client_id)); return false; } $this->parent->setPath('extension_root', $client->path . '/modules/' . $element); $this->parent->setPath('source', $this->parent->getPath('extension_root')); // Get the package manifest objecct // We do findManifest to avoid problem when uninstalling a list of extensions: getManifest cache its manifest file. $this->parent->findManifest(); $this->manifest = $this->parent->getManifest(); // Attempt to load the language file; might have uninstall strings $this->loadLanguage(($row->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/modules/' . $element); // If there is an manifest class file, let's load it $this->scriptElement = $this->manifest->scriptfile; $manifestScript = (string) $this->manifest->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('extension_root') . '/' . $manifestScript; if (is_file($manifestScriptFile)) { // Load the file include_once $manifestScriptFile; } // Set the class name $classname = $element . 'InstallerScript'; if (class_exists($classname)) { // Create a new instance $this->parent->manifestClass = new $classname($this); // And set this so we can copy it later $this->set('manifest_script', $manifestScript); // Note: if we don't find the class, don't bother to copy the file } } ob_start(); ob_implicit_flush(false); // Run uninstall if possible if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'uninstall')) { $this->parent->manifestClass->uninstall($this); } $msg = ob_get_contents(); ob_end_clean(); if (!($this->manifest instanceof SimpleXMLElement)) { // Make sure we delete the folders JFolder::delete($this->parent->getPath('extension_root')); JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_INVALID_NOTFOUND_MANIFEST')); return false; } /* * Let's run the uninstall queries for the component * If Joomla 1.5 compatible, with discreet sql files - execute appropriate * file for utf-8 support or non-utf support */ // Try for Joomla 1.5 type queries // Second argument is the utf compatible version attribute $utfresult = $this->parent->parseSQLFiles($this->manifest->uninstall->sql); if ($utfresult === false) { // Install failed, rollback changes JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_SQL_ERROR', $db->stderr(true))); $retval = false; } // Remove the schema version $query = $db->getQuery(true); $query->delete()->from('#__schemas')->where('extension_id = ' . $row->extension_id); $db->setQuery($query); $db->execute(); // Remove other files $this->parent->removeFiles($this->manifest->media); $this->parent->removeFiles($this->manifest->languages, $row->client_id); // Let's delete all the module copies for the type we are uninstalling $query = $db->getQuery(true); $query->select($query->qn('id'))->from($query->qn('#__modules')); $query->where($query->qn('module') . ' = ' . $query->q($row->element)); $query->where($query->qn('client_id') . ' = ' . (int) $row->client_id); $db->setQuery($query); try { $modules = $db->loadColumn(); } catch (JException $e) { $modules = array(); } // Do we have any module copies? if (count($modules)) { // Ensure the list is sane JArrayHelper::toInteger($modules); $modID = implode(',', $modules); // Wipe out any items assigned to menus $query = 'DELETE' . ' FROM #__modules_menu' . ' WHERE moduleid IN (' . $modID . ')'; $db->setQuery($query); try { $db->execute(); } catch (JException $e) { JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_EXCEPTION', $db->stderr(true))); $retval = false; } // Wipe out any instances in the modules table $query = 'DELETE' . ' FROM #__modules' . ' WHERE id IN (' . $modID . ')'; $db->setQuery($query); try { $db->execute(); } catch (JException $e) { JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_EXCEPTION', $db->stderr(true))); $retval = false; } } // Now we will no longer need the module object, so let's delete it and free up memory $row->delete($row->extension_id); $query = 'DELETE FROM #__modules WHERE module = ' . $db->Quote($row->element) . ' AND client_id = ' . $row->client_id; $db->setQuery($query); try { // Clean up any other ones that might exist as well $db->execute(); } catch (JException $e) { // Ignore the error... } unset($row); // Remove the installation folder if (!JFolder::delete($this->parent->getPath('extension_root'))) { // JFolder should raise an error $retval = false; } return $retval; } /** * Custom rollback method * - Roll back the menu item * * @param array $arg Installation step to rollback * * @return boolean True on success * * @since 11.1 */ protected function _rollback_menu($arg) { // Get database connector object $db = $this->parent->getDbo(); // Remove the entry from the #__modules_menu table $query = 'DELETE' . ' FROM #__modules_menu' . ' WHERE moduleid=' . (int) $arg['id']; $db->setQuery($query); try { return $db->execute(); } catch (JException $e) { return false; } } /** * Custom rollback method * - Roll back the module item * * @param array $arg Installation step to rollback * * @return boolean True on success * * @since 11.1 */ protected function _rollback_module($arg) { // Get database connector object $db = $this->parent->getDbo(); // Remove the entry from the #__modules table $query = 'DELETE' . ' FROM #__modules' . ' WHERE id=' . (int) $arg['id']; $db->setQuery($query); try { return $db->execute(); } catch (JException $e) { return false; } } } adapters/library.php000066600000031073151372561050010541 0ustar00parent->getPath('source'); if (!$source) { $this->parent->setPath('source', JPATH_PLATFORM . '/' . $this->parent->extension->element); } $this->manifest = $this->parent->getManifest(); $extension = 'lib_' . strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd')); $name = strtolower((string) $this->manifest->libraryname); $lang = JFactory::getLanguage(); $source = $path ? $path : JPATH_PLATFORM . "/$name"; $lang->load($extension . '.sys', $source, null, false, true) || $lang->load($extension . '.sys', JPATH_SITE, null, false, true); } /** * Custom install method * * @return boolean True on success * * @since 11.1 */ public function install() { // Get the extension manifest object $this->manifest = $this->parent->getManifest(); // Manifest Document Setup Section // Set the extensions name $name = JFilterInput::getInstance()->clean((string) $this->manifest->name, 'string'); $element = str_replace('.xml', '', basename($this->parent->getPath('manifest'))); $this->set('name', $name); $this->set('element', $element); $db = $this->parent->getDbo(); $query = $db->getQuery(true); $query->select($db->quoteName('extension_id')); $query->from($db->quoteName('#__extensions')); $query->where($db->quoteName('type') . ' = ' . $db->quote('library')); $query->where($db->quoteName('element') . ' = ' . $db->quote($element)); $db->setQuery($query); $result = $db->loadResult(); if ($result) { // Already installed, can we upgrade? if ($this->parent->isOverwrite() || $this->parent->isUpgrade()) { // We can upgrade, so uninstall the old one $installer = new JInstaller; // we don't want to compromise this instance! $installer->uninstall('library', $result); } else { // Abort the install, no upgrade possible $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_LIB_INSTALL_ALREADY_INSTALLED')); return false; } } // Get the libraries description $description = (string) $this->manifest->description; if ($description) { $this->parent->set('message', JText::_($description)); } else { $this->parent->set('message', ''); } // Set the installation path $group = (string) $this->manifest->libraryname; if (!$group) { $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_LIB_INSTALL_NOFILE')); return false; } else { $this->parent->setPath('extension_root', JPATH_PLATFORM . '/' . implode(DIRECTORY_SEPARATOR, explode('/', $group))); } // Filesystem Processing Section // If the plugin directory does not exist, let's create it $created = false; if (!file_exists($this->parent->getPath('extension_root'))) { if (!$created = JFolder::create($this->parent->getPath('extension_root'))) { $this->parent->abort( JText::sprintf('JLIB_INSTALLER_ABORT_LIB_INSTALL_FAILED_TO_CREATE_DIRECTORY', $this->parent->getPath('extension_root')) ); return false; } } // If we created the plugin directory and will want to remove it if we // have to roll back the installation, let's add it to the installation // step stack if ($created) { $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_root'))); } // Copy all necessary files if ($this->parent->parseFiles($this->manifest->files, -1) === false) { // Install failed, roll back changes $this->parent->abort(); return false; } // Parse optional tags $this->parent->parseLanguages($this->manifest->languages); $this->parent->parseMedia($this->manifest->media); // Extension Registration $row = JTable::getInstance('extension'); $row->name = $this->get('name'); $row->type = 'library'; $row->element = $this->get('element'); $row->folder = ''; // There is no folder for modules $row->enabled = 1; $row->protected = 0; $row->access = 1; $row->client_id = 0; $row->params = $this->parent->getParams(); $row->custom_data = ''; // custom data $row->manifest_cache = $this->parent->generateManifestCache(); if (!$row->store()) { // Install failed, roll back changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_LIB_INSTALL_ROLLBACK', $db->stderr(true))); return false; } // Finalization and Cleanup Section // Lastly, we will copy the manifest file to its appropriate place. $manifest = array(); $manifest['src'] = $this->parent->getPath('manifest'); $manifest['dest'] = JPATH_MANIFESTS . '/libraries/' . basename($this->parent->getPath('manifest')); if (!$this->parent->copyFiles(array($manifest), true)) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_LIB_INSTALL_COPY_SETUP')); return false; } return $row->get('extension_id'); } /** * Custom update method * * @return boolean True on success * * @since 11.1 */ public function update() { // Since this is just files, an update removes old files // Get the extension manifest object $this->manifest = $this->parent->getManifest(); // Manifest Document Setup Section // Set the extensions name $name = (string) $this->manifest->name; $name = JFilterInput::getInstance()->clean($name, 'string'); $element = str_replace('.xml', '', basename($this->parent->getPath('manifest'))); $this->set('name', $name); $this->set('element', $element); $installer = new JInstaller; // we don't want to compromise this instance! $db = $this->parent->getDbo(); $query = $db->getQuery(true); $query->select($db->quoteName('extension_id')); $query->from($db->quoteName('#__extensions')); $query->where($db->quoteName('type') . ' = ' . $db->quote('library')); $query->where($db->quoteName('element') . ' = ' . $db->quote($element)); $db->setQuery($query); $result = $db->loadResult(); if ($result) { // Already installed, which would make sense $installer->uninstall('library', $result); } // Now create the new files return $this->install(); } /** * Custom uninstall method * * @param string $id The id of the library to uninstall. * * @return boolean True on success * * @since 11.1 */ public function uninstall($id) { // Initialise variables. $retval = true; // First order of business will be to load the module object table from the database. // This should give us the necessary information to proceed. $row = JTable::getInstance('extension'); if (!$row->load((int) $id) || !strlen($row->element)) { JError::raiseWarning(100, JText::_('ERRORUNKOWNEXTENSION')); return false; } // Is the library we are trying to uninstall a core one? // Because that is not a good idea... if ($row->protected) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LIB_UNINSTALL_WARNCORELIBRARY')); return false; } $manifestFile = JPATH_MANIFESTS . '/libraries/' . $row->element . '.xml'; // Because libraries may not have their own folders we cannot use the standard method of finding an installation manifest if (file_exists($manifestFile)) { $manifest = new JLibraryManifest($manifestFile); // Set the plugin root path $this->parent->setPath('extension_root', JPATH_PLATFORM . '/' . $manifest->libraryname); $xml = JFactory::getXML($manifestFile); // If we cannot load the XML file return null if (!$xml) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LIB_UNINSTALL_LOAD_MANIFEST')); return false; } // Check for a valid XML root tag. // TODO: Remove backwards compatibility in a future version // Should be 'extension', but for backward compatibility we will accept 'install'. if ($xml->getName() != 'install' && $xml->getName() != 'extension') { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LIB_UNINSTALL_INVALID_MANIFEST')); return false; } $this->parent->removeFiles($xml->files, -1); JFile::delete($manifestFile); } else { // Remove this row entry since its invalid $row->delete($row->extension_id); unset($row); JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LIB_UNINSTALL_INVALID_NOTFOUND_MANIFEST')); return false; } // TODO: Change this so it walked up the path backwards so we clobber multiple empties // If the folder is empty, let's delete it if (JFolder::exists($this->parent->getPath('extension_root'))) { if (is_dir($this->parent->getPath('extension_root'))) { $files = JFolder::files($this->parent->getPath('extension_root')); if (!count($files)) { JFolder::delete($this->parent->getPath('extension_root')); } } } $this->parent->removeFiles($xml->media); $this->parent->removeFiles($xml->languages); $row->delete($row->extension_id); unset($row); return $retval; } /** * Custom discover method * * @return array JExtension list of extensions available * * @since 11.1 */ public function discover() { $results = array(); $file_list = JFolder::files(JPATH_MANIFESTS . '/libraries', '\.xml$'); foreach ($file_list as $file) { $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_MANIFESTS . '/libraries/' . $file); $file = JFile::stripExt($file); $extension = JTable::getInstance('extension'); $extension->set('type', 'library'); $extension->set('client_id', 0); $extension->set('element', $file); $extension->set('name', $file); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $results[] = $extension; } return $results; } /** * Custom discover_install method * * @return boolean True on success * * @since 11.1 */ public function discover_install() { /* Libraries are a strange beast; they are actually references to files * There are two parts to a library which are disjunct in their locations * 1) The manifest file (stored in /JPATH_MANIFESTS/libraries) * 2) The actual files (stored in /JPATH_PLATFORM/libraryname) * Thus installation of a library is the process of dumping files * in two different places. As such it is impossible to perform * any operation beyond mere registration of a library under the presumption * that the files exist in the appropriate location so that come uninstall * time they can be adequately removed. */ $manifestPath = JPATH_MANIFESTS . '/libraries/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->state = 0; $this->parent->extension->name = $manifest_details['name']; $this->parent->extension->enabled = 1; $this->parent->extension->params = $this->parent->getParams(); if ($this->parent->extension->store()) { return true; } else { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_LIB_DISCOVER_STORE_DETAILS')); return false; } } /** * Refreshes the extension table cache * * @return boolean Result of operation, true if updated, false on failure * * @since 11.1 */ public function refreshManifestCache() { // Need to find to find where the XML file is since we don't store this normally $manifestPath = JPATH_MANIFESTS . '/libraries/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; try { return $this->parent->extension->store(); } catch (JException $e) { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_LIB_REFRESH_MANIFEST_CACHE')); return false; } } } adapters/plugin.php000066600000061064151372561050010376 0ustar00parent->getPath('source'); if (!$source) { $this->parent->setPath('source', JPATH_PLUGINS . '/' . $this->parent->extension->folder . '/' . $this->parent->extension->element); } $this->manifest = $this->parent->getManifest(); $element = $this->manifest->files; if ($element) { $group = strtolower((string) $this->manifest->attributes()->group); $name = ''; if (count($element->children())) { foreach ($element->children() as $file) { if ((string) $file->attributes()->plugin) { $name = strtolower((string) $file->attributes()->plugin); break; } } } if ($name) { $extension = "plg_${group}_${name}"; $lang = JFactory::getLanguage(); $source = $path ? $path : JPATH_PLUGINS . "/$group/$name"; $folder = (string) $element->attributes()->folder; if ($folder && file_exists("$path/$folder")) { $source = "$path/$folder"; } $lang->load($extension . '.sys', $source, null, false, true) || $lang->load($extension . '.sys', JPATH_ADMINISTRATOR, null, false, true); } } } /** * Custom install method * * @return boolean True on success * * @since 11.1 */ public function install() { // Get a database connector object $db = $this->parent->getDbo(); // Get the extension manifest object $this->manifest = $this->parent->getManifest(); $xml = $this->manifest; // Manifest Document Setup Section // Set the extension name $name = (string) $xml->name; $name = JFilterInput::getInstance()->clean($name, 'string'); $this->set('name', $name); // Get the component description $description = (string) $xml->description; if ($description) { $this->parent->set('message', JText::_($description)); } else { $this->parent->set('message', ''); } /* * Backward Compatibility * @todo Deprecate in future version */ $type = (string) $xml->attributes()->type; // Set the installation path if (count($xml->files->children())) { foreach ($xml->files->children() as $file) { if ((string) $file->attributes()->$type) { $element = (string) $file->attributes()->$type; break; } } } $group = (string) $xml->attributes()->group; if (!empty($element) && !empty($group)) { $this->parent->setPath('extension_root', JPATH_PLUGINS . '/' . $group . '/' . $element); } else { $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_NO_FILE', JText::_('JLIB_INSTALLER_' . $this->route))); return false; } // Check if we should enable overwrite settings // Check to see if a plugin by the same name is already installed. $query = $db->getQuery(true); $query->select($query->qn('extension_id'))->from($query->qn('#__extensions')); $query->where($query->qn('folder') . ' = ' . $query->q($group)); $query->where($query->qn('element') . ' = ' . $query->q($element)); $db->setQuery($query); try { $db->execute(); } catch (JException $e) { // Install failed, roll back changes $this->parent ->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_ROLLBACK', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true))); return false; } $id = $db->loadResult(); // If it's on the fs... if (file_exists($this->parent->getPath('extension_root')) && (!$this->parent->isOverwrite() || $this->parent->isUpgrade())) { $updateElement = $xml->update; // Upgrade manually set or // Update function available or // Update tag detected if ($this->parent->isUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'update')) || $updateElement) { // Force this one $this->parent->setOverwrite(true); $this->parent->setUpgrade(true); if ($id) { // If there is a matching extension mark this as an update; semantics really $this->route = 'update'; } } elseif (!$this->parent->isOverwrite()) { // Overwrite is set // We didn't have overwrite set, find an update function or find an update tag so lets call it safe $this->parent ->abort( JText::sprintf( 'JLIB_INSTALLER_ABORT_PLG_INSTALL_DIRECTORY', JText::_('JLIB_INSTALLER_' . $this->route), $this->parent->getPath('extension_root') ) ); return false; } } // Installer Trigger Loading // If there is an manifest class file, let's load it; we'll copy it later (don't have destination yet). if ((string) $xml->scriptfile) { $manifestScript = (string) $xml->scriptfile; $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript; if (is_file($manifestScriptFile)) { // Load the file include_once $manifestScriptFile; } // If a dash is present in the group name, remove it $groupClass = str_replace('-', '', $group); // Set the class name $classname = 'plg' . $groupClass . $element . 'InstallerScript'; if (class_exists($classname)) { // Create a new instance $this->parent->manifestClass = new $classname($this); // And set this so we can copy it later $this->set('manifest_script', $manifestScript); // Note: if we don't find the class, don't bother to copy the file } } // Run preflight if possible (since we know we're not an update) ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight')) { if ($this->parent->manifestClass->preflight($this->route, $this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_PLG_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } $msg = ob_get_contents(); // create msg object; first use here ob_end_clean(); // Filesystem Processing Section // If the plugin directory does not exist, lets create it $created = false; if (!file_exists($this->parent->getPath('extension_root'))) { if (!$created = JFolder::create($this->parent->getPath('extension_root'))) { $this->parent ->abort( JText::sprintf( 'JLIB_INSTALLER_ABORT_PLG_INSTALL_CREATE_DIRECTORY', JText::_('JLIB_INSTALLER_' . $this->route), $this->parent->getPath('extension_root') ) ); return false; } } // If we're updating at this point when there is always going to be an extension_root find the old XML files if ($this->route == 'update') { // Hunt for the original XML file $old_manifest = null; $tmpInstaller = new JInstaller; // create a new installer because findManifest sets stuff; side effects! // Look in the extension root $tmpInstaller->setPath('source', $this->parent->getPath('extension_root')); if ($tmpInstaller->findManifest()) { $old_manifest = $tmpInstaller->getManifest(); $this->oldFiles = $old_manifest->files; } } // If we created the plugin directory and will want to remove it if we // have to roll back the installation, let's add it to the installation // step stack if ($created) { $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_root'))); } // Copy all necessary files if ($this->parent->parseFiles($xml->files, -1, $this->oldFiles) === false) { // Install failed, roll back changes $this->parent->abort(); return false; } // Parse optional tags -- media and language files for plugins go in admin app $this->parent->parseMedia($xml->media, 1); $this->parent->parseLanguages($xml->languages, 1); // If there is a manifest script, lets copy it. if ($this->get('manifest_script')) { $path['src'] = $this->parent->getPath('source') . '/' . $this->get('manifest_script'); $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->get('manifest_script'); if (!file_exists($path['dest'])) { if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes $this->parent ->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_MANIFEST', JText::_('JLIB_INSTALLER_' . $this->route))); return false; } } } // Database Processing Section $row = JTable::getInstance('extension'); // Was there a plugin with the same name already installed? if ($id) { if (!$this->parent->isOverwrite()) { // Install failed, roll back changes $this->parent ->abort( JText::sprintf( 'JLIB_INSTALLER_ABORT_PLG_INSTALL_ALLREADY_EXISTS', JText::_('JLIB_INSTALLER_' . $this->route), $this->get('name') ) ); return false; } $row->load($id); $row->name = $this->get('name'); $row->manifest_cache = $this->parent->generateManifestCache(); $row->store(); // update the manifest cache and name } else { // Store in the extensions table (1.6) $row->name = $this->get('name'); $row->type = 'plugin'; $row->ordering = 0; $row->element = $element; $row->folder = $group; $row->enabled = 0; $row->protected = 0; $row->access = 1; $row->client_id = 0; $row->params = $this->parent->getParams(); // Custom data $row->custom_data = ''; // System data $row->system_data = ''; $row->manifest_cache = $this->parent->generateManifestCache(); // Editor plugins are published by default if ($group == 'editors') { $row->enabled = 1; } if (!$row->store()) { // Install failed, roll back changes $this->parent ->abort( JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_ROLLBACK', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true)) ); return false; } // Since we have created a plugin item, we add it to the installation step stack // so that if we have to rollback the changes we can undo it. $this->parent->pushStep(array('type' => 'extension', 'id' => $row->extension_id)); $id = $row->extension_id; } // Let's run the queries for the module // If Joomla 1.5 compatible, with discreet sql files - execute appropriate // file for utf-8 support or non-utf-8 support // Try for Joomla 1.5 type queries // Second argument is the utf compatible version attribute if (strtolower($this->route) == 'install') { $utfresult = $this->parent->parseSQLFiles($this->manifest->install->sql); if ($utfresult === false) { // Install failed, rollback changes $this->parent ->abort( JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_SQL_ERROR', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true)) ); return false; } // Set the schema version to be the latest update version if ($this->manifest->update) { $this->parent->setSchemaVersion($this->manifest->update->schemas, $row->extension_id); } } elseif (strtolower($this->route) == 'update') { if ($this->manifest->update) { $result = $this->parent->parseSchemaUpdates($this->manifest->update->schemas, $row->extension_id); if ($result === false) { // Install failed, rollback changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_UPDATE_SQL_ERROR', $db->stderr(true))); return false; } } } // Start Joomla! 1.6 ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, $this->route)) { if ($this->parent->manifestClass->{$this->route}($this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_PLG_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } // Append messages $msg .= ob_get_contents(); ob_end_clean(); // Finalization and Cleanup Section // Lastly, we will copy the manifest file to its appropriate place. if (!$this->parent->copyManifest(-1)) { // Install failed, rollback changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_COPY_SETUP', JText::_('JLIB_INSTALLER_' . $this->route))); return false; } // And now we run the postflight ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'postflight')) { $this->parent->manifestClass->postflight($this->route, $this); } // Append messages $msg .= ob_get_contents(); ob_end_clean(); if ($msg != '') { $this->parent->set('extension_message', $msg); } return $id; } /** * Custom update method * * @return boolean True on success * * @since 11.1 */ public function update() { // Set the overwrite setting $this->parent->setOverwrite(true); $this->parent->setUpgrade(true); // Set the route for the install $this->route = 'update'; // Go to install which handles updates properly return $this->install(); } /** * Custom uninstall method * * @param integer $id The id of the plugin to uninstall * * @return boolean True on success * * @since 11.1 */ public function uninstall($id) { $this->route = 'uninstall'; // Initialise variables. $row = null; $retval = true; $db = $this->parent->getDbo(); // First order of business will be to load the plugin object table from the database. // This should give us the necessary information to proceed. $row = JTable::getInstance('extension'); if (!$row->load((int) $id)) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_PLG_UNINSTALL_ERRORUNKOWNEXTENSION')); return false; } // Is the plugin we are trying to uninstall a core one? // Because that is not a good idea... if ($row->protected) { JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_PLG_UNINSTALL_WARNCOREPLUGIN', $row->name)); return false; } // Get the plugin folder so we can properly build the plugin path if (trim($row->folder) == '') { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_PLG_UNINSTALL_FOLDER_FIELD_EMPTY')); return false; } // Set the plugin root path if (is_dir(JPATH_PLUGINS . '/' . $row->folder . '/' . $row->element)) { // Use 1.6 plugins $this->parent->setPath('extension_root', JPATH_PLUGINS . '/' . $row->folder . '/' . $row->element); } else { // Use Legacy 1.5 plugins $this->parent->setPath('extension_root', JPATH_PLUGINS . '/' . $row->folder); } // Because 1.5 plugins don't have their own folders we cannot use the standard method of finding an installation manifest // Since 1.6 they do, however until we move to 1.7 and remove 1.6 legacy we still need to use this method. // When we get there it'll be something like "$this->parent->findManifest();$manifest = $this->parent->getManifest();" $manifestFile = $this->parent->getPath('extension_root') . '/' . $row->element . '.xml'; if (!file_exists($manifestFile)) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_PLG_UNINSTALL_INVALID_NOTFOUND_MANIFEST')); return false; } $xml = JFactory::getXML($manifestFile); $this->manifest = $xml; // If we cannot load the XML file return null if (!$xml) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_PLG_UNINSTALL_LOAD_MANIFEST')); return false; } /* * Check for a valid XML root tag. * @todo: Remove backwards compatibility in a future version * Should be 'extension', but for backward compatibility we will accept 'install'. */ if ($xml->getName() != 'install' && $xml->getName() != 'extension') { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_PLG_UNINSTALL_INVALID_MANIFEST')); return false; } // Attempt to load the language file; might have uninstall strings $this->parent->setPath('source', JPATH_PLUGINS . '/' . $row->folder . '/' . $row->element); $this->loadLanguage(JPATH_PLUGINS . '/' . $row->folder . '/' . $row->element); // Installer Trigger Loading // If there is an manifest class file, let's load it; we'll copy it later (don't have dest yet) $manifestScript = (string) $xml->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript; if (is_file($manifestScriptFile)) { // Load the file include_once $manifestScriptFile; } // If a dash is present in the folder, remove it $folderClass = str_replace('-', '', $row->folder); // Set the class name $classname = 'plg' . $folderClass . $row->element . 'InstallerScript'; if (class_exists($classname)) { // Create a new instance $this->parent->manifestClass = new $classname($this); // And set this so we can copy it later $this->set('manifest_script', $manifestScript); // Note: if we don't find the class, don't bother to copy the file } } // Run preflight if possible (since we know we're not an update) ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight')) { if ($this->parent->manifestClass->preflight($this->route, $this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_PLG_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } // Create msg object; first use here $msg = ob_get_contents(); ob_end_clean(); // Let's run the queries for the module // If Joomla 1.5 compatible, with discreet sql files - execute appropriate // file for utf-8 support or non-utf-8 support // Try for Joomla 1.5 type queries // Second argument is the utf compatible version attribute $utfresult = $this->parent->parseSQLFiles($xml->{strtolower($this->route)}->sql); if ($utfresult === false) { // Install failed, rollback changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_UNINSTALL_SQL_ERROR', $db->stderr(true))); return false; } // Start Joomla! 1.6 ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'uninstall')) { $this->parent->manifestClass->uninstall($this); } // Append messages $msg = ob_get_contents(); ob_end_clean(); // Remove the plugin files $this->parent->removeFiles($xml->images, -1); $this->parent->removeFiles($xml->files, -1); JFile::delete($manifestFile); // Remove all media and languages as well $this->parent->removeFiles($xml->media); $this->parent->removeFiles($xml->languages, 1); // Remove the schema version $query = $db->getQuery(true); $query->delete()->from('#__schemas')->where('extension_id = ' . $row->extension_id); $db->setQuery($query); $db->execute(); // Now we will no longer need the plugin object, so let's delete it $row->delete($row->extension_id); unset($row); // If the folder is empty, let's delete it $files = JFolder::files($this->parent->getPath('extension_root')); JFolder::delete($this->parent->getPath('extension_root')); if ($msg) { $this->parent->set('extension_message', $msg); } return $retval; } /** * Custom discover method * * @return array JExtension) list of extensions available * * @since 11.1 */ public function discover() { $results = array(); $folder_list = JFolder::folders(JPATH_SITE . '/plugins'); foreach ($folder_list as $folder) { $file_list = JFolder::files(JPATH_SITE . '/plugins/' . $folder, '\.xml$'); foreach ($file_list as $file) { $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_SITE . '/plugins/' . $folder . '/' . $file); $file = JFile::stripExt($file); // Ignore example plugins if ($file == 'example') { continue; } $extension = JTable::getInstance('extension'); $extension->set('type', 'plugin'); $extension->set('client_id', 0); $extension->set('element', $file); $extension->set('folder', $folder); $extension->set('name', $file); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $results[] = $extension; } $folder_list = JFolder::folders(JPATH_SITE . '/plugins/' . $folder); foreach ($folder_list as $plugin_folder) { $file_list = JFolder::files(JPATH_SITE . '/plugins/' . $folder . '/' . $plugin_folder, '\.xml$'); foreach ($file_list as $file) { $manifest_details = JApplicationHelper::parseXMLInstallFile( JPATH_SITE . '/plugins/' . $folder . '/' . $plugin_folder . '/' . $file ); $file = JFile::stripExt($file); if ($file == 'example') { continue; } // ignore example plugins $extension = JTable::getInstance('extension'); $extension->set('type', 'plugin'); $extension->set('client_id', 0); $extension->set('element', $file); $extension->set('folder', $folder); $extension->set('name', $file); $extension->set('state', -1); $extension->set('manifest_cache', json_encode($manifest_details)); $results[] = $extension; } } } return $results; } /** * Custom discover_install method. * * @return mixed * * @since 11.1 */ public function discover_install() { // Plugins use the extensions table as their primary store // Similar to modules and templates, rather easy // If it's not in the extensions table we just add it $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id); if (is_dir($client->path . '/plugins/' . $this->parent->extension->folder . '/' . $this->parent->extension->element)) { $manifestPath = $client->path . '/plugins/' . $this->parent->extension->folder . '/' . $this->parent->extension->element . '/' . $this->parent->extension->element . '.xml'; } else { $manifestPath = $client->path . '/plugins/' . $this->parent->extension->folder . '/' . $this->parent->extension->element . '.xml'; } $this->parent->manifest = $this->parent->isManifest($manifestPath); $description = (string) $this->parent->manifest->description; if ($description) { $this->parent->set('message', JText::_($description)); } else { $this->parent->set('message', ''); } $this->parent->setPath('manifest', $manifestPath); $manifest_details = JApplicationHelper::parseXMLInstallFile($manifestPath); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->state = 0; $this->parent->extension->name = $manifest_details['name']; $this->parent->extension->enabled = ('editors' == $this->parent->extension->folder) ? 1 : 0; $this->parent->extension->params = $this->parent->getParams(); if ($this->parent->extension->store()) { return $this->parent->extension->get('extension_id'); } else { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_PLG_DISCOVER_STORE_DETAILS')); return false; } } /** * Refreshes the extension table cache. * * @return boolean Result of operation, true if updated, false on failure. * * @since 11.1 */ public function refreshManifestCache() { // Plugins use the extensions table as their primary store // Similar to modules and templates, rather easy // If it's not in the extensions table we just add it $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id); $manifestPath = $client->path . '/plugins/' . $this->parent->extension->folder . '/' . $this->parent->extension->element . '/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; if ($this->parent->extension->store()) { return true; } else { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_PLG_REFRESH_MANIFEST_CACHE')); return false; } } } adapters/file.php000066600000046525151372561050010024 0ustar00manifest = $this->parent->getManifest(); $extension = 'files_' . str_replace('files_', '', strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd'))); $lang = JFactory::getLanguage(); $source = $path; $lang->load($extension . '.sys', $source, null, false, true) || $lang->load($extension . '.sys', JPATH_SITE, null, false, true); } /** * Custom install method * * @return boolean True on success * * @since 11.1 */ public function install() { // Get the extension manifest object $this->manifest = $this->parent->getManifest(); // Manifest Document Setup Section // Set the extension's name $name = JFilterInput::getInstance()->clean((string) $this->manifest->name, 'string'); $this->set('name', $name); // Set element $manifestPath = JPath::clean($this->parent->getPath('manifest')); $element = preg_replace('/\.xml/', '', basename($manifestPath)); $this->set('element', $element); // Get the component description $description = (string) $this->manifest->description; if ($description) { $this->parent->set('message', JText::_($description)); } else { $this->parent->set('message', ''); } //Check if the extension by the same name is already installed if ($this->extensionExistsInSystem($element)) { // Package with same name already exists if (!$this->parent->isOverwrite()) { // we're not overwriting so abort $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_SAME_NAME')); return false; } else { // swap to the update route $this->route = 'update'; } } // Set the file root path $this->parent->setPath('extension_root', JPATH_ROOT); /** * --------------------------------------------------------------------------------------------- * Installer Trigger Loading * --------------------------------------------------------------------------------------------- */ // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet) $this->scriptElement = $this->manifest->scriptfile; $manifestScript = (string) $this->manifest->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript; if (is_file($manifestScriptFile)) { // load the file include_once $manifestScriptFile; } // Set the class name $classname = $element . 'InstallerScript'; if (class_exists($classname)) { // create a new instance $this->parent->manifestClass = new $classname($this); // and set this so we can copy it later $this->set('manifest_script', $manifestScript); // Note: if we don't find the class, don't bother to copy the file } } // run preflight if possible (since we know we're not an update) ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight')) { if ($this->parent->manifestClass->preflight($this->route, $this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } $msg = ob_get_contents(); // create msg object; first use here ob_end_clean(); // Populate File and Folder List to copy $this->populateFilesAndFolderList(); // Filesystem Processing Section // Now that we have folder list, lets start creating them foreach ($this->folderList as $folder) { if (!JFolder::exists($folder)) { if (!$created = JFolder::create($folder)) { JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ABORT_FILE_INSTALL_FAIL_SOURCE_DIRECTORY', $folder)); // If installation fails, rollback $this->parent->abort(); return false; } // Since we created a directory and will want to remove it if we have to roll back. // the installation due to some errors, let's add it to the installation step stack. if ($created) { $this->parent->pushStep(array('type' => 'folder', 'path' => $folder)); } } } // Now that we have file list, let's start copying them $this->parent->copyFiles($this->fileList); // Parse optional tags $this->parent->parseLanguages($this->manifest->languages); // Finalization and Cleanup Section // Get a database connector object $db = $this->parent->getDbo(); // Check to see if a module by the same name is already installed // If it is, then update the table because if the files aren't there // we can assume that it was (badly) uninstalled // If it isn't, add an entry to extensions $query = $db->getQuery(true); $query->select($query->qn('extension_id')) ->from($query->qn('#__extensions')); $query->where($query->qn('type') . ' = ' . $query->q('file')) ->where($query->qn('element') . ' = ' . $query->q($element)); $db->setQuery($query); try { $db->execute(); } catch (JException $e) { // Install failed, roll back changes $this->parent->abort( JText::sprintf('JLIB_INSTALLER_ABORT_FILE_ROLLBACK', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true)) ); return false; } $id = $db->loadResult(); $row = JTable::getInstance('extension'); if ($id) { // Load the entry and update the manifest_cache $row->load($id); // Update name $row->set('name', $this->get('name')); // Update manifest $row->manifest_cache = $this->parent->generateManifestCache(); if (!$row->store()) { // Install failed, roll back changes $this->parent->abort( JText::sprintf('JLIB_INSTALLER_ABORT_FILE_ROLLBACK', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true)) ); return false; } } else { // Add an entry to the extension table with a whole heap of defaults $row->set('name', $this->get('name')); $row->set('type', 'file'); $row->set('element', $this->get('element')); // There is no folder for files so leave it blank $row->set('folder', ''); $row->set('enabled', 1); $row->set('protected', 0); $row->set('access', 0); $row->set('client_id', 0); $row->set('params', ''); $row->set('system_data', ''); $row->set('manifest_cache', $this->parent->generateManifestCache()); if (!$row->store()) { // Install failed, roll back changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_FILE_INSTALL_ROLLBACK', $db->stderr(true))); return false; } // Set the insert id $row->set('extension_id', $db->insertid()); // Since we have created a module item, we add it to the installation step stack // so that if we have to rollback the changes we can undo it. $this->parent->pushStep(array('type' => 'extension', 'extension_id' => $row->extension_id)); } /* * Let's run the queries for the file */ // second argument is the utf compatible version attribute if (strtolower($this->route) == 'install') { $utfresult = $this->parent->parseSQLFiles($this->manifest->install->sql); if ($utfresult === false) { // Install failed, rollback changes $this->parent->abort( JText::sprintf('JLIB_INSTALLER_ABORT_FILE_INSTALL_SQL_ERROR', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true)) ); return false; } // Set the schema version to be the latest update version if ($this->manifest->update) { $this->parent->setSchemaVersion($this->manifest->update->schemas, $row->extension_id); } } elseif (strtolower($this->route) == 'update') { if ($this->manifest->update) { $result = $this->parent->parseSchemaUpdates($this->manifest->update->schemas, $row->extension_id); if ($result === false) { // Install failed, rollback changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_FILE_UPDATE_SQL_ERROR', $db->stderr(true))); return false; } } } // Start Joomla! 1.6 ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, $this->route)) { if ($this->parent->manifestClass->{$this->route}($this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } $msg .= ob_get_contents(); // append messages ob_end_clean(); // Lastly, we will copy the manifest file to its appropriate place. $manifest = array(); $manifest['src'] = $this->parent->getPath('manifest'); $manifest['dest'] = JPATH_MANIFESTS . '/files/' . basename($this->parent->getPath('manifest')); if (!$this->parent->copyFiles(array($manifest), true)) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_INSTALL_COPY_SETUP')); return false; } // Clobber any possible pending updates $update = JTable::getInstance('update'); $uid = $update->find( array('element' => $this->get('element'), 'type' => 'file', 'client_id' => '', 'folder' => '') ); if ($uid) { $update->delete($uid); } // And now we run the postflight ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'postflight')) { $this->parent->manifestClass->postflight($this->route, $this); } $msg .= ob_get_contents(); // append messages ob_end_clean(); if ($msg != '') { $this->parent->set('extension_message', $msg); } return $row->get('extension_id'); } /** * Custom update method * * @return boolean True on success * * @since 11.1 */ public function update() { // Set the overwrite setting $this->parent->setOverwrite(true); $this->parent->setUpgrade(true); $this->route = 'update'; // ...and adds new files return $this->install(); } /** * Custom uninstall method * * @param string $id The id of the file to uninstall * * @return boolean True on success * * @since 11.1 */ public function uninstall($id) { // Initialise variables. $row = JTable::getInstance('extension'); if (!$row->load($id)) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_LOAD_ENTRY')); return false; } if ($row->protected) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_WARNCOREFILE')); return false; } $retval = true; $manifestFile = JPATH_MANIFESTS . '/files/' . $row->element . '.xml'; // Because files may not have their own folders we cannot use the standard method of finding an installation manifest if (file_exists($manifestFile)) { // Set the plugin root path $this->parent->setPath('extension_root', JPATH_ROOT); // . '/files/' . $manifest->filename); $xml = JFactory::getXML($manifestFile); // If we cannot load the XML file return null if (!$xml) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_LOAD_MANIFEST')); return false; } /* * Check for a valid XML root tag. */ if ($xml->getName() != 'extension') { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_INVALID_MANIFEST')); return false; } $this->manifest = $xml; // If there is an manifest class file, let's load it $this->scriptElement = $this->manifest->scriptfile; $manifestScript = (string) $this->manifest->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('extension_root') . '/' . $manifestScript; if (is_file($manifestScriptFile)) { // Load the file include_once $manifestScriptFile; } // Set the class name $classname = $row->element . 'InstallerScript'; if (class_exists($classname)) { // Create a new instance $this->parent->manifestClass = new $classname($this); // And set this so we can copy it later $this->set('manifest_script', $manifestScript); // Note: if we don't find the class, don't bother to copy the file } } ob_start(); ob_implicit_flush(false); // Run uninstall if possible if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'uninstall')) { $this->parent->manifestClass->uninstall($this); } $msg = ob_get_contents(); ob_end_clean(); /* * Let's run the uninstall queries for the component * If Joomla 1.5 compatible, with discreet sql files - execute appropriate * file for utf-8 support or non-utf support */ // Try for Joomla 1.5 type queries // Second argument is the utf compatible version attribute $utfresult = $this->parent->parseSQLFiles($this->manifest->uninstall->sql); $db = JFactory::getDbo(); if ($utfresult === false) { // Install failed, rollback changes JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_SQL_ERROR', $db->stderr(true))); $retval = false; } // Remove the schema version $query = $db->getQuery(true); $query->delete() ->from('#__schemas') ->where('extension_id = ' . $row->extension_id); $db->setQuery($query); $db->execute(); // Set root folder names $packagePath = $this->parent->getPath('source'); $jRootPath = JPath::clean(JPATH_ROOT); // Loop through all elements and get list of files and folders foreach ($xml->fileset->files as $eFiles) { $folder = (string) $eFiles->attributes()->folder; $target = (string) $eFiles->attributes()->target; // Create folder path if (empty($target)) { $targetFolder = JPATH_ROOT; } else { $targetFolder = JPATH_ROOT . '/' . $target; } $folderList = array(); // Check if all children exists if (count($eFiles->children()) > 0) { // Loop through all filenames elements foreach ($eFiles->children() as $eFileName) { if ($eFileName->getName() == 'folder') { $folderList[] = $targetFolder . '/' . $eFileName; } else { $fileName = $targetFolder . '/' . $eFileName; JFile::delete($fileName); } } } // Delete any folders that don't have any content in them. foreach ($folderList as $folder) { $files = JFolder::files($folder); if (!count($files)) { JFolder::delete($folder); } } } JFile::delete($manifestFile); } else { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_INVALID_NOTFOUND_MANIFEST')); // Delete the row because its broken $row->delete(); return false; } $this->parent->removeFiles($xml->languages); $row->delete(); return $retval; } /** * Function used to check if extension is already installed * * @param string $extension The element name of the extension to install * * @return boolean True if extension exists * * @since 11.1 */ protected function extensionExistsInSystem($extension = null) { // Get a database connector object $db = $this->parent->getDBO(); $query = $db->getQuery(true); $query->select($query->qn('extension_id')) ->from($query->qn('#__extensions')); $query->where($query->qn('type') . ' = ' . $query->q('file')) ->where($query->qn('element') . ' = ' . $query->q($extension)); $db->setQuery($query); try { $db->execute(); } catch (JException $e) { // Install failed, roll back changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_FILE_ROLLBACK', $db->stderr(true))); return false; } $id = $db->loadResult(); if (empty($id)) { return false; } return true; } /** * Function used to populate files and folder list * * @return boolean none * * @since 11.1 */ protected function populateFilesAndFolderList() { // Initialise variable $this->folderList = array(); $this->fileList = array(); // Get fileset $eFileset = $this->manifest->fileset->files; // Set root folder names $packagePath = $this->parent->getPath('source'); $jRootPath = JPath::clean(JPATH_ROOT); // Loop through all elements and get list of files and folders foreach ($this->manifest->fileset->files as $eFiles) { // Check if the element is files element $folder = (string) $eFiles->attributes()->folder; $target = (string) $eFiles->attributes()->target; //Split folder names into array to get folder names. This will // help in creating folders $arrList = preg_split("#/|\\/#", $target); $folderName = $jRootPath; foreach ($arrList as $dir) { if (empty($dir)) { continue; } $folderName .= '/' . $dir; // Check if folder exists, if not then add to the array for folder creation if (!JFolder::exists($folderName)) { array_push($this->folderList, $folderName); } } // Create folder path $sourceFolder = empty($folder) ? $packagePath : $packagePath . '/' . $folder; $targetFolder = empty($target) ? $jRootPath : $jRootPath . '/' . $target; // Check if source folder exists if (!JFolder::exists($sourceFolder)) { JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ABORT_FILE_INSTALL_FAIL_SOURCE_DIRECTORY', $sourceFolder)); // If installation fails, rollback $this->parent->abort(); return false; } // Check if all children exists if (count($eFiles->children())) { // Loop through all filenames elements foreach ($eFiles->children() as $eFileName) { $path['src'] = $sourceFolder . '/' . $eFileName; $path['dest'] = $targetFolder . '/' . $eFileName; $path['type'] = 'file'; if ($eFileName->getName() == 'folder') { $folderName = $targetFolder . '/' . $eFileName; array_push($this->folderList, $folderName); $path['type'] = 'folder'; } array_push($this->fileList, $path); } } else { $files = JFolder::files($sourceFolder); foreach ($files as $file) { $path['src'] = $sourceFolder . '/' . $file; $path['dest'] = $targetFolder . '/' . $file; array_push($this->fileList, $path); } } } } /** * Refreshes the extension table cache * * @return boolean result of operation, true if updated, false on failure * * @since 11.1 */ public function refreshManifestCache() { // Need to find to find where the XML file is since we don't store this normally $manifestPath = JPATH_MANIFESTS . '/files/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; try { return $this->parent->extension->store(); } catch (JException $e) { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_PACK_REFRESH_MANIFEST_CACHE')); return false; } } } adapters/package.php000066600000035574151372561050010502 0ustar00manifest = $this->parent->getManifest(); $extension = 'pkg_' . strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->packagename, 'cmd')); $lang = JFactory::getLanguage(); $source = $path; $lang->load($extension . '.sys', $source, null, false, true) || $lang->load($extension . '.sys', JPATH_SITE, null, false, true); } /** * Custom install method * * @return int The extension id * * @since 11.1 */ public function install() { // Get the extension manifest object $this->manifest = $this->parent->getManifest(); // Manifest Document Setup Section // Set the extensions name $filter = JFilterInput::getInstance(); $name = (string) $this->manifest->packagename; $name = $filter->clean($name, 'cmd'); $this->set('name', $name); $element = 'pkg_' . $filter->clean($this->manifest->packagename, 'cmd'); $this->set('element', $element); // Get the component description $description = (string) $this->manifest->description; if ($description) { $this->parent->set('message', JText::_($description)); } else { $this->parent->set('message', ''); } // Set the installation path $files = $this->manifest->files; $group = (string) $this->manifest->packagename; if (!empty($group)) { $this->parent->setPath('extension_root', JPATH_MANIFESTS . '/packages/' . implode(DIRECTORY_SEPARATOR, explode('/', $group))); } else { $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PACK_INSTALL_NO_PACK', JText::_('JLIB_INSTALLER_' . strtoupper($this->route)))); return false; } /** * --------------------------------------------------------------------------------------------- * Installer Trigger Loading * --------------------------------------------------------------------------------------------- */ // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet) $this->scriptElement = $this->manifest->scriptfile; $manifestScript = (string) $this->manifest->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript; if (is_file($manifestScriptFile)) { // load the file include_once $manifestScriptFile; } // Set the class name $classname = $element . 'InstallerScript'; if (class_exists($classname)) { // create a new instance $this->parent->manifestClass = new $classname($this); // and set this so we can copy it later $this->set('manifest_script', $manifestScript); // Note: if we don't find the class, don't bother to copy the file } } // run preflight if possible (since we know we're not an update) ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight')) { if ($this->parent->manifestClass->preflight($this->route, $this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_PACKAGE_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } $msg = ob_get_contents(); // create msg object; first use here ob_end_clean(); // Filesystem Processing Section if ($folder = $files->attributes()->folder) { $source = $this->parent->getPath('source') . '/' . $folder; } else { $source = $this->parent->getPath('source'); } // Install all necessary files if (count($this->manifest->files->children())) { $i = 0; foreach ($this->manifest->files->children() as $child) { $file = $source . '/' . $child; if (is_dir($file)) { // If it's actually a directory then fill it up $package = array(); $package['dir'] = $file; $package['type'] = JInstallerHelper::detectType($file); } else { // If it's an archive $package = JInstallerHelper::unpack($file); } $tmpInstaller = new JInstaller; $installResult = $tmpInstaller->install($package['dir']); if (!$installResult) { $this->parent->abort( JText::sprintf( 'JLIB_INSTALLER_ABORT_PACK_INSTALL_ERROR_EXTENSION', JText::_('JLIB_INSTALLER_' . strtoupper($this->route)), basename($file) ) ); return false; } else { $results[$i] = array( 'name' => $tmpInstaller->manifest->name, 'result' => $installResult ); } $i++; } } else { $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PACK_INSTALL_NO_FILES', JText::_('JLIB_INSTALLER_' . strtoupper($this->route)))); return false; } // Parse optional tags $this->parent->parseLanguages($this->manifest->languages); // Extension Registration $row = JTable::getInstance('extension'); $eid = $row->find(array('element' => strtolower($this->get('element')), 'type' => 'package')); if ($eid) { $row->load($eid); } else { $row->name = $this->get('name'); $row->type = 'package'; $row->element = $this->get('element'); // There is no folder for modules $row->folder = ''; $row->enabled = 1; $row->protected = 0; $row->access = 1; $row->client_id = 0; // custom data $row->custom_data = ''; $row->params = $this->parent->getParams(); } // Update the manifest cache for the entry $row->manifest_cache = $this->parent->generateManifestCache(); if (!$row->store()) { // Install failed, roll back changes $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PACK_INSTALL_ROLLBACK', $row->getError())); return false; } // Finalization and Cleanup Section // Start Joomla! 1.6 ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, $this->route)) { if ($this->parent->manifestClass->{$this->route}($this) === false) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_INSTALL_CUSTOM_INSTALL_FAILURE')); return false; } } $msg .= ob_get_contents(); // append messages ob_end_clean(); // Lastly, we will copy the manifest file to its appropriate place. $manifest = array(); $manifest['src'] = $this->parent->getPath('manifest'); $manifest['dest'] = JPATH_MANIFESTS . '/packages/' . basename($this->parent->getPath('manifest')); if (!$this->parent->copyFiles(array($manifest), true)) { // Install failed, rollback changes $this->parent->abort( JText::sprintf('JLIB_INSTALLER_ABORT_PACK_INSTALL_COPY_SETUP', JText::_('JLIB_INSTALLER_ABORT_PACK_INSTALL_NO_FILES')) ); return false; } // If there is a manifest script, let's copy it. if ($this->get('manifest_script')) { // First, we have to create a folder for the script if one isn't present $created = false; if (!file_exists($this->parent->getPath('extension_root'))) { JFolder::create($this->parent->getPath('extension_root')); } $path['src'] = $this->parent->getPath('source') . '/' . $this->get('manifest_script'); $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->get('manifest_script'); if (!file_exists($path['dest']) || $this->parent->isOverwrite()) { if (!$this->parent->copyFiles(array($path))) { // Install failed, rollback changes $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_PACKAGE_INSTALL_MANIFEST')); return false; } } } // And now we run the postflight ob_start(); ob_implicit_flush(false); if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'postflight')) { $this->parent->manifestClass->postflight($this->route, $this, $results); } $msg .= ob_get_contents(); // append messages ob_end_clean(); if ($msg != '') { $this->parent->set('extension_message', $msg); } return $row->extension_id; } /** * Updates a package * * The only difference between an update and a full install * is how we handle the database * * @return void * * @since 11.1 */ public function update() { $this->route = 'update'; $this->install(); } /** * Custom uninstall method * * @param integer $id The id of the package to uninstall. * * @return boolean True on success * * @since 11.1 */ public function uninstall($id) { // Initialise variables. $row = null; $retval = true; $row = JTable::getInstance('extension'); $row->load($id); if ($row->protected) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_WARNCOREPACK')); return false; } $manifestFile = JPATH_MANIFESTS . '/packages/' . $row->get('element') . '.xml'; $manifest = new JPackageManifest($manifestFile); // Set the package root path $this->parent->setPath('extension_root', JPATH_MANIFESTS . '/packages/' . $manifest->packagename); // Because packages may not have their own folders we cannot use the standard method of finding an installation manifest if (!file_exists($manifestFile)) { // TODO: Fail? JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_MISSINGMANIFEST')); return false; } $xml = JFactory::getXML($manifestFile); // If we cannot load the XML file return false if (!$xml) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_LOAD_MANIFEST')); return false; } /* * Check for a valid XML root tag. * @todo: Remove backwards compatibility in a future version * Should be 'extension', but for backward compatibility we will accept 'install'. */ if ($xml->getName() != 'install' && $xml->getName() != 'extension') { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_INVALID_MANIFEST')); return false; } // If there is an manifest class file, let's load it $this->scriptElement = $manifest->scriptfile; $manifestScript = (string) $manifest->scriptfile; if ($manifestScript) { $manifestScriptFile = $this->parent->getPath('extension_root') . '/' . $manifestScript; if (is_file($manifestScriptFile)) { // Load the file include_once $manifestScriptFile; } // Set the class name $classname = $row->element . 'InstallerScript'; if (class_exists($classname)) { // Create a new instance $this->parent->manifestClass = new $classname($this); // And set this so we can copy it later $this->set('manifest_script', $manifestScript); // Note: if we don't find the class, don't bother to copy the file } } ob_start(); ob_implicit_flush(false); // Run uninstall if possible if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'uninstall')) { $this->parent->manifestClass->uninstall($this); } $msg = ob_get_contents(); ob_end_clean(); $error = false; foreach ($manifest->filelist as $extension) { $tmpInstaller = new JInstaller; $id = $this->_getExtensionID($extension->type, $extension->id, $extension->client, $extension->group); $client = JApplicationHelper::getClientInfo($extension->client, true); if ($id) { if (!$tmpInstaller->uninstall($extension->type, $id, $client->id)) { $error = true; JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_NOT_PROPER', basename($extension->filename))); } } else { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_UNKNOWN_EXTENSION')); } } // Remove any language files $this->parent->removeFiles($xml->languages); // clean up manifest file after we're done if there were no errors if (!$error) { JFile::delete($manifestFile); $folder = $this->parent->getPath('extension_root'); if (JFolder::exists($folder)) { JFolder::delete($folder); } $row->delete(); } else { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_MANIFEST_NOT_REMOVED')); } // Return the result up the line return $retval; } /** * Gets the extension id. * * @param string $type The extension type. * @param string $id The name of the extension (the element field). * @param integer $client The application id (0: Joomla CMS site; 1: Joomla CMS administrator). * @param string $group The extension group (mainly for plugins). * * @return integer * * @since 11.1 */ protected function _getExtensionID($type, $id, $client, $group) { $db = $this->parent->getDbo(); $result = $id; $query = $db->getQuery(true); $query->select('extension_id'); $query->from('#__extensions'); $query->where('type = ' . $db->Quote($type)); $query->where('element = ' . $db->Quote($id)); switch ($type) { case 'plugin': // Plugins have a folder but not a client $query->where('folder = ' . $db->Quote($group)); break; case 'library': case 'package': case 'component': // Components, packages and libraries don't have a folder or client. // Included for completeness. break; case 'language': case 'module': case 'template': // Languages, modules and templates have a client but not a folder $client = JApplicationHelper::getClientInfo($client, true); $query->where('client_id = ' . (int) $client->id); break; } $db->setQuery($query); $result = $db->loadResult(); // Note: For templates, libraries and packages their unique name is their key. // This means they come out the same way they came in. return $result; } /** * Refreshes the extension table cache * * @return boolean Result of operation, true if updated, false on failure * * @since 11.1 */ public function refreshManifestCache() { // Need to find to find where the XML file is since we don't store this normally $manifestPath = JPATH_MANIFESTS . '/packages/' . $this->parent->extension->element . '.xml'; $this->parent->manifest = $this->parent->isManifest($manifestPath); $this->parent->setPath('manifest', $manifestPath); $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest')); $this->parent->extension->manifest_cache = json_encode($manifest_details); $this->parent->extension->name = $manifest_details['name']; try { return $this->parent->extension->store(); } catch (JException $e) { JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_PACK_REFRESH_MANIFEST_CACHE')); return false; } } } helper.php000066600000016460151372561050006554 0ustar00getUserAgent('Installer')); $http = JHttpFactory::getHttp(); // load installer plugins, and allow url and headers modification $headers = array(); JPluginHelper::importPlugin('installer'); $dispatcher = JDispatcher::getInstance(); $results = $dispatcher->trigger('onInstallerBeforePackageDownload', array(&$url, &$headers)); try { $response = $http->get($url, $headers); } catch (Exception $exc) { $response = null; } if (is_null($response)) { JError::raiseWarning(42, JText::_('JLIB_INSTALLER_ERROR_DOWNLOAD_SERVER_CONNECT')); return false; } if (302 == $response->code && isset($response->headers['Location'])) { return self::downloadPackage($response->headers['Location']); } elseif (200 != $response->code) { if ($response->body === '') { $response->body = $php_errormsg; } JError::raiseWarning(42, JText::sprintf('JLIB_INSTALLER_ERROR_DOWNLOAD_SERVER_CONNECT', $response->body)); return false; } // Parse the Content-Disposition header to get the file name if (isset($response->headers['Content-Disposition']) && preg_match("/\s*filename\s?=\s?(.*)/", $response->headers['Content-Disposition'], $parts)) { $target = trim(rtrim($parts[1], ";"), '"'); } // Set the target path if not given if (!$target) { $target = $config->get('tmp_path') . '/' . self::getFilenameFromURL($url); } else { $target = $config->get('tmp_path') . '/' . basename($target); } // Write buffer to file JFile::write($target, $response->body); // Restore error tracking to what it was before ini_set('track_errors', $track_errors); // bump the max execution time because not using built in php zip libs are slow @set_time_limit(ini_get('max_execution_time')); // Return the name of the downloaded package return basename($target); } /** * Unpacks a file and verifies it as a Joomla element package * Supports .gz .tar .tar.gz and .zip * * @param string $p_filename The uploaded package filename or install directory * * @return array Two elements: extractdir and packagefile * * @since 11.1 */ public static function unpack($p_filename) { // Path to the archive $archivename = $p_filename; // Temporary folder to extract the archive into $tmpdir = uniqid('install_'); // Clean the paths to use for archive extraction $extractdir = JPath::clean(dirname($p_filename) . '/' . $tmpdir); $archivename = JPath::clean($archivename); // Do the unpacking of the archive $result = JArchive::extract($archivename, $extractdir); if ($result === false) { return false; } /* * Let's set the extraction directory and package file in the result array so we can * cleanup everything properly later on. */ $retval['extractdir'] = $extractdir; $retval['packagefile'] = $archivename; /* * Try to find the correct install directory. In case the package is inside a * subdirectory detect this and set the install directory to the correct path. * * List all the items in the installation directory. If there is only one, and * it is a folder, then we will set that folder to be the installation folder. */ $dirList = array_merge(JFolder::files($extractdir, ''), JFolder::folders($extractdir, '')); if (count($dirList) == 1) { if (JFolder::exists($extractdir . '/' . $dirList[0])) { $extractdir = JPath::clean($extractdir . '/' . $dirList[0]); } } /* * We have found the install directory so lets set it and then move on * to detecting the extension type. */ $retval['dir'] = $extractdir; /* * Get the extension type and return the directory/type array on success or * false on fail. */ if ($retval['type'] = self::detectType($extractdir)) { return $retval; } else { return false; } } /** * Method to detect the extension type from a package directory * * @param string $p_dir Path to package directory * * @return mixed Extension type string or boolean false on fail * * @since 11.1 */ public static function detectType($p_dir) { // Search the install dir for an XML file $files = JFolder::files($p_dir, '\.xml$', 1, true); if (!count($files)) { JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ERROR_NOTFINDXMLSETUPFILE')); return false; } foreach ($files as $file) { if (!$xml = JFactory::getXML($file)) { continue; } if ($xml->getName() != 'install' && $xml->getName() != 'extension') { unset($xml); continue; } $type = (string) $xml->attributes()->type; // Free up memory unset($xml); return $type; } JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ERROR_NOTFINDJOOMLAXMLSETUPFILE')); // Free up memory. unset($xml); return false; } /** * Gets a file name out of a url * * @param string $url URL to get name from * * @return mixed String filename or boolean false if failed * * @since 11.1 */ public static function getFilenameFromURL($url) { if (is_string($url)) { $parts = explode('/', $url); return $parts[count($parts) - 1]; } return false; } /** * Clean up temporary uploaded package and unpacked extension * * @param string $package Path to the uploaded package file * @param string $resultdir Path to the unpacked extension * * @return boolean True on success * * @since 11.1 */ public static function cleanupInstall($package, $resultdir) { $config = JFactory::getConfig(); // Does the unpacked extension directory exist? if (is_dir($resultdir)) { JFolder::delete($resultdir); } // Is the package file a valid file? if (is_file($package)) { JFile::delete($package); } elseif (is_file(JPath::clean($config->get('tmp_path') . '/' . $package))) { // It might also be just a base filename JFile::delete(JPath::clean($config->get('tmp_path') . '/' . $package)); } } /** * Splits contents of a sql file into array of discreet queries. * Queries need to be delimited with end of statement marker ';' * * @param string $sql The SQL statement. * * @return array Array of queries * * @since 11.1 */ public static function splitSql($sql) { $db = JFactory::getDbo(); return $db->splitSql($sql); } } index.html000066600000000037151372561050006552 0ustar00 installer.php000066600000144066151372561050007276 0ustar00isOverwrite(); } /** * Get the allow overwrite switch * * @return boolean Allow overwrite switch * * @since 11.4 */ public function isOverwrite() { return $this->_overwrite; } /** * Set the allow overwrite switch * * @param boolean $state Overwrite switch state * * @return boolean True it state is set, false if it is not * * @since 11.1 */ public function setOverwrite($state = false) { $tmp = $this->_overwrite; if ($state) { $this->_overwrite = true; } else { $this->_overwrite = false; } return $tmp; } /** * Get the redirect location * * @return string Redirect location (or null) * * @since 11.1 */ public function getRedirectURL() { return $this->redirect_url; } /** * Set the redirect location * * @param string $newurl New redirect location * * @return void * * @since 11.1 */ public function setRedirectURL($newurl) { $this->redirect_url = $newurl; } /** * Get the upgrade switch * * @return boolean * * @since 11.1 * @deprecated 12.1 Use JInstaller::isUpgrade() */ public function getUpgrade() { JLog::add('JInstaller::getUpgrade() is deprecated. Please use JInstaller::isUpgrade() instead', JLog::WARNING, 'deprecated'); return $this->isUpgrade(); } /** * Get the upgrade switch * * @return boolean * * @since 11.4 */ public function isUpgrade() { return $this->_upgrade; } /** * Set the upgrade switch * * @param boolean $state Upgrade switch state * * @return boolean True if upgrade, false otherwise * * @since 11.1 */ public function setUpgrade($state = false) { $tmp = $this->_upgrade; if ($state) { $this->_upgrade = true; } else { $this->_upgrade = false; } return $tmp; } /** * Get the installation manifest object * * @return object Manifest object * * @since 11.1 */ public function getManifest() { if (!is_object($this->manifest)) { $this->findManifest(); } return $this->manifest; } /** * Get an installer path by name * * @param string $name Path name * @param string $default Default value * * @return string Path * * @since 11.1 */ public function getPath($name, $default = null) { return (!empty($this->_paths[$name])) ? $this->_paths[$name] : $default; } /** * Sets an installer path by name * * @param string $name Path name * @param string $value Path * * @return void * * @since 11.1 */ public function setPath($name, $value) { $this->_paths[$name] = $value; } /** * Pushes a step onto the installer stack for rolling back steps * * @param array $step Installer step * * @return void * * @since 11.1 */ public function pushStep($step) { $this->_stepStack[] = $step; } /** * Installation abort method * * @param string $msg Abort message from the installer * @param string $type Package type if defined * * @return boolean True if successful * * @since 11.1 */ public function abort($msg = null, $type = null) { // Initialise variables. $retval = true; $step = array_pop($this->_stepStack); // Raise abort warning if ($msg) { JError::raiseWarning(100, $msg); } while ($step != null) { switch ($step['type']) { case 'file': // Remove the file $stepval = JFile::delete($step['path']); break; case 'folder': // Remove the folder $stepval = JFolder::delete($step['path']); break; case 'query': // Placeholder in case this is necessary in the future // $stepval is always false because if this step was called it invariably failed $stepval = false; break; case 'extension': // Get database connector object $db = $this->getDBO(); $query = $db->getQuery(true); // Remove the entry from the #__extensions table $query->delete($db->quoteName('#__extensions')); $query->where($db->quoteName('extension_id') . ' = ' . (int) $step['id']); $db->setQuery($query); $stepval = $db->execute(); break; default: if ($type && is_object($this->_adapters[$type])) { // Build the name of the custom rollback method for the type $method = '_rollback_' . $step['type']; // Custom rollback method handler if (method_exists($this->_adapters[$type], $method)) { $stepval = $this->_adapters[$type]->$method($step); } } else { $stepval = false; // set it to false } break; } // Only set the return value if it is false if ($stepval === false) { $retval = false; } // Get the next step and continue $step = array_pop($this->_stepStack); } $conf = JFactory::getConfig(); $debug = $conf->get('debug'); if ($debug) { JError::raiseError(500, JText::_('JLIB_INSTALLER_ABORT_DEBUG') . $msg); } return $retval; } // Adapter functions /** * Package installation method * * @param string $path Path to package source folder * * @return boolean True if successful * * @since 11.1 */ public function install($path = null) { if ($path && JFolder::exists($path)) { $this->setPath('source', $path); } else { $this->abort(JText::_('JLIB_INSTALLER_ABORT_NOINSTALLPATH')); return false; } if (!$this->setupInstall()) { $this->abort(JText::_('JLIB_INSTALLER_ABORT_DETECTMANIFEST')); return false; } $type = (string) $this->manifest->attributes()->type; if (is_object($this->_adapters[$type])) { // Add the languages from the package itself if (method_exists($this->_adapters[$type], 'loadLanguage')) { $this->_adapters[$type]->loadLanguage($path); } // Fire the onExtensionBeforeInstall event. JPluginHelper::importPlugin('extension'); $dispatcher = JDispatcher::getInstance(); $dispatcher->trigger( 'onExtensionBeforeInstall', array('method' => 'install', 'type' => $type, 'manifest' => $this->manifest, 'extension' => 0) ); // Run the install $result = $this->_adapters[$type]->install(); // Fire the onExtensionAfterInstall $dispatcher->trigger( 'onExtensionAfterInstall', array('installer' => clone $this, 'eid' => $result) ); if ($result !== false) { return true; } else { return false; } } return false; } /** * Discovered package installation method * * @param integer $eid Extension ID * * @return boolean True if successful * * @since 11.1 */ public function discover_install($eid = null) { if ($eid) { $this->extension = JTable::getInstance('extension'); if (!$this->extension->load($eid)) { $this->abort(JText::_('JLIB_INSTALLER_ABORT_LOAD_DETAILS')); return false; } if ($this->extension->state != -1) { $this->abort(JText::_('JLIB_INSTALLER_ABORT_ALREADYINSTALLED')); return false; } // Lazy load the adapter if (!isset($this->_adapters[$this->extension->type]) || !is_object($this->_adapters[$this->extension->type])) { if (!$this->setAdapter($this->extension->type)) { return false; } } if (is_object($this->_adapters[$this->extension->type])) { if (method_exists($this->_adapters[$this->extension->type], 'discover_install')) { // Add the languages from the package itself if (method_exists($this->_adapters[$this->extension->type], 'loadLanguage')) { $this->_adapters[$this->extension->type]->loadLanguage(); } // Fire the onExtensionBeforeInstall event. JPluginHelper::importPlugin('extension'); $dispatcher = JDispatcher::getInstance(); $dispatcher->trigger( 'onExtensionBeforeInstall', array( 'method' => 'discover_install', 'type' => $this->extension->get('type'), 'manifest' => null, 'extension' => $this->extension->get('extension_id') ) ); // Run the install $result = $this->_adapters[$this->extension->type]->discover_install(); // Fire the onExtensionAfterInstall $dispatcher->trigger( 'onExtensionAfterInstall', array('installer' => clone $this, 'eid' => $result) ); if ($result !== false) { return true; } else { return false; } } else { $this->abort(JText::_('JLIB_INSTALLER_ABORT_METHODNOTSUPPORTED')); return false; } } return false; } else { $this->abort(JText::_('JLIB_INSTALLER_ABORT_EXTENSIONNOTVALID')); return false; } } /** * Extension discover method * Asks each adapter to find extensions * * @return array JExtension * * @since 11.1 */ public function discover() { $this->loadAllAdapters(); $results = array(); foreach ($this->_adapters as $adapter) { // Joomla! 1.5 installation adapter legacy support if (method_exists($adapter, 'discover')) { $tmp = $adapter->discover(); // if its an array and has entries if (is_array($tmp) && count($tmp)) { // merge it into the system $results = array_merge($results, $tmp); } } } return $results; } /** * Package update method * * @param string $path Path to package source folder * * @return boolean True if successful * * @since 11.1 */ public function update($path = null) { if ($path && JFolder::exists($path)) { $this->setPath('source', $path); } else { $this->abort(JText::_('JLIB_INSTALLER_ABORT_NOUPDATEPATH')); return false; } if (!$this->setupInstall()) { $this->abort(JText::_('JLIB_INSTALLER_ABORT_DETECTMANIFEST')); return false; } $type = (string) $this->manifest->attributes()->type; if (is_object($this->_adapters[$type])) { // Add the languages from the package itself if (method_exists($this->_adapters[$type], 'loadLanguage')) { $this->_adapters[$type]->loadLanguage($path); } // Fire the onExtensionBeforeUpdate event. JPluginHelper::importPlugin('extension'); $dispatcher = JDispatcher::getInstance(); $dispatcher->trigger('onExtensionBeforeUpdate', array('type' => $type, 'manifest' => $this->manifest)); // Run the update $result = $this->_adapters[$type]->update(); // Fire the onExtensionAfterUpdate $dispatcher->trigger( 'onExtensionAfterUpdate', array('installer' => clone $this, 'eid' => $result) ); if ($result !== false) { return true; } else { return false; } } return false; } /** * Package uninstallation method * * @param string $type Package type * @param mixed $identifier Package identifier for adapter * @param integer $cid Application ID; deprecated in 1.6 * * @return boolean True if successful * * @since 11.1 */ public function uninstall($type, $identifier, $cid = 0) { if (!isset($this->_adapters[$type]) || !is_object($this->_adapters[$type])) { if (!$this->setAdapter($type)) { // We failed to get the right adapter return false; } } if (is_object($this->_adapters[$type])) { // We don't load languages here, we get the extension adapter to work it out // Fire the onExtensionBeforeUninstall event. JPluginHelper::importPlugin('extension'); $dispatcher = JDispatcher::getInstance(); $dispatcher->trigger('onExtensionBeforeUninstall', array('eid' => $identifier)); // Run the uninstall $result = $this->_adapters[$type]->uninstall($identifier); // Fire the onExtensionAfterInstall $dispatcher->trigger( 'onExtensionAfterUninstall', array('installer' => clone $this, 'eid' => $identifier, 'result' => $result) ); return $result; } return false; } /** * Refreshes the manifest cache stored in #__extensions * * @param integer $eid Extension ID * * @return mixed void on success, false on error @todo missing return value ? * * @since 11.1 */ public function refreshManifestCache($eid) { if ($eid) { $this->extension = JTable::getInstance('extension'); if (!$this->extension->load($eid)) { $this->abort(JText::_('JLIB_INSTALLER_ABORT_LOAD_DETAILS')); return false; } if ($this->extension->state == -1) { $this->abort(JText::_('JLIB_INSTALLER_ABORT_REFRESH_MANIFEST_CACHE')); return false; } // Lazy load the adapter if (!isset($this->_adapters[$this->extension->type]) || !is_object($this->_adapters[$this->extension->type])) { if (!$this->setAdapter($this->extension->type)) { return false; } } if (is_object($this->_adapters[$this->extension->type])) { if (method_exists($this->_adapters[$this->extension->type], 'refreshManifestCache')) { $result = $this->_adapters[$this->extension->type]->refreshManifestCache(); if ($result !== false) { return true; } else { return false; } } else { $this->abort(JText::sprintf('JLIB_INSTALLER_ABORT_METHODNOTSUPPORTED_TYPE', $this->extension->type)); return false; } } return false; } else { $this->abort(JText::_('JLIB_INSTALLER_ABORT_REFRESH_MANIFEST_CACHE_VALID')); return false; } } // Utility functions /** * Prepare for installation: this method sets the installation directory, finds * and checks the installation file and verifies the installation type. * * @return boolean True on success * * @since 11.1 */ public function setupInstall() { // We need to find the installation manifest file if (!$this->findManifest()) { return false; } // Load the adapter(s) for the install manifest $type = (string) $this->manifest->attributes()->type; // Lazy load the adapter if (!isset($this->_adapters[$type]) || !is_object($this->_adapters[$type])) { if (!$this->setAdapter($type)) { return false; } } return true; } /** * Backward compatible method to parse through a queries element of the * installation manifest file and take appropriate action. * * @param SimpleXMLElement $element The XML node to process * * @return mixed Number of queries processed or False on error * * @since 11.1 */ public function parseQueries($element) { // Get the database connector object $db = & $this->_db; if (!$element || !count($element->children())) { // Either the tag does not exist or has no children therefore we return zero files processed. return 0; } // Get the array of query nodes to process $queries = $element->children(); if (count($queries) == 0) { // No queries to process return 0; } // Process each query in the $queries array (children of $tagName). foreach ($queries as $query) { $db->setQuery($query->data()); if (!$db->execute()) { JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_SQL_ERROR', $db->stderr(true))); return false; } } return (int) count($queries); } /** * Method to extract the name of a discreet installation sql file from the installation manifest file. * * @param object $element The XML node to process * * @return mixed Number of queries processed or False on error * * @since 11.1 */ public function parseSQLFiles($element) { if (!$element || !count($element->children())) { // The tag does not exist. return 0; } // Initialise variables. $queries = array(); $db = & $this->_db; $dbDriver = strtolower($db->name); if ($dbDriver == 'mysqli') { $dbDriver = 'mysql'; } elseif($dbDriver == 'sqlsrv') { $dbDriver = 'sqlazure'; } // Get the name of the sql file to process $sqlfile = ''; foreach ($element->children() as $file) { $fCharset = (strtolower($file->attributes()->charset) == 'utf8') ? 'utf8' : ''; $fDriver = strtolower($file->attributes()->driver); if ($fDriver == 'mysqli') { $fDriver = 'mysql'; } elseif($fDriver == 'sqlsrv') { $fDriver = 'sqlazure'; } if ($fCharset == 'utf8' && $fDriver == $dbDriver) { $sqlfile = $this->getPath('extension_root') . '/' . trim($file); // Check that sql files exists before reading. Otherwise raise error for rollback if (!file_exists($sqlfile)) { JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_SQL_FILENOTFOUND', $sqlfile)); return false; } $buffer = file_get_contents($sqlfile); // Graceful exit and rollback if read not successful if ($buffer === false) { JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ERROR_SQL_READBUFFER')); return false; } // Create an array of queries from the sql file $queries = JInstallerHelper::splitSql($buffer); if (count($queries) == 0) { // No queries to process return 0; } // Process each query in the $queries array (split out of sql file). foreach ($queries as $query) { $query = trim($query); if ($query != '' && $query{0} != '#') { $db->setQuery($query); if (!$db->execute()) { JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_SQL_ERROR', $db->stderr(true))); return false; } } } } } return (int) count($queries); } /** * Set the schema version for an extension by looking at its latest update * * @param SimpleXMLElement $schema Schema Tag * @param integer $eid Extension ID * * @return void * * @since 11.1 */ public function setSchemaVersion($schema, $eid) { if ($eid && $schema) { $db = JFactory::getDBO(); $schemapaths = $schema->children(); if (!$schemapaths) { return; } if (count($schemapaths)) { $dbDriver = strtolower($db->name); if ($dbDriver == 'mysqli') { $dbDriver = 'mysql'; } elseif ($dbDriver == 'sqlsrv') { $dbDriver = 'sqlazure'; } $schemapath = ''; foreach ($schemapaths as $entry) { $attrs = $entry->attributes(); if ($attrs['type'] == $dbDriver) { $schemapath = $entry; break; } } if (strlen($schemapath)) { $files = str_replace('.sql', '', JFolder::files($this->getPath('extension_root') . '/' . $schemapath, '\.sql$')); usort($files, 'version_compare'); // Update the database $query = $db->getQuery(true); $query->delete() ->from('#__schemas') ->where('extension_id = ' . $eid); $db->setQuery($query); if ($db->execute()) { $query->clear(); $query->insert($db->quoteName('#__schemas')); $query->columns(array($db->quoteName('extension_id'), $db->quoteName('version_id'))); $query->values($eid . ', ' . $db->quote(end($files))); $db->setQuery($query); $db->execute(); } } } } } /** * Method to process the updates for an item * * @param SimpleXMLElement $schema The XML node to process * @param integer $eid Extension Identifier * * @return boolean Result of the operations * * @since 11.1 */ public function parseSchemaUpdates($schema, $eid) { $files = array(); $update_count = 0; // Ensure we have an XML element and a valid extension id if ($eid && $schema) { $db = JFactory::getDBO(); $schemapaths = $schema->children(); if (count($schemapaths)) { $dbDriver = strtolower($db->name); if ($dbDriver == 'mysqli') { $dbDriver = 'mysql'; } elseif ($dbDriver == 'sqlsrv') { $dbDriver = 'sqlazure'; } $schemapath = ''; foreach ($schemapaths as $entry) { $attrs = $entry->attributes(); if ($attrs['type'] == $dbDriver) { $schemapath = $entry; break; } } if (strlen($schemapath)) { $files = str_replace('.sql', '', JFolder::files($this->getPath('extension_root') . '/' . $schemapath, '\.sql$')); usort($files, 'version_compare'); if (!count($files)) { return false; } $query = $db->getQuery(true); $query->select('version_id') ->from('#__schemas') ->where('extension_id = ' . $eid); $db->setQuery($query); $version = $db->loadResult(); if ($version) { // We have a version! foreach ($files as $file) { if (version_compare($file, $version) > 0) { $buffer = file_get_contents($this->getPath('extension_root') . '/' . $schemapath . '/' . $file . '.sql'); // Graceful exit and rollback if read not successful if ($buffer === false) { JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ERROR_SQL_READBUFFER')); return false; } // Create an array of queries from the sql file $queries = JInstallerHelper::splitSql($buffer); if (count($queries) == 0) { // No queries to process continue; } // Process each query in the $queries array (split out of sql file). foreach ($queries as $query) { $query = trim($query); if ($query != '' && $query{0} != '#') { $db->setQuery($query); if (!$db->execute()) { JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_SQL_ERROR', $db->stderr(true))); return false; } $update_count++; } } } } } // Update the database $query = $db->getQuery(true); $query->delete() ->from('#__schemas') ->where('extension_id = ' . $eid); $db->setQuery($query); if ($db->execute()) { $query->clear(); $query->insert($db->quoteName('#__schemas')); $query->columns(array($db->quoteName('extension_id'), $db->quoteName('version_id'))); $query->values($eid . ', ' . $db->quote(end($files))); $db->setQuery($query); $db->execute(); } } } } return $update_count; } /** * Method to parse through a files element of the installation manifest and take appropriate * action. * * @param SimpleXMLElement $element The XML node to process * @param integer $cid Application ID of application to install to * @param array $oldFiles List of old files (SimpleXMLElement's) * @param array $oldMD5 List of old MD5 sums (indexed by filename with value as MD5) * * @return boolean True on success * * @since 11.1 */ public function parseFiles($element, $cid = 0, $oldFiles = null, $oldMD5 = null) { // Get the array of file nodes to process; we checked whether this had children above. if (!$element || !count($element->children())) { // Either the tag does not exist or has no children (hence no files to process) therefore we return zero files processed. return 0; } // Initialise variables. $copyfiles = array(); // Get the client info $client = JApplicationHelper::getClientInfo($cid); /* * Here we set the folder we are going to remove the files from. */ if ($client) { $pathname = 'extension_' . $client->name; $destination = $this->getPath($pathname); } else { $pathname = 'extension_root'; $destination = $this->getPath($pathname); } // Here we set the folder we are going to copy the files from. // Does the element have a folder attribute? // // If so this indicates that the files are in a subdirectory of the source // folder and we should append the folder attribute to the source path when // copying files. $folder = (string) $element->attributes()->folder; if ($folder && file_exists($this->getPath('source') . '/' . $folder)) { $source = $this->getPath('source') . '/' . $folder; } else { $source = $this->getPath('source'); } // Work out what files have been deleted if ($oldFiles && ($oldFiles instanceof SimpleXMLElement)) { $oldEntries = $oldFiles->children(); if (count($oldEntries)) { $deletions = $this->findDeletedFiles($oldEntries, $element->children()); foreach ($deletions['folders'] as $deleted_folder) { JFolder::delete($destination . '/' . $deleted_folder); } foreach ($deletions['files'] as $deleted_file) { JFile::delete($destination . '/' . $deleted_file); } } } // Copy the MD5SUMS file if it exists if (file_exists($source . '/MD5SUMS')) { $path['src'] = $source . '/MD5SUMS'; $path['dest'] = $destination . '/MD5SUMS'; $path['type'] = 'file'; $copyfiles[] = $path; } // Process each file in the $files array (children of $tagName). foreach ($element->children() as $file) { $path['src'] = $source . '/' . $file; $path['dest'] = $destination . '/' . $file; // Is this path a file or folder? $path['type'] = ($file->getName() == 'folder') ? 'folder' : 'file'; // Before we can add a file to the copyfiles array we need to ensure // that the folder we are copying our file to exits and if it doesn't, // we need to create it. if (basename($path['dest']) != $path['dest']) { $newdir = dirname($path['dest']); if (!JFolder::create($newdir)) { JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_DIRECTORY', $newdir)); return false; } } // Add the file to the copyfiles array $copyfiles[] = $path; } return $this->copyFiles($copyfiles); } /** * Method to parse through a languages element of the installation manifest and take appropriate * action. * * @param SimpleXMLElement $element The XML node to process * @param integer $cid Application ID of application to install to * * @return boolean True on success * * @since 11.1 */ public function parseLanguages($element, $cid = 0) { // TODO: work out why the below line triggers 'node no longer exists' errors with files if (!$element || !count($element->children())) { // Either the tag does not exist or has no children therefore we return zero files processed. return 0; } // Initialise variables. $copyfiles = array(); // Get the client info $client = JApplicationHelper::getClientInfo($cid); // Here we set the folder we are going to copy the files to. // 'languages' Files are copied to JPATH_BASE/language/ folder $destination = $client->path . '/language'; // Here we set the folder we are going to copy the files from. // Does the element have a folder attribute? // If so this indicates that the files are in a subdirectory of the source // folder and we should append the folder attribute to the source path when // copying files. $folder = (string) $element->attributes()->folder; if ($folder && file_exists($this->getPath('source') . '/' . $folder)) { $source = $this->getPath('source') . '/' . $folder; } else { $source = $this->getPath('source'); } // Process each file in the $files array (children of $tagName). foreach ($element->children() as $file) { // Language files go in a subfolder based on the language code, ie. // en-US.mycomponent.ini // would go in the en-US subdirectory of the language folder. // We will only install language files where a core language pack // already exists. if ((string) $file->attributes()->tag != '') { $path['src'] = $source . '/' . $file; if ((string) $file->attributes()->client != '') { // Override the client $langclient = JApplicationHelper::getClientInfo((string) $file->attributes()->client, true); $path['dest'] = $langclient->path . '/language/' . $file->attributes()->tag . '/' . basename((string) $file); } else { // Use the default client $path['dest'] = $destination . '/' . $file->attributes()->tag . '/' . basename((string) $file); } // If the language folder is not present, then the core pack hasn't been installed... ignore if (!JFolder::exists(dirname($path['dest']))) { continue; } } else { $path['src'] = $source . '/' . $file; $path['dest'] = $destination . '/' . $file; } // // Before we can add a file to the copyfiles array we need to ensure // that the folder we are copying our file to exits and if it doesn't, // we need to create it. if (basename($path['dest']) != $path['dest']) { $newdir = dirname($path['dest']); if (!JFolder::create($newdir)) { JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_DIRECTORY', $newdir)); return false; } } // Add the file to the copyfiles array $copyfiles[] = $path; } return $this->copyFiles($copyfiles); } /** * Method to parse through a media element of the installation manifest and take appropriate * action. * * @param SimpleXMLElement $element The XML node to process * @param integer $cid Application ID of application to install to * * @return boolean True on success * * @since 11.1 */ public function parseMedia($element, $cid = 0) { if (!$element || !count($element->children())) { // Either the tag does not exist or has no children therefore we return zero files processed. return 0; } // Initialise variables. $copyfiles = array(); // Get the client info $client = JApplicationHelper::getClientInfo($cid); // Here we set the folder we are going to copy the files to. // Default 'media' Files are copied to the JPATH_BASE/media folder $folder = ((string) $element->attributes()->destination) ? '/' . $element->attributes()->destination : null; $destination = JPath::clean(JPATH_ROOT . '/media' . $folder); // Here we set the folder we are going to copy the files from. // Does the element have a folder attribute? // If so this indicates that the files are in a subdirectory of the source // folder and we should append the folder attribute to the source path when // copying files. $folder = (string) $element->attributes()->folder; if ($folder && file_exists($this->getPath('source') . '/' . $folder)) { $source = $this->getPath('source') . '/' . $folder; } else { $source = $this->getPath('source'); } // Process each file in the $files array (children of $tagName). foreach ($element->children() as $file) { $path['src'] = $source . '/' . $file; $path['dest'] = $destination . '/' . $file; // Is this path a file or folder? $path['type'] = ($file->getName() == 'folder') ? 'folder' : 'file'; // Before we can add a file to the copyfiles array we need to ensure // that the folder we are copying our file to exits and if it doesn't, // we need to create it. if (basename($path['dest']) != $path['dest']) { $newdir = dirname($path['dest']); if (!JFolder::create($newdir)) { JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_DIRECTORY', $newdir)); return false; } } // Add the file to the copyfiles array $copyfiles[] = $path; } return $this->copyFiles($copyfiles); } /** * Method to parse the parameters of an extension, build the INI * string for its default parameters, and return the INI string. * * @return string INI string of parameter values * * @since 11.1 */ public function getParams() { // Validate that we have a fieldset to use if (!isset($this->manifest->config->fields->fieldset)) { return '{}'; } // Getting the fieldset tags $fieldsets = $this->manifest->config->fields->fieldset; // Creating the data collection variable: $ini = array(); // Iterating through the fieldsets: foreach ($fieldsets as $fieldset) { if (!count($fieldset->children())) { // Either the tag does not exist or has no children therefore we return zero files processed. return null; } // Iterating through the fields and collecting the name/default values: foreach ($fieldset as $field) { // Check against the null value since otherwise default values like "0" // cause entire parameters to be skipped. if (($name = $field->attributes()->name) === null) { continue; } if (($value = $field->attributes()->default) === null) { continue; } $ini[(string) $name] = (string) $value; } } return json_encode($ini); } /** * Copyfiles * * Copy files from source directory to the target directory * * @param array $files Array with filenames * @param boolean $overwrite True if existing files can be replaced * * @return boolean True on success * * @since 11.1 */ public function copyFiles($files, $overwrite = null) { // To allow for manual override on the overwriting flag, we check to see if // the $overwrite flag was set and is a boolean value. If not, use the object // allowOverwrite flag. if (is_null($overwrite) || !is_bool($overwrite)) { $overwrite = $this->_overwrite; } /* * $files must be an array of filenames. Verify that it is an array with * at least one file to copy. */ if (is_array($files) && count($files) > 0) { foreach ($files as $file) { // Get the source and destination paths $filesource = JPath::clean($file['src']); $filedest = JPath::clean($file['dest']); $filetype = array_key_exists('type', $file) ? $file['type'] : 'file'; if (!file_exists($filesource)) { /* * The source file does not exist. Nothing to copy so set an error * and return false. */ JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_NO_FILE', $filesource)); return false; } elseif (($exists = file_exists($filedest)) && !$overwrite) { // It's okay if the manifest already exists if ($this->getPath('manifest') == $filesource) { continue; } // The destination file already exists and the overwrite flag is false. // Set an error and return false. JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_FILE_EXISTS', $filedest)); return false; } else { // Copy the folder or file to the new location. if ($filetype == 'folder') { if (!(JFolder::copy($filesource, $filedest, null, $overwrite))) { JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_FAIL_COPY_FOLDER', $filesource, $filedest)); return false; } $step = array('type' => 'folder', 'path' => $filedest); } else { if (!(JFile::copy($filesource, $filedest, null))) { JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_FAIL_COPY_FILE', $filesource, $filedest)); return false; } $step = array('type' => 'file', 'path' => $filedest); } /* * Since we copied a file/folder, we want to add it to the installation step stack so that * in case we have to roll back the installation we can remove the files copied. */ if (!$exists) { $this->_stepStack[] = $step; } } } } else { // The $files variable was either not an array or an empty array return false; } return count($files); } /** * Method to parse through a files element of the installation manifest and remove * the files that were installed * * @param object $element The XML node to process * @param integer $cid Application ID of application to remove from * * @return boolean True on success * * @since 11.1 */ public function removeFiles($element, $cid = 0) { if (!$element || !count($element->children())) { // Either the tag does not exist or has no children therefore we return zero files processed. return true; } // Initialise variables. $removefiles = array(); $retval = true; $debug = false; if (isset($GLOBALS['installerdebug']) && $GLOBALS['installerdebug']) { $debug = true; } // Get the client info if we're using a specific client if ($cid > -1) { $client = JApplicationHelper::getClientInfo($cid); } else { $client = null; } // Get the array of file nodes to process $files = $element->children(); if (count($files) == 0) { // No files to process return true; } $folder = ''; /* * Here we set the folder we are going to remove the files from. There are a few * special cases that need to be considered for certain reserved tags. */ switch ($element->getName()) { case 'media': if ((string) $element->attributes()->destination) { $folder = (string) $element->attributes()->destination; } else { $folder = ''; } $source = $client->path . '/media/' . $folder; break; case 'languages': $lang_client = (string) $element->attributes()->client; if ($lang_client) { $client = JApplicationHelper::getClientInfo($lang_client, true); $source = $client->path . '/language'; } else { if ($client) { $source = $client->path . '/language'; } else { $source = ''; } } break; default: if ($client) { $pathname = 'extension_' . $client->name; $source = $this->getPath($pathname); } else { $pathname = 'extension_root'; $source = $this->getPath($pathname); } break; } // Process each file in the $files array (children of $tagName). foreach ($files as $file) { // If the file is a language, we must handle it differently. Language files // go in a subdirectory based on the language code, ie. // en_US.mycomponent.ini // would go in the en_US subdirectory of the languages directory. if ($file->getName() == 'language' && (string) $file->attributes()->tag != '') { if ($source) { $path = $source . '/' . $file->attributes()->tag . '/' . basename((string) $file); } else { $target_client = JApplicationHelper::getClientInfo((string) $file->attributes()->client, true); $path = $target_client->path . '/language/' . $file->attributes()->tag . '/' . basename((string) $file); } // If the language folder is not present, then the core pack hasn't been installed... ignore if (!JFolder::exists(dirname($path))) { continue; } } else { $path = $source . '/' . $file; } // Actually delete the files/folders if (is_dir($path)) { $val = JFolder::delete($path); } else { $val = JFile::delete($path); } if ($val === false) { JError::raiseWarning(43, 'Failed to delete ' . $path); $retval = false; } } if (!empty($folder)) { $val = JFolder::delete($source); } return $retval; } /** * Copies the installation manifest file to the extension folder in the given client * * @param integer $cid Where to copy the installfile [optional: defaults to 1 (admin)] * * @return boolean True on success, False on error * * @since 11.1 */ public function copyManifest($cid = 1) { // Get the client info $client = JApplicationHelper::getClientInfo($cid); $path['src'] = $this->getPath('manifest'); if ($client) { $pathname = 'extension_' . $client->name; $path['dest'] = $this->getPath($pathname) . '/' . basename($this->getPath('manifest')); } else { $pathname = 'extension_root'; $path['dest'] = $this->getPath($pathname) . '/' . basename($this->getPath('manifest')); } return $this->copyFiles(array($path), true); } /** * Tries to find the package manifest file * * @return boolean True on success, False on error * * @since 1.0 */ public function findManifest() { // Main folder manifests (higher priority) $parentXmlfiles = JFolder::files($this->getPath('source'), '.xml$', false, true); // Search for children manifests (lower priority) $allXmlFiles = JFolder::files($this->getPath('source'), '.xml$', 1, true); // Create an unique array of files $xmlfiles = array_unique(array_merge($parentXmlfiles, $allXmlFiles)); // If at least one XML file exists if (!empty($xmlfiles)) { foreach ($xmlfiles as $file) { // Is it a valid Joomla installation manifest file? $manifest = $this->isManifest($file); if (!is_null($manifest)) { // If the root method attribute is set to upgrade, allow file overwrite if ((string) $manifest->attributes()->method == 'upgrade') { $this->_upgrade = true; $this->_overwrite = true; } // If the overwrite option is set, allow file overwriting if ((string) $manifest->attributes()->overwrite == 'true') { $this->_overwrite = true; } // Set the manifest object and path $this->manifest = $manifest; $this->setPath('manifest', $file); // Set the installation source path to that of the manifest file $this->setPath('source', dirname($file)); return true; } } // None of the XML files found were valid install files JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ERROR_NOTFINDJOOMLAXMLSETUPFILE')); return false; } else { // No XML files were found in the install folder JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ERROR_NOTFINDXMLSETUPFILE')); return false; } } /** * Is the XML file a valid Joomla installation manifest file. * * @param string $file An xmlfile path to check * * @return mixed A JXMLElement, or null if the file failed to parse * * @since 11.1 */ public function isManifest($file) { // Initialise variables. $xml = JFactory::getXML($file); // If we cannot load the XML file return null if (!$xml) { return null; } // Check for a valid XML root tag. // @todo: Remove backwards compatibility in a future version // Should be 'extension', but for backward compatibility we will accept 'extension' or 'install'. // 1.5 uses 'install' // 1.6 uses 'extension' if ($xml->getName() != 'install' && $xml->getName() != 'extension') { return null; } // Valid manifest file return the object return $xml; } /** * Generates a manifest cache * * @return string serialised manifest data * * @since 11.1 */ public function generateManifestCache() { return json_encode(JApplicationHelper::parseXMLInstallFile($this->getPath('manifest'))); } /** * Cleans up discovered extensions if they're being installed some other way * * @param string $type The type of extension (component, etc) * @param string $element Unique element identifier (e.g. com_content) * @param string $folder The folder of the extension (plugins; e.g. system) * @param integer $client The client application (administrator or site) * * @return object Result of query * * @since 11.1 */ public function cleanDiscoveredExtension($type, $element, $folder = '', $client = 0) { $dbo = JFactory::getDBO(); $query = $dbo->getQuery(true); $query->delete($dbo->quoteName('#__extensions')); $query->where('type = ' . $dbo->Quote($type)); $query->where('element = ' . $dbo->Quote($element)); $query->where('folder = ' . $dbo->Quote($folder)); $query->where('client_id = ' . intval($client)); $query->where('state = -1'); return $dbo->execute(); } /** * Compares two "files" entries to find deleted files/folders * * @param array $old_files An array of SimpleXMLElement objects that are the old files * @param array $new_files An array of SimpleXMLElement objects that are the new files * * @return array An array with the delete files and folders in findDeletedFiles[files] and findDeletedFiles[folders] respectively * * @since 11.1 */ public function findDeletedFiles($old_files, $new_files) { // The magic find deleted files function! // The files that are new $files = array(); // The folders that are new $folders = array(); // The folders of the files that are new $containers = array(); // A list of files to delete $files_deleted = array(); // A list of folders to delete $folders_deleted = array(); foreach ($new_files as $file) { switch ($file->getName()) { case 'folder': // Add any folders to the list $folders[] = (string) $file; // add any folders to the list break; case 'file': default: // Add any files to the list $files[] = (string) $file; // Now handle the folder part of the file to ensure we get any containers // Break up the parts of the directory $container_parts = explode('/', dirname((string) $file)); // Make sure this is clean and empty $container = ''; foreach ($container_parts as $part) { // Iterate through each part // Add a slash if its not empty if (!empty($container)) { $container .= '/'; } $container .= $part; // append the folder part if (!in_array($container, $containers)) { $containers[] = $container; // add the container if it doesn't already exist } } break; } } foreach ($old_files as $file) { switch ($file->getName()) { case 'folder': if (!in_array((string) $file, $folders)) { // See whether the folder exists in the new list if (!in_array((string) $file, $containers)) { // Check if the folder exists as a container in the new list // If it's not in the new list or a container then delete it $folders_deleted[] = (string) $file; } } break; case 'file': default: if (!in_array((string) $file, $files)) { // look if the file exists in the new list if (!in_array(dirname((string) $file), $folders)) { // look if the file is now potentially in a folder $files_deleted[] = (string) $file; // not in a folder, doesn't exist, wipe it out! } } break; } } return array('files' => $files_deleted, 'folders' => $folders_deleted); } /** * Loads an MD5SUMS file into an associative array * * @param string $filename Filename to load * * @return array Associative array with filenames as the index and the MD5 as the value * * @since 11.1 */ public function loadMD5Sum($filename) { if (!file_exists($filename)) { // Bail if the file doesn't exist return false; } $data = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); $retval = array(); foreach ($data as $row) { $results = explode(' ', $row); // split up the data $results[1] = str_replace('./', '', $results[1]); // cull any potential prefix $retval[$results[1]] = $results[0]; // throw into the array } return $retval; } /** * Parse a XML install manifest file. * * XML Root tag should be 'install' except for languages which use meta file. * * @param string $path Full path to XML file. * * @return array XML metadata. * * @since 12.1 */ public static function parseXMLInstallFile($path) { // Read the file to see if it's a valid component XML file if (!$xml = JFactory::getXML($path)) { return false; } // Check for a valid XML root tag. // Should be 'install', but for backward compatibility we will accept 'extension'. // Languages use 'metafile' instead if ($xml->getName() != 'install' && $xml->getName() != 'extension' && $xml->getName() != 'metafile') { unset($xml); return false; } $data = array(); $data['legacy'] = ($xml->getName() == 'mosinstall' || $xml->getName() == 'install'); $data['name'] = (string) $xml->name; // Check if we're a language. If so use metafile. $data['type'] = $xml->getName() == 'metafile' ? 'language' : (string) $xml->attributes()->type; $data['creationDate'] = ((string) $xml->creationDate) ? (string) $xml->creationDate : JText::_('Unknown'); $data['author'] = ((string) $xml->author) ? (string) $xml->author : JText::_('Unknown'); $data['copyright'] = (string) $xml->copyright; $data['authorEmail'] = (string) $xml->authorEmail; $data['authorUrl'] = (string) $xml->authorUrl; $data['version'] = (string) $xml->version; $data['description'] = (string) $xml->description; $data['group'] = (string) $xml->group; return $data; } } extension.php000066600000005572151372561050007313 0ustar00type = (string) $element->attributes()->type; $this->id = (string) $element->attributes()->id; switch ($this->type) { case 'component': // By default a component doesn't have anything break; case 'module': case 'template': case 'language': $this->client = (string) $element->attributes()->client; $tmp_client_id = JApplicationHelper::getClientInfo($this->client, 1); if ($tmp_client_id == null) { JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_EXTENSION_INVALID_CLIENT_IDENTIFIER')); } else { $this->client_id = $tmp_client_id->id; } break; case 'plugin': $this->group = (string) $element->attributes()->group; break; default: // Catch all // Get and set client and group if we don't recognise the extension if ($client = (string) $element->attributes()->client) { $this->client_id = JApplicationHelper::getClientInfo($this->client, 1); $this->client_id = $this->client_id->id; } if ($group = (string) $element->attributes()->group) { $this->group = (string) $element->attributes()->group; } break; } $this->filename = (string) $element; } } } packagemanifest.php000066600000005601151372561050010412 0ustar00loadManifestFromXML($xmlpath); } } /** * Load a manifest from an XML file * * @param string $xmlfile Path to XML manifest file * * @return boolean Result of load * * @since 11.1 */ public function loadManifestFromXML($xmlfile) { $this->manifest_file = JFile::stripExt(basename($xmlfile)); $xml = JFactory::getXML($xmlfile); if (!$xml) { $this->_errors[] = JText::sprintf('JLIB_INSTALLER_ERROR_LOAD_XML', $xmlfile); return false; } else { $this->name = (string) $xml->name; $this->packagename = (string) $xml->packagename; $this->update = (string) $xml->update; $this->authorurl = (string) $xml->authorUrl; $this->author = (string) $xml->author; $this->authoremail = (string) $xml->authorEmail; $this->description = (string) $xml->description; $this->packager = (string) $xml->packager; $this->packagerurl = (string) $xml->packagerurl; $this->scriptfile = (string) $xml->scriptfile; $this->version = (string) $xml->version; if (isset($xml->files->file) && count($xml->files->file)) { foreach ($xml->files->file as $file) { // NOTE: JExtension doesn't expect a string. // DO NOT CAST $file $this->filelist[] = new JExtension($file); } } return true; } } } librarymanifest.php000066600000006324151372561050010466 0ustar00loadManifestFromXML($xmlpath); } } /** * Load a manifest from a file * * @param string $xmlfile Path to file to load * * @return boolean * * @since 11.1 */ public function loadManifestFromXML($xmlfile) { $this->manifest_file = JFile::stripExt(basename($xmlfile)); $xml = JFactory::getXML($xmlfile); if (!$xml) { $this->_errors[] = JText::sprintf('JLIB_INSTALLER_ERROR_LOAD_XML', $xmlfile); return false; } else { $this->name = (string) $xml->name; $this->libraryname = (string) $xml->libraryname; $this->version = (string) $xml->version; $this->description = (string) $xml->description; $this->creationdate = (string) $xml->creationdate; $this->author = (string) $xml->author; $this->authoremail = (string) $xml->authorEmail; $this->authorurl = (string) $xml->authorUrl; $this->packager = (string) $xml->packager; $this->packagerurl = (string) $xml->packagerurl; $this->update = (string) $xml->update; if (isset($xml->files) && isset($xml->files->file) && count($xml->files->file)) { foreach ($xml->files->file as $file) { $this->filelist[] = (string) $file; } } return true; } } } .htaccess000066600000000177151372561050006360 0ustar00 Order allow,deny Deny from all