minimumPHPVersion)) { if (defined('PHP_VERSION')) { $version = PHP_VERSION; } elseif (function_exists('phpversion')) { $version = phpversion(); } else { $version = '5.0.0'; // all bets are off! } if (!version_compare($version, $this->minimumPHPVersion, 'ge')) { $msg = "
You need PHP $this->minimumPHPVersion or later to install this package but you are currently using PHP $version
"; JLog::add($msg, JLog::WARNING, 'jerror'); return false; } } // Check the minimum Joomla! version if (!empty($this->minimumJoomlaVersion) && !version_compare(JVERSION, $this->minimumJoomlaVersion, 'ge')) { $jVersion = JVERSION; $msg = "You need Joomla! $this->minimumJoomlaVersion or later to install this package but you only have $jVersion installed.
"; JLog::add($msg, JLog::WARNING, 'jerror'); return false; } // Check the maximum Joomla! version if (!empty($this->maximumJoomlaVersion) && !version_compare(JVERSION, $this->maximumJoomlaVersion, 'le')) { $jVersion = JVERSION; $msg = <<< HTMLSummary: FEF is no longer used on Joomla 5. Please uninstall it.
Akeeba FEF a.k.a. the Akeeba Front-End Framework was a CSS and JavaScript framework used by Akeeba Ltd with the Joomla 3 versions of our software.
Akeeba Ltd has stopped using the FEF framework for developing extensions. All of our extensions have new, Joomla 4 and later native versions which use the Bootstrap library, included in Joomla itself.
You can no longer install or update FEF on Joomla 5.0 and later (you have {$jVersion}). In fact, you just need to uninstall it.
HTML; JLog::add($msg, JLog::WARNING, 'jerror'); return false; } // In case of an update, discovery etc I need to check if I am an update if (($type == 'update') && !$this->amIAnUpdate($parent)) { $msg = "You already have a newer version of Akeeba Frontend Framework installed. If you want to downgrade please uninstall Akeeba Frontend Framework and install the older version.
If you see this message during the installation or update of an Akeeba extension please ignore it and the immediately following “Files Install: Custom install routine failure” message. They are expected but Joomla! won't allow us to prevent them from showing up.
"; JLog::add($msg, JLog::WARNING, 'jerror'); return false; } // Delete obsolete font files and folders if ($type == 'update') { // Use pathnames relative to your site's root $removeFiles = [ 'files' => [ // Non-WOFF fonts are not shipped as of 1.0.1 since all modern browsers we target use WOFF 'media/fef/fonts/akeeba/Akeeba-Products.eot', 'media/fef/fonts/akeeba/Akeeba-Products.svg', 'media/fef/fonts/akeeba/Akeeba-Products.ttf', 'media/fef/fonts/Ionicon/ionicons.eot', 'media/fef/fonts/Ionicon/ionicons.svg', 'media/fef/fonts/Ionicon/ionicons.ttf', // Files renamed in 1.0.8 'css/reset.min.css', 'css/style.min.css', // JavaScript: Irrelevant for Joomla 'js/darkmode.js', 'js/darkmode.min.js', 'js/darkmode.map', 'js/Darkmode.min.js', 'js/Darkmode.map', 'js/menu.js', 'js/menu.min.js', 'js/menu.map', 'js/Menu.min.js', 'js/Menu.map', // JavaScript: Uncompressed and map files 'js/dropdown.js', 'js/dropdown.map', 'js/Dropdown.map', 'js/loader.js', 'js/loader.map', 'js/Loader.map', 'js/tabs.js', 'js/tabs.map', 'js/Tabs.map', ], 'folders' => [ ], ]; // Remove obsolete files and folders $this->removeFilesAndFolders($removeFiles); } return true; } /** * Runs after install, update or discover_update. In other words, it executes after Joomla! has finished installing * or updating your component. This is the last chance you've got to perform any additional installations, clean-up, * database updates and similar housekeeping functions. * * @param string $type install, update or discover_update * @param JInstallerAdapterFile $parent Parent object * * @throws Exception * * @noinspection PhpUnusedParameterInspection */ public function postflight($type, JInstallerAdapterFile $parent) { // Do not run on uninstall. if ($type === 'uninstall') { return true; } // Auto-uninstall this package when it is no longer needed. if (($type != 'install') && ($this->countHardcodedDependencies() === 0)) { $this->uninstallSelf($parent); return true; } $this->bugfixFilesNotCopiedOnUpdate($parent); return true; } /** * Runs on uninstallation * * @param JInstallerAdapterFile $parent The parent object * * @throws RuntimeException If the uninstallation is not allowed * * @noinspection PhpUnusedParameterInspection */ public function uninstall($parent) { if (version_compare(JVERSION, '4.1.0', 'ge')) { return false; } // Check dependencies on FEF $dependencyCount = $this->countHardcodedDependencies(); if ($dependencyCount) { $msg = "You have $dependencyCount extension(s) depending on Akeeba Frontend Framework. The package cannot be uninstalled unless these extensions are uninstalled first.
"; JLog::add($msg, JLog::WARNING, 'jerror'); throw new RuntimeException($msg, 500); } Folder::delete(JPATH_SITE . '/media/fef'); return true; } /** * Removes obsolete files and folders * * @param array $removeList The files and directories to remove */ protected function removeFilesAndFolders($removeList) { // Remove files if (isset($removeList['files']) && !empty($removeList['files'])) { foreach ($removeList['files'] as $file) { $f = JPATH_ROOT . '/' . $file; if (!is_file($f)) { continue; } File::delete($f); } } // Remove folders if (isset($removeList['folders']) && !empty($removeList['folders'])) { foreach ($removeList['folders'] as $folder) { $f = JPATH_ROOT . '/' . $folder; if (!is_dir($f)) { continue; } Folder::delete($f); } } } /** * Is this package an update to the currently installed FEF? If not (we're a downgrade) we will return false * and prevent the installation from going on. * * @param JInstallerAdapterFile $parent The parent object * * @return bool Am I an update to an existing version> */ protected function amIAnUpdate($parent) { $grandpa = $parent->getParent(); $source = $grandpa->getPath('source'); $target = JPATH_ROOT . '/media/fef'; if (!Folder::exists($source)) { // WTF? I can't find myself. I can't install anything. return false; } // If FEF is not really installed (someone removed the directory instead of uninstalling?) I have to install it. if (!Folder::exists($target)) { return true; } $fefVersion = []; if (File::exists($target . '/version.txt')) { $rawData = @file_get_contents($target . '/version.txt'); $rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData; $info = explode("\n", $rawData); $fefVersion['installed'] = [ 'version' => trim($info[0]), 'date' => new JDate(trim($info[1])), ]; } else { $fefVersion['installed'] = [ 'version' => '0.0', 'date' => new JDate('2011-01-01'), ]; } $rawData = @file_get_contents($source . '/version.txt'); $rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData; $info = explode("\n", $rawData); $fefVersion['package'] = [ 'version' => trim($info[0]), 'date' => new JDate(trim($info[1])), ]; return $fefVersion['package']['date']->toUNIX() >= $fefVersion['installed']['date']->toUNIX(); } /** * Fix for Joomla bug: sometimes files are not copied on update. * * We have observed that ever since Joomla! 1.5.5, when Joomla! is performing an extension update some files / * folders are not copied properly. This seems to be a bit random and seems to be more likely to happen the more * added / modified files and folders you have. We are trying to work around it by retrying the copy operation * ourselves WITHOUT going through the manifest, based entirely on the conventions we follow. * * @param \Joomla\CMS\Installer\Adapter\FileAdapter $parent */ protected function bugfixFilesNotCopiedOnUpdate($parent) { $source = $parent->getParent()->getPath('source'); $target = JPATH_SITE . '/media/fef'; $this->recursiveConditionalCopy($source, $target); } /** * Recursively copy a bunch of files, but only if the source and target file have a different size. * * @param string $source Path to copy FROM * @param string $dest Path to copy TO * @param array $ignored List of entries to ignore (first level entries are taken into account) * * @return void */ protected function recursiveConditionalCopy($source, $dest, $ignored = []) { // Make sure source and destination exist if (!@is_dir($source)) { return; } if (!@is_dir($dest)) { if (!@mkdir($dest, 0755)) { Folder::create($dest, 0755); } } if (!@is_dir($dest)) { // Cannot create folder $dest return; } // List the contents of the source folder try { $di = new DirectoryIterator($source); } catch (Exception $e) { return; } // Process each entry foreach ($di as $entry) { // Ignore dot dirs (. and ..) if ($entry->isDot()) { continue; } $sourcePath = $entry->getPathname(); $fileName = $entry->getFilename(); // Do not copy ignored files if (!empty($ignored) && in_array($fileName, $ignored)) { continue; } // If it's a directory do a recursive copy if ($entry->isDir()) { $this->recursiveConditionalCopy($sourcePath, $dest . DIRECTORY_SEPARATOR . $fileName); continue; } // If it's a file check if it's missing or identical $mustCopy = false; $targetPath = $dest . DIRECTORY_SEPARATOR . $fileName; if (!@is_file($targetPath)) { $mustCopy = true; } else { $sourceSize = @filesize($sourcePath); $targetSize = @filesize($targetPath); $mustCopy = $sourceSize != $targetSize; if ((substr($targetPath, -4) === '.php') && function_exists('opcache_invalidate')) { opcache_invalidate($targetPath); } } if (!$mustCopy) { continue; } if (!@copy($sourcePath, $targetPath)) { File::copy($sourcePath, $targetPath); } } } /** * Count the number of old FOF + FEF based extensions installed on this site * * @return int */ private function countHardcodedDependencies() { // Look for fof.xml in the backend directories of the following components $hardcodedDependencies = [ 'com_admintools', 'com_akeeba', 'com_ars', 'com_ats', 'com_compatibility', 'com_datacompliance', 'com_contactus', 'com_docimport', 'com_loginguard', ]; $count = 0; foreach ($hardcodedDependencies as $component) { $filePath = JPATH_ADMINISTRATOR . '/components/' . $component . '/fof.xml'; if (@file_exists($filePath)) { $count++; } } return $count; } /** * Uninstall this package. * * This runs on update when there are no more dependencies left. * * @param \Joomla\CMS\Installer\Adapter\FileAdapter $adapter * * @return void */ private function uninstallSelf($adapter) { $parent = $adapter->getParent(); if (empty($parent) || !property_exists($parent, 'extension')) { return; } if (version_compare(JVERSION, '4.0', 'lt')) { $db = \Joomla\CMS\Factory::getDbo(); } else { $db = \Joomla\CMS\Factory::getContainer()->get('DatabaseDriver'); } try { $query = $db->getQuery(true) ->select($db->quoteName('extension_id')) ->from($db->quoteName('#__extensions')) ->where($db->quoteName('type') . ' = ' . $db->quote('file')) ->where($db->quoteName('name') . ' = ' . $db->quote('file_fef')); $id = $db->setQuery($query)->loadResult(); } catch (Exception $e) { return; } if (empty($id)) { return; } $msg = 'Automatically uninstalling FEF; this package is no longer required on your site.'; \Joomla\CMS\Log\Log::add($msg, \Joomla\CMS\Log\Log::INFO, 'jerror'); $parent->uninstall('file', $id); } }