Server : LiteSpeed System : Linux server 3.10.0-1160.90.1.el7.x86_64 #1 SMP Thu May 4 15:21:22 UTC 2023 x86_64 User : alsaif ( 1057) PHP Version : 7.4.33 Disable Function : show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/alsaif/public_html/administrator/manifests/files/file_fof40/ |
<?php
/**
* @package FOF
* @copyright Copyright (c)2010-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
defined('_JEXEC') || die;
use Joomla\CMS\Date\Date as JoomlaDate;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Filesystem\File;
use Joomla\CMS\Filesystem\Folder;
use Joomla\CMS\Installer\Installer as JoomlaInstaller;
use Joomla\CMS\Installer\InstallerAdapter;
use Joomla\CMS\Log\Log;
if (class_exists('file_fof40InstallerScript', false))
{
return;
}
/**
* Class file_fof40InstallerScript
*
* @noinspection PhpIllegalPsrClassPathInspection
*/
class file_fof40InstallerScript
{
public $removeFiles;
/**
* The minimum PHP version required to install this extension
*
* @var string
*/
protected $minimumPHPVersion = '7.2.0';
/**
* The minimum Joomla! version required to install this extension
*
* @var string
*/
protected $minimumJoomlaVersion = '3.9.0';
/**
* The maximum Joomla! version this extension can be installed on
*
* @var string
*/
protected $maximumJoomlaVersion = '4.999.999';
/**
* The name of the subdirectory under JPATH_LIBRARIES where this version of FOF is installed.
*
* @var string
*/
protected $libraryFolder = 'fof40';
/**
* Obsolete files and folders to remove.
*
* This is used when we refactor code. Some files inevitably become obsolete and need to be removed.
*
* All files and folders are relative to the library's root (JPATH_LIBRARIES . '/' . $this->libraryFolder).
*
* @var array
*/
protected $removeFilesAllVersions = [
'files' => [
],
'folders' => [
],
];
/**
* Joomla! pre-flight event. This runs before Joomla! installs or updates the component. This is our last chance to
* tell Joomla! if it should abort the installation.
*
* @param string $type Installation type (install, update, discover_install)
* @param JoomlaInstaller $parent Parent object
*
* @return boolean True to let the installation proceed, false to halt the installation
*/
public function preflight($type, $parent)
{
// Do not run on uninstall.
if ($type === 'uninstall')
{
return true;
}
// Check the minimum PHP version
if (!empty($this->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 = "<p>You need PHP $this->minimumPHPVersion or later to install this package but you are currently using PHP $version</p>";
Log::add($msg, Log::WARNING, 'jerror');
return false;
}
}
// Check the minimum Joomla! version
if (!empty($this->minimumJoomlaVersion) && !version_compare(JVERSION, $this->minimumJoomlaVersion, 'ge'))
{
$jVersion = JVERSION;
$msg = "<p>You need Joomla! $this->minimumJoomlaVersion or later to install this package but you only have $jVersion installed.</p>";
Log::add($msg, Log::WARNING, 'jerror');
return false;
}
// Check the maximum Joomla! version
if (!empty($this->maximumJoomlaVersion) && !version_compare(JVERSION, $this->maximumJoomlaVersion, 'le'))
{
$jVersion = JVERSION;
$msg = <<< HTML
<h3>FOF is no longer needed on Joomla 5</h3>
<p>
<strong>Summary: FOF is no longer used on Joomla 5. Please uninstall it.</strong>
</p>
<hr/>
<p>
FOF a.k.a. Framework-on-Framework was an extension development framework used by Akeeba Ltd (and some third party extensions developed by companies not affiliated with Akeeba Ltd) on Joomla 1.5 to 3.10.
</p>
<p>
Akeeba Ltd has stopped using the FOF framework for developing extensions. All of our extensions have new, Joomla 4 and later native versions which use the Joomla Core MVC library, included in Joomla itself.
</p>
<p>
You can no longer install or update FOF on Joomla 5.0 and later (you have {$jVersion}). In fact, you just need to uninstall it.
</p>
HTML;
Log::add($msg, Log::WARNING, 'jerror');
return false;
}
// In case of an update, discovery etc I need to check if I am an update
if (($type != 'install') && !$this->amIAnUpdate($parent))
{
$msg = "<p>You have a newer version of FOF installed. If you want to downgrade please uninstall FOF and install the older version.</p>";
if (defined('AKEEBA_PACKAGE_INSTALLING'))
{
$msg = "<p>Your site has a newer version of FOF 4 than the one bundled with this package. Please note that <strong>you can safely ignore the “Custom install routine failure” message</strong> below. It is not a real error; it is an expected message which is always printed by Joomla! in this case and which cannot be suppressed.</p>";
}
Log::add($msg, Log::WARNING, 'jerror');
return false;
}
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 InstallerAdapter $parent Parent object
*
* @throws Exception
*/
public function postflight($type, $parent)
{
// Do not run on uninstall.
if ($type === 'uninstall')
{
return;
}
// Auto-uninstall this package when it is no longer needed.
if (($type != 'install') && ($this->countHardcodedDependencies() === 0))
{
// $this->uninstallSelf($parent);
return;
}
// Remove obsolete files and folders
$this->removeFilesAndFolders($this->removeFiles);
if ($type == 'update')
{
$this->bugfixFilesNotCopiedOnUpdate($parent);
}
$this->loadFOF40();
if (!defined('FOF40_INCLUDED'))
{
return;
}
// Install or update database
$db = JoomlaFactory::getDbo();
/** @var JoomlaInstaller $grandpa */
$grandpa = $parent->getParent();
$src = $grandpa->getPath('source');
$sqlSource = $src . '/fof/sql';
// If we have an uppercase db prefix we can expect the database update to fail because we cannot detect reliably
// the existence of database tables. See https://github.com/joomla/joomla-cms/issues/10928#issuecomment-228549658
$prefix = $db->getPrefix();
$canFail = preg_match('/[A-Z]/', $prefix);
try
{
$dbInstaller = new FOF40\Database\Installer($db, $sqlSource);
$dbInstaller->updateSchema();
}
catch (\Exception $e)
{
if (!$canFail)
{
throw $e;
}
}
// Since we're adding common table, I have to nuke the installer cache, otherwise checks on their existence would fail
$dbInstaller->nukeCache();
// Clear the FOF cache
$fakeController = \FOF40\Container\Container::getInstance('com_FOOBAR');
$fakeController->platform->clearCache();
// Clear op-code caches
$this->clearOpcodeCaches();
}
/**
* Runs on uninstallation
*
* @param InstallerAdapter $parent The parent object
*
* @throws RuntimeException If the uninstallation is not allowed
*/
public function uninstall($parent)
{
if (version_compare(JVERSION, '4.1.0', 'ge'))
{
return;
}
// Check dependencies on FOF
$dependencyCount = $this->countHardcodedDependencies();
if ($dependencyCount !== 0)
{
$msg = "<p>You have $dependencyCount extension(s) depending on this version of FOF. The package cannot be uninstalled unless these extensions are uninstalled first.</p>";
Log::add($msg, Log::WARNING, 'jerror');
throw new RuntimeException($msg, 500);
}
}
/**
* Is this package an update to the currently installed FOF? If not (we're a downgrade) we will return false
* and prevent the installation from going on.
*
* @param InstallerAdapter $parent The parent object
*
* @return bool The installation status
*/
protected function amIAnUpdate($parent): bool
{
/** @var JoomlaInstaller $grandpa */
$grandpa = $parent->getParent();
$source = $grandpa->getPath('source');
$target = JPATH_LIBRARIES . '/fof40';
// If FOF is not really installed (someone removed the directory instead of uninstalling?) I have to install it.
if (!Folder::exists($target))
{
return true;
}
$fofVersion = [];
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);
$fofVersion['installed'] = [
'version' => trim($info[0]),
'date' => new JoomlaDate(trim($info[1])),
];
}
else
{
$fofVersion['installed'] = [
'version' => '0.0',
'date' => new JoomlaDate('2011-01-01'),
];
}
$rawData = @file_get_contents($source . '/fof/version.txt');
$rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData;
$info = explode("\n", $rawData);
$fofVersion['package'] = [
'version' => trim($info[0]),
'date' => new JoomlaDate(trim($info[1])),
];
return $fofVersion['package']['date']->toUNIX() >= $fofVersion['installed']['date']->toUNIX();
}
/**
* Loads FOF 3.0 if it's not already loaded
*/
protected function loadFOF40()
{
// Load FOF if not already loaded
if (!defined('FOF40_INCLUDED'))
{
$filePath = JPATH_LIBRARIES . '/fof40/include.php';
if (defined('FOF40_INCLUDED'))
{
return;
}
if (!file_exists($filePath))
{
return;
}
@include_once $filePath;
}
}
/**
* 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 InstallerAdapter $parent
*/
protected function bugfixFilesNotCopiedOnUpdate($parent)
{
$source = $parent->getParent()->getPath('source') . '/fof';
$target = JPATH_LIBRARIES . '/' . $this->libraryFolder;
$this->recursiveConditionalCopy($source, $target);
}
/**
* Clear PHP opcode caches
*
* @return void
*/
protected function clearOpcodeCaches()
{
// Always reset the OPcache if it's enabled. Otherwise there's a good chance the server will not know we are
// replacing .php scripts. This is a major concern since PHP 5.5 included and enabled OPcache by default.
if (function_exists('opcache_reset'))
{
opcache_reset();
}
// Also do that for APC cache
elseif (function_exists('apc_clear_cache'))
{
@apc_clear_cache();
}
}
/**
* 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 = sprintf("%s/%s/%s", JPATH_LIBRARIES, $this->libraryFolder, $file);
if (!is_file($f))
{
continue;
}
File::delete($f);
}
}
// Remove folders
if (!isset($removeList['folders']))
{
return;
}
if (empty($removeList['folders']))
{
return;
}
foreach ($removeList['folders'] as $folder)
{
$f = sprintf("%s/%s/%s", JPATH_LIBRARIES, $this->libraryFolder, $folder);
if (!@file_exists($f) || !is_dir($f) || is_link($f))
{
continue;
}
Folder::delete($f);
}
}
/**
* 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'))
{
/** @noinspection PhpComposerExtensionStubsInspection */
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_fof40'));
$id = $db->setQuery($query)->loadResult();
}
catch (Exception $e)
{
return;
}
if (empty($id))
{
return;
}
$msg = 'Automatically uninstalling FOF 4; this package is no longer required on your site.';
Log::add($msg, Log::INFO, 'jerror');
$parent->uninstall('file', $id);
}
}