Your IP : 216.73.216.11


Current Path : /proc/self/root/tmp/
Upload File :
Current File : //proc/self/root/tmp/phpjsSzwu

<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller\Mixin;

// Protect from unauthorized access
use Akeeba\Engine\Platform;

defined('_JEXEC') || die();

/**
 * Provides the method to set the current backup profile from the request variables
 */
trait ActivateProfile
{
	/**
	 * Set the active profile from the input parameters
	 */
	protected function setProfile()
	{
		$profile = $this->input->get('profile', 1, 'int');
		$profile = max(1, $profile);

		$this->container->platform->setSessionVar('profile', $profile, 'akeeba');

		/**
		 * DO NOT REMOVE!
		 *
		 * The Model will only try to load the configuration after nuking the factory. This causes Profile 1 to be
		 * loaded first. Then it figures out it needs to load a different profile and it does – but the protected keys
		 * are NOT replaced, meaning that certain configuration parameters are not replaced. Most notably, the chain.
		 * This causes backups to behave weirdly. So, DON'T REMOVE THIS UNLESS WE REFACTOR THE MODEL.
		 */
		Platform::getInstance()->load_configuration($profile);
	}

}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller\Mixin;

// Protect from unauthorized access
use Akeeba\Engine\Platform;

defined('_JEXEC') || die();

/**
 * Provides the method to send custom HTTP redirection headers
 */
trait CustomRedirection
{
	/**
	 * Sends custom HTTP redirection headers
	 *
	 * @param   string  $url     The URL to redirect to
	 * @param   string  $header  The HTTP header to send, default 302 Found
	 */
	protected function customRedirect($url, $header = '302 Found')
	{
		header('HTTP/1.1 ' . $header);
		header('Location: ' . $url);
		header('Content-Type: text/plain');
		header('Connection: close');

		$this->container->platform->closeApplication();
	}

}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller\Mixin;

// Protect from unauthorized access
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\Complexify;
use DateInterval;
use Exception;
use FOF40\Date\Date;
use Joomla\CMS\Language\Text;

defined('_JEXEC') || die();

/**
 * Provides the method to check whether front-end backup is enabled and weather the key is correct
 */
trait FrontEndPermissions
{
	private static $ENABLE_DATE_CHECKS = false;

	/**
	 * Check that the user has sufficient permissions to access the front-end backup feature.
	 *
	 * @return  void
	 */
	protected function checkPermissions()
	{
		// Is frontend backup enabled?
		$febEnabled = $this->container->params->get('legacyapi_enabled', 0) == 1;

		// Is the Secret Key strong enough?
		$validKey     = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');
		$validKeyTrim = trim($validKey);

		if (!Complexify::isStrongEnough($validKey, false))
		{
			$febEnabled = false;
		}

		if (static::$ENABLE_DATE_CHECKS && !$this->confirmDates())
		{
			@ob_end_clean();
			echo '402 Your version of Akeeba Backup is too old. Please update it to re-enable the remote backup features';
			flush();

			$this->container->platform->closeApplication();
		}

		// Is the key good?
		$key = $this->input->get('key', '', 'none', 2);

		if (!$febEnabled || ($key != $validKey) || (empty($validKeyTrim)))
		{
			@ob_end_clean();
			echo sprintf("403 %s", Text::_('COM_AKEEBA_COMMON_ERR_NOT_ENABLED'));
			flush();

			$this->container->platform->closeApplication();
		}

	}

	private function confirmDates()
	{
		if (!defined('AKEEBA_DATE'))
		{
			return false;
		}

		try
		{
			$jDate    = new Date(AKEEBA_DATE);
			$interval = new DateInterval('P4M');
			$jFuture  = $jDate->add($interval);
			$futureTS = $jFuture->toUnix();
		}
		catch (Exception $e)
		{
			return false;
		}

		return time() <= $futureTS;
	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Backup\Site\Model\Json\Task;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\Complexify;
use Exception;
use FOF40\Container\Container;
use FOF40\Controller\Controller;
use FOF40\Controller\Mixin\PredefinedTaskList;
use FOF40\Input\Input;
use Joomla\CMS\Document\Document;
use Joomla\CMS\Document\JsonDocument;
use Joomla\CMS\Factory;
use JsonSerializable;

/**
 * API version
 *
 * 400: First JSON API v2 implementation
 */
if (!defined('AKEEBA_JSON_API_VERSION'))
{
	define('AKEEBA_JSON_API_VERSION', 400);
}

/**
 * Akeeba Backup JSON API v2
 *
 * @since   7.4.0
 */
class Api extends Controller
{
	use PredefinedTaskList;

	/**
	 * Secret Key (cached for quicker retrieval)
	 *
	 * @var   null|string
	 * @since 7.4.0
	 */
	private $key = null;

	/**
	 * Overridden constructor
	 *
	 * @param   Container  $container  The application container
	 * @param   array      $config     The configuration array
	 *
	 * @since   7.4.0
	 */
	public function __construct(Container $container, array $config)
	{
		parent::__construct($container, $config);

		$this->setPredefinedTaskList(['main']);
	}

	public function main()
	{
		if (!defined('AKEEBA_BACKUP_ORIGIN'))
		{
			define('AKEEBA_BACKUP_ORIGIN', 'json');
		}

		$outputBuffering = function_exists('ob_start') && function_exists('ob_end_clean');

		// Use the model to parse the JSON message
		if ($outputBuffering)
		{
			@ob_start();
		}

		try
		{
			if (!$this->verifyKey())
			{
				throw new \RuntimeException("Access denied", 503);
			}

			$httpVerb = $this->input->getMethod() ?? 'GET';

			switch ($httpVerb)
			{
				case 'GET':
					$method = $this->input->get->getCmd('method', '');
					$input  = new Input('GET');
					break;

				case 'POST':
					$method = $this->input->post->getCmd('method', '');
					$input  = new Input('POST');
					break;

				default:
					throw new \RuntimeException("Invalid HTTP method {$httpVerb}", 405);
					break;
			}

			if (class_exists('Joomla\CMS\Component\ComponentHelper') && \Joomla\CMS\Component\ComponentHelper::isEnabled('com_akeebabackup'))
			{
				throw new \RuntimeException(sprintf('Please finish upgrading to Akeeba Backup 9 and uninstall Akeeba Backup 8 per the instructions shown on your site\'s backend, Components, Akeeba Backup'), 400);
			}

			$taskHandler = new Task($this->container);

			$result = [
				'status' => 200,
				'data' => $taskHandler->execute($method, $input->getData())
			];
		}
		catch (Exception $e)
		{
			$result = [
				'status' => $e->getCode(),
				'data'   => $e->getMessage(),
			];
		}

		if ($outputBuffering)
		{
			@ob_end_clean();
		}

		/** @var JsonDocument $doc */
		$doc = Document::getInstance('json');

		if (!($doc instanceof JsonDocument))
		{
			$this->workaroundResponse($result);
		}

		// Force cache busting
		$app = $this->container->platform;
		$app->setHeader('Expires', 'Wed, 17 Aug 2005 00:00:00 GMT', true);
		$app->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', true);
		$app->setHeader('Pragma', 'no-cache', true);


		$doc->setName('akeeba');

		$jsonOptions = (defined('JDEBUG') && JDEBUG) ? JSON_PRETTY_PRINT : 0;

		echo json_encode($result, $jsonOptions);
	}

	/**
	 * Send a JSON response when format=html or anything other than json
	 *
	 * @param   JsonSerializable|array  $result
	 *
	 * @throws Exception
	 *
	 * @since  7.4.0
	 */
	private function workaroundResponse($result): void
	{
		// Disable caching
		@header('Expires: Wed, 17 Aug 2005 00:00:00 GMT', true);
		@header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0', true);
		@header('Pragma: no-cache', true);

		// JSON content
		@header('Content-Type: application/json; charset=utf-8', true);
		@header('Content-Disposition: attachment; filename="joomla.json"', true);

		$jsonOptions = (defined('JDEBUG') && JDEBUG) ? JSON_PRETTY_PRINT : 0;

		echo json_encode($result, $jsonOptions);

		Factory::getApplication()->close();
	}

	/**
	 * Verifies the Secret Key (API token)
	 *
	 * @return  bool
	 * @since   7.4.0
	 */
	private function verifyKey(): bool
	{
		// Is the JSON API enabled?
		if ($this->container->params->get('jsonapi_enabled', 0) != 1)
		{
			return false;
		}

		// Is the key secure enough?
		$validKey = $this->serverKey();

		if (empty($validKey) || empty(trim($validKey)) || !Complexify::isStrongEnough($validKey, false))
		{
			return false;
		}

		/**
		 * Get the API authentication token. There are two sources
		 * 1. X-Akeeba-Auth header (preferred, overrides all others)
		 * 2. the _akeebaAuth GET parameter
		 */
		$authSource = $this->input->server->getString('HTTP_X_AKEEBA_AUTH', null);

		if (is_null($authSource))
		{
			$authSource = $this->input->get->getString('_akeebaAuth', null);
		}

		// No authentication token? No joy.
		if (empty($authSource) || !is_string($authSource) || empty(trim($authSource)))
		{
			return false;
		}

		return hash_equals($validKey, $authSource);
	}

	/**
	 * Get the server key, i.e. the Secret Word for the front-end backups and JSON API
	 *
	 * @return  mixed
	 *
	 * @since   7.4.0
	 */
	private function serverKey()
	{
		if (is_null($this->key))
		{
			$this->key = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');
		}

		return $this->key;
	}

}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Backup\Site\Controller\Mixin\ActivateProfile;
use Akeeba\Backup\Site\Controller\Mixin\CustomRedirection;
use Akeeba\Backup\Site\Controller\Mixin\FrontEndPermissions;
use Akeeba\Engine\Factory;
use FOF40\Container\Container;
use FOF40\Controller\Controller;
use FOF40\Controller\Mixin\PredefinedTaskList;
use FOF40\Date\Date;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;

if (!defined('AKEEBA_BACKUP_ORIGIN'))
{
	define('AKEEBA_BACKUP_ORIGIN', 'frontend');
}

/**
 * Controller for the front-end backup feature.
 *
 * The Traits used by this class offer most of the features you don't see, especially those pertaining to security:
 * PredefinedTaskList   Only allows certain tasks to be called.
 * FrontEndPermissions  Validates the secret word before running a task through checkPermissions.
 * ActivateProfile      Finds the profile specified in the URL and loads it through setProfile.
 * CustomRedirection    Provides customRedirect for HTTP redirects without dealing with CMS inconsistencies.
 */
class Backup extends Controller
{
	use PredefinedTaskList, FrontEndPermissions, ActivateProfile, CustomRedirection;

	/**
	 * Overridden constructor
	 *
	 * @param   Container  $container  The application container
	 * @param   array      $config     The configuration array
	 */
	public function __construct(Container $container, array $config)
	{
		parent::__construct($container, $config);

		$this->setPredefinedTaskList(['main', 'step']);
	}

	/**
	 * Start a front-end legacy backup
	 *
	 * @return  void
	 */
	public function main()
	{
		$this->checkPermissions();
		$this->setProfile();

		if (class_exists('Joomla\CMS\Component\ComponentHelper') && \Joomla\CMS\Component\ComponentHelper::isEnabled('com_akeebabackup'))
		{
			@ob_end_clean();
			echo '500 ERROR -- Please finish upgrading to Akeeba Backup 9 and uninstall Akeeba Backup 8 per the instructions shown on your site\'s backend, Components, Akeeba Backup';
			flush();

			$this->container->platform->closeApplication();
		}


		// Get the backup ID
		$backupId = $this->input->get('backupid', null, 'cmd');

		if (empty($backupId))
		{
			$backupId = null;
		}

		/** @var \Akeeba\Backup\Site\Model\Backup $model */
		$model = $this->container->factory->model('Backup')->tmpInstance();

		$dateNow = new Date();

		$model->setState('tag', AKEEBA_BACKUP_ORIGIN);
		$model->setState('backupid', $backupId);
		$model->setState('description', $model->getDefaultDescription() . ' (Frontend)');
		$model->setState('comment', '');

		$array = $model->startBackup();

		$backupId = $model->getState('backupid', null, 'cmd');

		$this->processEngineReturnArray($array, $backupId);
	}

	/**
	 * Step through a front-end legacy backup
	 *
	 * @return  void
	 */
	public function step()
	{
		// Setup
		$this->checkPermissions();
		$this->setProfile();

		// Get the backup ID
		$backupId = $this->input->get('backupid', null, 'cmd');

		if (empty($backupId))
		{
			$backupId = null;
		}

		/** @var \Akeeba\Backup\Site\Model\Backup $model */
		$model = $this->container->factory->model('Backup')->tmpInstance();

		$model->setState('tag', AKEEBA_BACKUP_ORIGIN);
		$model->setState('backupid', $backupId);

		$array = $model->stepBackup();

		$backupId = $model->getState('backupid', null, 'cmd');

		$this->processEngineReturnArray($array, $backupId);
	}

	/**
	 * Used by the tasks to process Akeeba Engine's return array. Depending on the result and the component options we
	 * may throw text output or send an HTTP redirection header.
	 *
	 * @param   array   $array     The return array to process
	 * @param   string  $backupId  The backup ID (used to step the backup process)
	 */
	private function processEngineReturnArray($array, $backupId)
	{
		if ($array['Error'] != '')
		{
			@ob_end_clean();
			echo '500 ERROR -- ' . $array['Error'];
			flush();

			$this->container->platform->closeApplication();
		}

		if ($array['HasRun'] == 1)
		{
			// All done
			Factory::nuke();
			Factory::getFactoryStorage()->reset();
			@ob_end_clean();
			header('Content-type: text/plain');
			header('Connection: close');
			echo '200 OK';
			flush();

			$this->container->platform->closeApplication();
		}

		$noredirect = $this->input->get('noredirect', 0, 'int');

		if ($noredirect != 0)
		{
			@ob_end_clean();
			header('Content-type: text/plain');
			header('Connection: close');
			echo "301 More work required -- BACKUPID ###$backupId###";
			flush();

			$this->container->platform->closeApplication();
		}

		$curUri  = Uri::getInstance();
		$ssl     = $curUri->isSSL() ? 1 : 0;
		$tempURL = Route::_('index.php?option=com_akeeba', false, $ssl);
		$uri     = new Uri($tempURL);

		$uri->delVar('key');
		$uri->setVar('view', 'Backup');
		$uri->setVar('task', 'step');
		$uri->setVar('profile', $this->input->get('profile', 1, 'int'));

		if (!empty($backupId))
		{
			$uri->setVar('backupid', $backupId);
		}

		// Maybe we have a multilingual site?
		$language    = $this->container->platform->getLanguage();
		$languageTag = $language->getTag();

		$uri->setVar('lang', $languageTag);

		$key            = $this->input->get('key', '', 'none', 2);
		$redirectionUrl = $uri->toString() . '&key=' . urlencode($key);

		$this->customRedirect($redirectionUrl);
	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Backup\Site\Controller\Mixin\FrontEndPermissions;
use Akeeba\Backup\Site\Model\Statistics;
use FOF40\Container\Container;
use FOF40\Controller\Controller;
use FOF40\Controller\Mixin\PredefinedTaskList;

/**
 * Controller for the front-end Check Backups features
 */
class Check extends Controller
{
	use PredefinedTaskList, FrontEndPermissions;

	/**
	 * Overridden constructor
	 *
	 * @param   Container  $container  The application container
	 * @param   array      $config     The configuration array
	 */
	public function __construct(Container $container, array $config)
	{
		parent::__construct($container, $config);

		$this->setPredefinedTaskList(['main']);
	}

	/**
	 * Checks for failed backups and sends out any notification emails
	 */
	public function main()
	{
		// Check permissions
		$this->checkPermissions();

		/** @var Statistics $model */
		$model  = $this->container->factory->model('Statistics')->tmpInstance();
		$result = $model->notifyFailed();

		$message = $result['result'] ? '200 ' : '500 ';
		$message .= implode(', ', $result['message']);

		@ob_end_clean();
		header('Content-type: text/plain');
		header('Connection: close');
		echo $message;
		flush();

		$this->container->platform->closeApplication();
	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller;

// Protect from unauthorized access
defined('_JEXEC') || die();

use FOF40\Container\Container;
use FOF40\Controller\Controller;
use FOF40\Controller\Mixin\PredefinedTaskList;

/**
 * Controller for the JSON API
 */
class Json extends Controller
{
	use PredefinedTaskList;

	/**
	 * Overridden constructor
	 *
	 * @param   Container  $container  The application container
	 * @param   array      $config     The configuration array
	 */
	public function __construct(Container $container, array $config)
	{
		parent::__construct($container, $config);

		$this->setPredefinedTaskList(['json']);
	}

	/**
	 * Handles API calls
	 */
	public function json()
	{
		// Use the model to parse the JSON message
		if (function_exists('ob_start'))
		{
			@ob_start();
		}

		$sourceJSON = $this->input->get('json', null, 'raw', 2);

		/** @var \Akeeba\Backup\Site\Model\Json $model */
		$model = $this->getModel();
		$json  = $model->execute($sourceJSON);

		if (function_exists('ob_end_clean'))
		{
			@ob_end_clean();
		}

		// Just dump the JSON and tear down the application, without plugins executing
		header('Content-type: text/plain');
		header('Connection: close');
		echo $json;

		$this->container->platform->closeApplication();
	}

}
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<html><head><title></title></head><body></body></html><?xml version="1.0"?>
<!--
    This only works on IIS 7 or later. See https://www.iis.net/configreference/system.webserver/security/requestfiltering/fileextensions
-->
<configuration>
    <system.webServer>
        <security>
            <requestFiltering>
                <fileExtensions allowUnlisted="false" >
                    <clear />
                    <add fileExtension=".html" allowed="true"/>
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration><?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Dispatcher;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Backup\Admin\Dispatcher\Dispatcher as AdminDispatcher;
use Akeeba\Backup\Admin\Helper\SecretWord;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use FOF40\Container\Container;
use FOF40\Dispatcher\Exception\AccessForbidden;
use Joomla\CMS\Document\Document;
use Joomla\CMS\Document\JsonDocument as JDocumentJSON;
use Joomla\CMS\Factory as JFactory;
use Joomla\CMS\Language\Text;

class Dispatcher extends AdminDispatcher
{
	/** @var   string  The name of the default view, in case none is specified */
	public $defaultView = 'Backup';

	/**
	 * Dispatcher constructor. Overridden to set up a different default view and migrated views map than the back-end.
	 *
	 * @param   Container  $container  The component's container
	 * @param   array      $config     Optional configuration overrides
	 */
	public function __construct(Container $container, array $config)
	{
		parent::__construct($container, $config);

		$this->defaultView = 'Backup';

		$this->viewNameAliases = [
			'backup'  => 'Backup',
			'backups' => 'Backup',
			'check'   => 'Check',
			'checks'  => 'Check',
			'json'    => 'Json',
			'jsons'   => 'Json',
		];
	}


	/**
	 * Executes before dispatching the request to the appropriate controller
	 */
	public function onBeforeDispatch()
	{
		// Make sure we have a version loaded
		@include_once($this->container->backEndPath . '/version.php');

		if (!defined('AKEEBA_VERSION'))
		{
			define('AKEEBA_VERSION', 'dev');
			define('AKEEBA_DATE', date('Y-m-d'));
		}

		// Core version: there is no front-end, throw a 403
		if (!defined('AKEEBA_PRO') || !AKEEBA_PRO)
		{
			throw new AccessForbidden(Text::_('COM_AKEEBA_ERR_NO_FRONTEND_IN_CORE'));
		}

//		$this->container->platform->importPlugin('akeebabackup');
//		$this->container->platform->runPlugins('onComAkeebaDispatcherBeforeDispatch', []);

		$this->onBeforeDispatchViewAliases();

		// Load the FOF language
		$lang = $this->container->platform->getLanguage();
		$lang->load('lib_fof40', JPATH_SITE, 'en-GB', true, true);
		$lang->load('lib_fof40', JPATH_SITE, null, true, false);

		// Necessary defines for Akeeba Engine
		if (!defined('AKEEBAENGINE'))
		{
			define('AKEEBAENGINE', 1);
			define('AKEEBAROOT', $this->container->backEndPath . '/BackupEngine');
			define('ALICEROOT', $this->container->backEndPath . '/AliceEngine');
		}

		// Make sure we have a profile set throughout the component's lifetime
		$profile_id = $this->container->platform->getSessionVar('profile', null, 'akeeba');

		if (is_null($profile_id))
		{
			$this->container->platform->setSessionVar('profile', 1, 'akeeba');
		}

		// Load Akeeba Engine
		$basePath = $this->container->backEndPath;
		require_once $basePath . '/BackupEngine/Factory.php';

		// Load the Akeeba Engine configuration
		Platform::addPlatform('joomla3x', JPATH_COMPONENT_ADMINISTRATOR . '/BackupPlatform/Joomla3x');
		$akeebaEngineConfig = Factory::getConfiguration();
		Platform::getInstance()->load_configuration();
		unset($akeebaEngineConfig);

		// Prevents the "SQLSTATE[HY000]: General error: 2014" due to resource sharing with Akeeba Engine
		$this->fixPDOMySQLResourceSharing();

		// Load the utils helper library
		Platform::getInstance()->load_version_defines();

		// Make sure the front-end backup Secret Word is stored encrypted
		$params = $this->container->params;
		SecretWord::enforceEncryption($params, 'frontend_secret_word');

		// Create a media file versioning tag
		$this->container->mediaVersion = md5(AKEEBA_VERSION . AKEEBA_DATE);
	}

	public function onAfterDispatch()
	{
		// Make sure that Api and Json views forcibly get format=json
		if (in_array($this->view, ['Api', 'Json']))
		{
			$format = $this->input->getCmd('format', 'html');

			if ($format == 'json')
			{
				return;
			}

			$app     = JFactory::getApplication();

			// Disable caching, disable offline, force use of index.php
			$app->set('caching', 0);
			$app->set('offline', 0);
			$app->set('themeFile', 'index.php');

			/** @var \Joomla\CMS\Document\JsonDocument $doc */
			$doc = Document::getInstance('json');

			$app->loadDocument($doc);

			if (property_exists(JFactory::class, 'document'))
			{
				JFactory::$document = $doc;
			}

			// Set a custom document name
			/** @var JDocumentJSON $document */
			$document = $this->container->platform->getDocument();
			$document->setName('akeeba_backup');

		}
	}
}
<?xml version="1.0"?>
<!--
    This only works on IIS 7 or later. See https://www.iis.net/configreference/system.webserver/security/requestfiltering/fileextensions
-->
<configuration>
    <system.webServer>
        <security>
            <requestFiltering>
                <fileExtensions allowUnlisted="false" >
                    <clear />
                    <add fileExtension=".html" allowed="true"/>
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration><?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Encapsulation;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Backup\Site\Model\Json\EncapsulationInterface;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\Encrypt;

abstract class Base implements EncapsulationInterface
{
	/**
	 * The numeric ID of this encapsulation
	 *
	 * @var  int
	 */
	protected $id = 0;

	/**
	 * The code of this encapsulation
	 *
	 * @var  string
	 */
	protected $code = 'ENCAPSULATION_VOID';

	/**
	 * The description of this encapsulation
	 *
	 * @var  string
	 */
	protected $description = 'Invalid encapsulation';

	/**
	 * The encryption object which is set up for use with the JSON API
	 *
	 * @var  Encrypt
	 */
	private $encryption;

	/**
	 * Public constructor. Called by children to customise the encapsulation handler object
	 *
	 * @param   int     $id           Numeric ID
	 * @param   string  $code         Code
	 * @param   string  $description  Human readable description
	 */
	function __construct($id, $code, $description)
	{
		$this->id          = $id;
		$this->code        = strtoupper($code);
		$this->description = $description;
	}

	/**
	 * Returns information about the encapsulation supported by this class. The return array has the following keys:
	 * id: The numeric ID of the encapsulation, e.g. 3
	 * code: The short code of the encapsulation, e.g. ENCAPSULATION_AESCTR256
	 * description: A human readable descriptions, e.g. "Data in AES-256 stream (CTR) mode encrypted JSON"
	 *
	 * @return  array  See above
	 */
	public function getInformation()
	{
		return array(
			'id'          => $this->id,
			'code'        => $this->code,
			'description' => $this->description,
		);
	}

	/**
	 * Checks if the request body authorises the user to use the API. Each encapsulation can implement its own
	 * authorisation method. This method is only called after the request body has been successfully decoded, therefore
	 * encrypted encapsulations can simply return true.
	 *
	 * @param   string $serverKey The server key we need to check the authorisation
	 * @param   array  $body      The decoded body (as returned by the decode() method)
	 *
	 * @return  bool  True if authorised
	 */
	public function isAuthorised($serverKey, $body)
	{
		return true;
	}

	/**
	 * Is the provided encapsulation type supported by this class?
	 *
	 * @param   int  $encapsulation  Encapsulation type
	 *
	 * @return  bool  True if supported
	 */
	public function isSupported($encapsulation)
	{
		return $encapsulation == $this->id;
	}

	/**
	 * Decodes the data. For encrypted encapsulations this means base64-decoding the data, decrypting it and then JSON-
	 * decoding the result. If any error occurs along the way the appropriate exception is thrown.
	 *
	 * The data being decoded corresponds to the Request Body described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to decode data
	 * @param   string  $data       Encoded data
	 *
	 * @return  string  The decoded data.
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be decoded successfully
	 *
	 * @see     https://www.akeeba.com/documentation/json-api/ar01s02.html
	 */
	public function decode($serverKey, $data)
	{
		return $data;
	}

	/**
	 * Encodes the data. The data is JSON encoded by this method before encapsulation takes place. Encrypted
	 * encapsulations will then encrypt the data and base64-encode it before returning it.
	 *
	 * The data being encoded correspond to the body > data structure described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to encode data
	 * @param   mixed   $data       The data to encode, typically a string, array or object
	 *
	 * @return  string  The encapsulated data
	 *
	 * @see     https://www.akeeba.com/documentation/json-api/ar01s02s02.html
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be converted to JSON
	 */
	public function encode($serverKey, $data)
	{
		return $data;
	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Encapsulation;

// Protect from unauthorized access
defined('_JEXEC') || die();

/**
 * Raw (plain text) encapsulation
 */
class Raw extends Base
{
	/**
	 * Constructs the encapsulation handler object
	 */
	function __construct()
	{
		parent::__construct(1, 'ENCAPSULATION_RAW', 'Data in plain-text JSON');
	}

	/**
	 * Decodes the data. For encrypted encapsulations this means base64-decoding the data, decrypting it and then JSON-
	 * decoding the result. If any error occurs along the way the appropriate exception is thrown.
	 *
	 * The data being decoded corresponds to the Request Body described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to decode data
	 * @param   string  $data       Encoded data
	 *
	 * @return  string  The decoded data.
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be decoded successfully
	 *
	 * @see     https://www.akeeba.com/documentation/json-api/ar01s02.html
	 */
	public function decode($serverKey, $data)
	{
		return $data;
	}

	/**
	 * Encodes the data. The data is JSON encoded by this method before encapsulation takes place. Encrypted
	 * encapsulations will then encrypt the data and base64-encode it before returning it.
	 *
	 * The data being encoded correspond to the body > data structure described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to encode data
	 * @param   mixed   $data       The data to encode, typically a string, array or object
	 *
	 * @return  string  The encapsulated data
	 *
	 * @see     https://www.akeeba.com/documentation/json-api/ar01s02s02.html
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be converted to JSON
	 */
	public function encode($serverKey, $data)
	{
		return $data;
	}

	/**
	 * Checks if the request body authorises the user to use the API. Each encapsulation can implement its own
	 * authorisation method. This method is only called after the request body has been successfully decoded, therefore
	 * encrypted encapsulations can simply return true.
	 *
	 * @param   string $serverKey The server key we need to check the authorisation
	 * @param   array  $body      The decoded body (as returned by the decode() method)
	 *
	 * @return  bool  True if authorised
	 */
	public function isAuthorised($serverKey, $body)
	{
		$authenticated = false;

		if (isset($body['challenge']) && (strpos($body['challenge'], ':') >= 2) && (strlen($body['challenge']) >= 3))
		{
			[$challengeData, $providedHash] = explode(':', $body['challenge']);
			$computedHash = strtolower(md5($challengeData . $serverKey));
			$authenticated = ($computedHash == $providedHash);
		}

		return $authenticated;
	}

}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') || die();

// Protect from unauthorized access
use Akeeba\Backup\Site\Model\Json\TaskInterface;
use FOF40\Container\Container;

class AbstractTask implements TaskInterface
{
	/**
	 * The container of the component we belong to
	 *
	 * @var  Container
	 */
	protected $container = null;

	/**
	 * The method name
	 *
	 * @var  string
	 */
	protected $methodName = '';

	/**
	 * Public constructor
	 *
	 * @param   Container  $container  The container of the component we belong to
	 */
	public function __construct(Container $container)
	{
		$this->container = $container;

		$path = explode('\\', get_class($this));
		$shortName = array_pop($path);
		$this->methodName = lcfirst($shortName);
	}

	/**
	 * Return the JSON API task's name ("method" name). Remote clients will use it to call us.
	 *
	 * @return  string
	 */
	public function getMethodName()
	{
		return $this->methodName;
	}

	/**
	 * Execute the JSON API task
	 *
	 * @param   array  $parameters  The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		throw new \LogicException(__CLASS__ . ' has not implemented its execute() method yet.');
	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Filter\InputFilter;

/**
 * Return folder browser results
 *
 * @deprecated
 */
class Browse extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array  $parameters  The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = [])
	{
		throw new \RuntimeException('This method is no longer supported by the Akeeba Remote JSON API', 501);
	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Backup\Site\Model\Statistics;
use Akeeba\Engine\Platform;

/**
 * Delete a backup record
 */
class Delete extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'backup_id' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$backup_id = (int)$defConfig['backup_id'];

		/** @var Statistics $model */
		$model = $this->container->factory->model('Statistics')->tmpInstance();
		$model->setState('id', $backup_id);

		try
		{
			$model->delete();
		}
		catch (\Exception $e)
		{
			throw new \RuntimeException($e->getMessage(), 500);
		}

		return true;
	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Backup\Site\Model\Statistics;
use Akeeba\Engine\Platform;

/**
 * Delete the backup archives of a backup record
 */
class DeleteFiles extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'backup_id' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$backup_id = (int)$defConfig['backup_id'];

		/** @var Statistics $model */
		$model = $this->container->factory->model('Statistics')->tmpInstance();
		$model->setState('id', $backup_id);

		try
		{
			$model->deleteFile();
		}
		catch (\Exception $e)
		{
			throw new \RuntimeException($e->getMessage(), 500);
		}

		return true;
	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') || die();

/**
 * Delete a backup profile
 *
 * @deprecated
 */
class DeleteProfile extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		throw new \RuntimeException('This method is no longer supported by the Akeeba Remote JSON API', 501);
	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Download a chunk of a backup archive over HTTP
 */
class Download extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'backup_id'  => 0,
			'part_id'    => 1,
			'segment'    => 1,
			'chunk_size' => 1
		);

		$defConfig = array_merge($defConfig, $parameters);

		$backup_id  = (int)$defConfig['backup_id'];
		$part_id    = (int)$defConfig['part_id'];
		$segment    = (int)$defConfig['segment'];
		$chunk_size = (int)$defConfig['chunk_size'];

		$backup_stats = Platform::getInstance()->get_statistics($backup_id);

		if (empty($backup_stats))
		{
			// Backup record doesn't exist
			throw new \RuntimeException('Invalid backup record identifier', 404);
		}

		$files = Factory::getStatistics()->get_all_filenames($backup_stats);

		if ((($files === null ? 0 : count($files)) < $part_id) || ($part_id <= 0))
		{
			// Invalid part
			throw new \RuntimeException('Invalid backup part', 404);
		}

		$file = $files[ $part_id - 1 ];

		$filesize = @filesize($file);
		$seekPos  = $chunk_size * 1048576 * ($segment - 1);

		if ($seekPos > $filesize)
		{
			// Trying to seek past end of file
			throw new \RuntimeException('Invalid segment', 404);
		}

		$fp = fopen($file, 'r');

		if ($fp === false)
		{
			// Could not read file
			throw new \RuntimeException('Error reading backup archive', 500);
		}

		rewind($fp);
		if (fseek($fp, $seekPos, SEEK_SET) === -1)
		{
			// Could not seek to position
			throw new \RuntimeException('Error reading specified segment', 500);
		}

		$buffer = fread($fp, 1048576);

		if ($buffer === false)
		{
			throw new \RuntimeException('Error reading specified segment', 500);
		}

		fclose($fp);

		return base64_encode($buffer);

	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Download an entire backup archive directly over HTTP
 */
class DownloadDirect extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'backup_id' => 0,
			'part_id'   => 1,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$backup_id = (int)$defConfig['backup_id'];
		$part_id   = (int)$defConfig['part_id'];

		$backup_stats = Platform::getInstance()->get_statistics($backup_id);

		if (empty($backup_stats))
		{
			// Backup record doesn't exist
			@ob_end_clean();
			header('HTTP/1.1 500 Invalid backup record identifier');
			flush();

			$this->container->platform->closeApplication();
		}

		$files = Factory::getStatistics()->get_all_filenames($backup_stats);

		if ((($files === null ? 0 : count($files)) < $part_id) || ($part_id <= 0))
		{
			// Invalid part
			@ob_end_clean();
			header('HTTP/1.1 500 Invalid backup part');
			flush();

			$this->container->platform->closeApplication();
		}

		$filename = $files[ $part_id - 1 ];
		@clearstatcache();

		// For a certain unmentionable browser
		if (function_exists('ini_get') && function_exists('ini_set'))
		{
			if (ini_get('zlib.output_compression'))
			{
				ini_set('zlib.output_compression', 'Off');
			}
		}

		// Remove php's time limit
		if (function_exists('ini_get') && function_exists('set_time_limit'))
		{
			if (!ini_get('safe_mode'))
			{
				@set_time_limit(0);
			}
		}

		$basename  = @basename($filename);
		$fileSize  = @filesize($filename);
		$extension = strtolower(str_replace(".", "", strrchr($filename, ".")));

		while (@ob_end_clean())
		{
			;
		}
		@clearstatcache();
		// Send MIME headers
		header('MIME-Version: 1.0');
		header('Content-Disposition: attachment; filename="' . $basename . '"');
		header('Content-Transfer-Encoding: binary');
		header('Accept-Ranges: bytes');

		switch ($extension)
		{
			case 'zip':
				// ZIP MIME type
				header('Content-Type: application/zip');
				break;

			default:
				// Generic binary data MIME type
				header('Content-Type: application/octet-stream');
				break;
		}

		// Notify of file size, if this info is available
		if ($fileSize > 0)
		{
			header('Content-Length: ' . @filesize($filename));
		}

		// Disable caching
		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		header("Expires: 0");
		header('Pragma: no-cache');
		flush();

		if ($fileSize > 0)
		{
			// If the filesize is reported, use 1M chunks for echoing the data to the browser
			$blockSize = 1048576; //1M chunks
			$handle    = @fopen($filename, "r");

			// Now we need to loop through the file and echo out chunks of file data
			if ($handle !== false)
			{
				while (!@feof($handle))
				{
					echo @fread($handle, $blockSize);
					@ob_flush();
					flush();
				}
			}

			if ($handle !== false)
			{
				@fclose($handle);
			}
		}
		else
		{
			// If the filesize is not reported, hope that readfile works
			@readfile($filename);
		}

		flush();

		$this->container->platform->closeApplication();

		// Totally ignored, only added to make static analysis happy
		return null;
	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Backup\Site\Model\Profiles;
use Akeeba\Engine\Factory;

/**
 * Export the profile's configuration
 */
class ExportConfiguration extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile_id = (int)$defConfig['profile'];

		if ($profile_id <= 0)
		{
			$profile_id = 1;
		}

		/** @var Profiles $profile */
		$profile = $this->container->factory->model('Profiles')->tmpInstance();

		$data = $profile->findOrFail($profile_id)->getData();

		if (substr($data['configuration'], 0, 12) == '###AES128###')
		{
			// Load the server key file if necessary
			if (!defined('AKEEBA_SERVERKEY'))
			{
				$filename = JPATH_COMPONENT_ADMINISTRATOR . '/BackupEngine/serverkey.php';

				include_once $filename;
			}

			$key = Factory::getSecureSettings()->getKey();

			$data['configuration'] = Factory::getSecureSettings()->decryptSettings($data['configuration'], $key);
		}

		return array(
			'description'   => $data['description'],
			'configuration' => $data['configuration'],
			'filters'       => $data['filters'],
		);
	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Get information for a given backup record
 */
class GetBackupInfo extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'backup_id' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$backup_id = (int)$defConfig['backup_id'];

		// Get the basic statistics
		$record = Platform::getInstance()->get_statistics($backup_id);

		// Backup record doesn't exist
		if (empty($record))
		{
			throw new \RuntimeException('Invalid backup record identifier', 404);
		}

		// Get a list of filenames
		$filenames = Factory::getStatistics()->get_all_filenames($record);

		if (empty($filenames))
		{
			// Archives are not stored on the server or no files produced
			$record['filenames'] = array();
		}
		else
		{
			$filedata = array();
			$i        = 0;

			// Get file sizes per part
			foreach ($filenames as $file)
			{
				$i++;
				$size       = @filesize($file);
				$size       = is_numeric($size) ? $size : 0;
				$filedata[] = array(
					'part' => $i,
					'name' => basename($file),
					'size' => $size
				);
			}

			// Add the file info to $record['filenames']
			$record['filenames'] = $filedata;
		}

		return $record;
	}
}
<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Filter\InputFilter;

/**
 * Get the database entities along with their filtering status (typically for rendering a GUI)
 *
 * @deprecated
 */
class GetDBEntities extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array  $parameters  The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = [])
	{
		throw new \RuntimeException('This method is no longer supported by the Akeeba Remote JSON API', 501);
	}
}