Current File : /home/pacjaorg/www/kmm/administrator/manifests/packages/akeebabackup/script.akeebabackup.php |
<?php
/**
* @package akeebabackup
* @copyright Copyright (c)2006-2024 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
/** @noinspection PhpUnused */
defined('_JEXEC') || die;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeModel;
use Joomla\CMS\Factory;
use Joomla\CMS\Installer\Adapter\PackageAdapter;
use Joomla\CMS\Installer\InstallerAdapter;
use Joomla\CMS\Installer\InstallerScript;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;
/**
* Akeeba Backup package extension installation script file.
*
* @see https://docs.joomla.org/Manifest_files#Script_file
* @see UpgradeModel
*/
class Pkg_AkeebabackupInstallerScript extends InstallerScript
{
/**
* @var DatabaseDriver|DatabaseInterface|null
* @since 9.3.0
*/
protected $dbo;
protected $minimumPhp = '7.4.0';
protected $minimumJoomla = '4.3.0';
protected $allowDowngrades = true;
public function preflight($type, $parent)
{
if (!parent::preflight($type, $parent))
{
return false;
}
$this->setDboFromAdapter($parent);
// Do not run on uninstall.
if ($type === 'uninstall')
{
return true;
}
define(
'AKEEBABACKUP_INSTALLATION_PRO',
is_file($parent->getParent()->getPath('source') . '/com_akeebabackup-pro.zip')
);
// If it's an update, try to migrate the encrypted settings key file
if ($type === 'update')
{
$this->migrateSettingsKeyFile();
}
return true;
}
/**
* Called after any type of installation / uninstallation action.
*
* @param string $type Which action is happening (install|uninstall|discover_install|update)
* @param PackageAdapter $parent The object responsible for running this script
*
* @return bool
* @since 9.0.0
*/
public function postflight(string $type, PackageAdapter $parent): bool
{
// Do not run on uninstall.
if ($type === 'uninstall')
{
return true;
}
$this->setDboFromAdapter($parent);
// Forcibly create the autoload_psr4.php file afresh.
if (class_exists(JNamespacePsr4Map::class))
{
try
{
$nsMap = new JNamespacePsr4Map();
@clearstatcache(JPATH_CACHE . '/autoload_psr4.php');
if (function_exists('opcache_invalidate'))
{
@opcache_invalidate(JPATH_CACHE . '/autoload_psr4.php');
}
@clearstatcache(JPATH_CACHE . '/autoload_psr4.php');
$nsMap->create();
if (function_exists('opcache_invalidate'))
{
@opcache_invalidate(JPATH_CACHE . '/autoload_psr4.php');
}
$nsMap->load();
}
catch (\Throwable $e)
{
// In case of failure, just try to delete the old autoload_psr4.php file
if (function_exists('opcache_invalidate'))
{
@opcache_invalidate(JPATH_CACHE . '/autoload_psr4.php');
}
@unlink(JPATH_CACHE . '/autoload_psr4.php');
@clearstatcache(JPATH_CACHE . '/autoload_psr4.php');
}
}
$this->invalidateFiles();
$model = $this->getUpgradeModel();
if (empty($model))
{
return true;
}
return $model->postflight($type, $parent);
}
/**
* Get the UpgradeModel of the installed component
*
* @return UpgradeModel|null The upgrade Model. NULL if it cannot be loaded.
* @since 9.0.0
*/
private function getUpgradeModel(): ?UpgradeModel
{
// Make sure the latest version of the Model file will be loaded, regardless of the OPcache state.
$filePath = JPATH_ADMINISTRATOR . '/components/com_akeebabackup/src/Model/UpgradeModel.php';
if (function_exists('opcache_invalidate'))
{
opcache_invalidate(
$filePath = JPATH_ADMINISTRATOR . '/components/com_akeebabackup/src/Model/UpgradeModel.php', true
);
}
// Can I please load the model?
if (!class_exists('\Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeModel'))
{
if (!file_exists($filePath) || !is_readable($filePath))
{
return null;
}
include_once $filePath;
}
if (!class_exists('\Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeModel'))
{
return null;
}
try
{
$upgradeModel = new UpgradeModel();
}
catch (Throwable $e)
{
return null;
}
if (method_exists($upgradeModel, 'setDatabase'))
{
$upgradeModel->setDatabase($this->dbo ?? Factory::getContainer()->get(DatabaseInterface::class));
}
elseif (method_exists($upgradeModel, 'setDbo'))
{
$upgradeModel->setDbo($this->dbo ?? Factory::getContainer()->get(DatabaseInterface::class));
}
if (method_exists($upgradeModel, 'init'))
{
$upgradeModel->init();
}
return $upgradeModel;
}
/**
* Set the database object from the installation adapter, if possible
*
* @param InstallerAdapter|mixed $adapter The installation adapter, hopefully.
*
* @return void
* @since 9.3.0
*/
private function setDboFromAdapter($adapter): void
{
$this->dbo = null;
if (class_exists(InstallerAdapter::class) && ($adapter instanceof InstallerAdapter))
{
/**
* If this is Joomla 4.2+ the adapter has a protected getDatabase() method which we can access with the
* magic property $adapter->db. On Joomla 4.1 and lower this is not available. So, we have to first figure
* out if we can actually use the magic property...
*/
try
{
$refObj = new ReflectionObject($adapter);
if ($refObj->hasMethod('getDatabase'))
{
$this->dbo = $adapter->db;
return;
}
}
catch (Throwable $e)
{
// If something breaks we will fall through
}
}
$this->dbo = Factory::getContainer()->get(DatabaseInterface::class);
}
private function invalidateFiles()
{
$extensionsFromPackage = $this->invF_getExtensionsFromManifest($this->invF_getManifestXML(__CLASS__));
foreach ($extensionsFromPackage as $element)
{
$paths = [];
if (strpos($element, 'plg_') === 0)
{
[$dummy, $folder, $plugin] = explode('_', $element);
$paths = [
sprintf('%s/%s/%s/services', JPATH_PLUGINS, $folder, $plugin),
sprintf('%s/%s/%s/src', JPATH_PLUGINS, $folder, $plugin),
];
}
elseif (strpos($element, 'com_') === 0)
{
$paths = [
sprintf('%s/components/%s/services', JPATH_ADMINISTRATOR, $element),
sprintf('%s/components/%s/src', JPATH_ADMINISTRATOR, $element),
sprintf('%s/components/%s/src', JPATH_SITE, $element),
sprintf('%s/components/%s/src', JPATH_API, $element),
];
}
elseif (strpos($element, 'mod_') === 0)
{
$paths = [
sprintf('%s/modules/%s/services', JPATH_ADMINISTRATOR, $element),
sprintf('%s/modules/%s/src', JPATH_ADMINISTRATOR, $element),
sprintf('%s/modules/%s/services', JPATH_SITE, $element),
sprintf('%s/modules/%s/src', JPATH_SITE, $element),
];
}
else
{
continue;
}
foreach ($paths as $path)
{
$this->invF_recursiveClearCache($path);
}
}
$this->invF_clearFileInOPCache(JPATH_CACHE . '/autoload_psr4.php');
}
private function invF_getManifestXML($class): ?SimpleXMLElement
{
// Get the package element name
$myPackage = strtolower(str_replace('InstallerScript', '', $class));
// Get the package's manifest file
$filePath = JPATH_MANIFESTS . '/packages/' . $myPackage . '.xml';
if (!@file_exists($filePath) || !@is_readable($filePath))
{
return null;
}
$xmlContent = @file_get_contents($filePath);
if (empty($xmlContent))
{
return null;
}
return new SimpleXMLElement($xmlContent);
}
private function invF_xmlNodeToExtensionName(SimpleXMLElement $fileField): ?string
{
$type = (string) $fileField->attributes()->type;
$id = (string) $fileField->attributes()->id;
switch ($type)
{
case 'component':
case 'file':
case 'library':
$extension = $id;
break;
case 'plugin':
$group = (string) $fileField->attributes()->group ?? 'system';
$extension = 'plg_' . $group . '_' . $id;
break;
case 'module':
$client = (string) $fileField->attributes()->client ?? 'site';
$extension = (($client != 'site') ? 'a' : '') . $id;
break;
default:
$extension = null;
break;
}
return $extension;
}
private function invF_getExtensionsFromManifest(?SimpleXMLElement $xml): array
{
if (empty($xml))
{
return [];
}
$extensions = [];
foreach ($xml->xpath('//files/file') as $fileField)
{
$extensions[] = $this->invF_xmlNodeToExtensionName($fileField);
}
return array_filter($extensions);
}
private function invF_clearFileInOPCache(string $file): bool
{
static $hasOpCache = null;
if (is_null($hasOpCache))
{
$hasOpCache = ini_get('opcache.enable')
&& function_exists('opcache_invalidate')
&& (!ini_get('opcache.restrict_api')
|| stripos(
realpath($_SERVER['SCRIPT_FILENAME']), ini_get('opcache.restrict_api')
) === 0);
}
if ($hasOpCache && (strtolower(substr($file, -4)) === '.php'))
{
$ret = opcache_invalidate($file, true);
@clearstatcache($file);
return $ret;
}
return false;
}
private function invF_recursiveClearCache(string $path): void
{
if (!@is_dir($path))
{
return;
}
/** @var DirectoryIterator $file */
foreach (new DirectoryIterator($path) as $file)
{
if ($file->isDot() || $file->isLink())
{
continue;
}
if ($file->isDir())
{
$this->invF_recursiveClearCache($file->getPathname());
continue;
}
if (!$file->isFile())
{
continue;
}
$this->invF_clearFileInOPCache($file->getPathname());
}
}
/**
* Migrate the encrypted settings file moving to Akeeba Backup 9.8.0 or later
*
* @return void
* @since 9.8.0
*/
private function migrateSettingsKeyFile(): void
{
$oldFile = JPATH_ADMINISTRATOR . '/components/com_akeebabackup/engine/serverkey.php';
$newFile = JPATH_ADMINISTRATOR . '/components/com_akeebabackup/serverkey.php';
if (@file_exists($oldFile))
{
\Joomla\Filesystem\File::copy($oldFile, $newFile);
}
}
}