Your IP : 216.73.216.85


Current Path : /home/smartconb/www/armencom33/plugins/content/gpfirewall/
Upload File :
Current File : /home/smartconb/www/armencom33/plugins/content/gpfirewall/gpfirewall.php

<?php

/**
 * @package     gpfirewall.Plugin
 * @subpackage  Content.gpfirewall
 * @plugin      gpfirewall
 * @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
 */

defined('_JEXEC') or die;

use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Version;


class PlgContentGPfirewall extends CMSPlugin
{
	############# NEVER CHANGE BELOW CODE ###############
	const WAF_V = '1.0.0';
	private $WAF_TOKEN;
	private $WAF_FRONT;
	private $WAF_BACK;
	private $WAF_TOWER;
	private $WAF_HUB;
	private $WAF_CHECKPOINT;
	private $WAF_SIDE;
	private $WAF_POST;
	private $WAF_SESSION;
	private $WAF_CSRF;
	private $WAF_XFRAME;
	private $WAF_HEADERS;
	private $url;
	private $WAF_APP_NAME;
	private $plugin_page;
	private $WAF_AUTOUPDATE;
	private $WAF_update_url;
	private $WAF_update_performed;
	private $WAF_update_backup_created;
	private $WAF_update_tmp_created;
	private $WAF_update_run;
	private $WAF_update_log;
	protected $session;

	function __construct()
	{
		// If called while plugin disabled, exit and unset the calling hook point.
		if (\Joomla\CMS\Plugin\PluginHelper::isEnabled('content', 'gpfirewall') != 1) {
			$this->wafDisable();
			return;
		}

		// Front/Back office side Get/Set
		$app = Joomla\CMS\Factory::getApplication();
		if ($app->getName() == 'administrator') {
			$this->WAF_SIDE = -1;
		} else {
			$this->WAF_SIDE = 1;
		}

		$this->session = \Joomla\CMS\Factory::getSession();

		// Check if plugin is enabled & Get plugin params
		$this->plugin = \Joomla\CMS\Plugin\PluginHelper::getPlugin('content', 'gpfirewall');
		$this->pluginParams = new \Joomla\Registry\Registry($this->plugin->params);
		
		$this->WAF_TOKEN = strip_tags($this->pluginParams->get('WAF_TOKEN'));
		if ($this->isValidToken($this->WAF_TOKEN) === false) {
			$this->WAF_TOKEN = '';
			$this->UpdatedRecord("WAF_TOKEN", null);
		}
		$this->WAF_FRONT = strip_tags($this->pluginParams->get('WAF_FRONT'));
		$this->WAF_BACK = strip_tags($this->pluginParams->get('WAF_BACK'));
		$this->WAF_TOWER = $this->pluginParams->get('WAF_TOWER');
		$this->WAF_HUB = $this->pluginParams->get('WAF_HUB');
		$this->WAF_CSRF = $this->pluginParams->get('WAF_CSRF');
		$this->WAF_XFRAME = $this->pluginParams->get('WAF_XFRAME');
		$this->WAF_POST = $this->pluginParams->get('WAF_POST');
		$this->WAF_SESSION = $this->pluginParams->get('WAF_SESSION');
		$this->WAF_HEADERS = $this->pluginParams->get('WAF_HEADERS');
		$this->WAF_CHECKPOINT = $this->pluginParams->get('WAF_CHECKPOINT');

		$this->WAF_update_url = 'https://hub.geniusplugin.com/pub/joomla_version.php?v=';
		$this->WAF_update_run = false;
		$this->WAF_AUTOUPDATE = true; // Assume auto-update is enabled by default
		$this->WAF_update_performed = false;
		$this->WAF_APP_NAME = 'j';


		// refresh data once per 20mn
		if (!empty($this->WAF_TOKEN) && (empty($this->WAF_HUB) || $this->WAF_CHECKPOINT != date('YmdH') . substr(date('i'), 0, 1))) {
			if (empty($this->WAF_HUB) || (date('YmdH') . substr(date('i'), 0, 1)) % 2 == 0)
				$this->getTower();
			// Check if plugin is enabled & Get plugin params
			$this->plugin = \Joomla\CMS\Plugin\PluginHelper::getPlugin('content', 'gpfirewall'); 
			$this->pluginParams = new \Joomla\Registry\Registry($this->plugin->params);
			$this->WAF_TOKEN = $this->pluginParams->get('WAF_TOKEN');
			$this->WAF_FRONT = $this->pluginParams->get('WAF_FRONT');
			$this->WAF_BACK = $this->pluginParams->get('WAF_BACK');
			$this->WAF_TOWER = $this->pluginParams->get('WAF_TOWER');
			$this->WAF_HUB = $this->pluginParams->get('WAF_HUB');
			$this->WAF_CSRF = $this->pluginParams->get('WAF_CSRF');
			$this->WAF_XFRAME = $this->pluginParams->get('WAF_XFRAME');
			$this->WAF_POST = $this->pluginParams->get('WAF_POST');
			$this->WAF_SESSION = $this->pluginParams->get('WAF_SESSION');
			$this->WAF_HEADERS = $this->pluginParams->get('WAF_HEADERS');
			$this->WAF_CHECKPOINT = $this->pluginParams->get('WAF_CHECKPOINT');
		}

		// Get this plugin id
		$plugid = $this->plugin->id;
		$this->url = Uri::getInstance()->toString();

		// Set the current page is this plugin edit page from backend
		if (strpos($this->url, 'com_plugins&view=plugin&layout=edit&extension_id=' . $plugid) !== false) {
			$this->plugin_page = 1;
		} else {
			$this->plugin_page = 0;
		}

		// Deploy the firewall whatever the token is/Not empty
		$this->header_modify();

		// Set default result of license request
		$wafCheck = -1;
		$isroot = \Joomla\CMS\Factory::getApplication()->isClient('administrator');

		$app = \Joomla\CMS\Factory::getApplication();
		
		// run once the plugin settings view on this plugin backoffice page.
		if ($this->WAF_SIDE == -1 && $this->plugin_page == 1 && $isroot === true) {

			if (!empty($this->WAF_TOKEN)) {
				$wafCheck = json_decode($this->check_license(), true);

				if (is_array($wafCheck) && $wafCheck[0] == 200 && isset($wafCheck[1]) && !empty($wafCheck[1])) {


					// Display first activation welcome message
					if (isset($wafCheck[2]) && !empty($wafCheck[2])) {
						echo '<div id="system-message-container" aria-live="polite"><noscript><div class="alert alert-success">' . $wafCheck[2] . '</div></noscript><joomla-alert type="success" close-text="Close" dismiss="true" role="alert" style="animation-name: joomla-alert-fade-in;"><button type="button" class="joomla-alert--close" aria-label="Close"><span aria-hidden="true">×</span></button><div class="alert-heading"><span class="success"></span><span class="visually-hidden">success</span></div><div class="alert-wrapper"><div class="alert-message">' . $wafCheck[2] . '</div></div></joomla-alert></div>';
					}

					// Notify user if asked for by the plugin.
					if (isset($wafCheck[4]) && $wafCheck[4] == 1) {

						// Notifier once per session and n times remotely
						if (!$this->session->get('WAF_NOTIFIER') || $this->session->get('WAF_NOTIFIER') != date('Ymd')) {
							$this->session->set('WAF_NOTIFIER', date('Ymd'));
							echo '<p>' . $this->notify_user();
						}
					}

					// Get a snapshot map of the current attacks and legitimate visitors
					echo '<div id="ifr"><span style="padding-left:25px">' . $wafCheck[3] . '</span><p>' .  file_get_contents($this->WAF_HUB . '/noc-r.php?app='. $this->WAF_APP_NAME.'&token=' .  $this->WAF_TOKEN) . '</p></div>';
				}
			}

			
			// Display error message on empty token or invalid token
			if (empty($this->WAF_TOKEN) || $wafCheck == -1 || !isset($wafCheck[0]) || $wafCheck[0] != 200) {

				// Disable the firewall
				$this->UpdatedRecord("WAF_FRONT", null);
				$this->UpdatedRecord("WAF_BACK", null);
				$this->WAF_FRONT = null;
				$this->WAF_BACK = null;
				$this->jsValidateForm();
				$systemmessage = 'License token is invalid. Please fill the below field with your GP Firewall token, then clic on the submit button. <a href="https://cloud.geniusplugin.com/order.php?step=1&productGroup=1" target="_blank">Need a free license token?</a>';
				echo '<div id="system-message-container" aria-live="polite"><noscript><div class="alert alert-warning">' . $systemmessage . '</div></noscript><joomla-alert type="warning" close-text="Close" dismiss="true" role="alert" style="animation-name: joomla-alert-fade-in;"><button type="button" class="joomla-alert--close" aria-label="Close"><span aria-hidden="true">×</span></button><div class="alert-heading"><span class="warning"></span><span class="visually-hidden">success</span></div><div class="alert-wrapper"><div class="alert-message">' . $systemmessage . '</div></div></joomla-alert></div>';
				return;
			}
			// Display warning message if silence is the only thing we get from remote server
			if ($wafCheck == NULL) {
				// Disable the firewall
				$this->UpdatedRecord("WAF_FRONT", null);
				$this->UpdatedRecord("WAF_BACK", null);
				$this->WAF_FRONT = null;
				$this->WAF_BACK = null;
				$this->jsValidateForm();
				$systemmessage = 'There was a temporary problem. Please check your token, then try again or contact support.';
				echo '<div id="system-message-container" aria-live="polite"><noscript><div class="alert alert-warning">' . $systemmessage . '</div></noscript><joomla-alert type="warning" close-text="Close" dismiss="true" role="alert" style="animation-name: joomla-alert-fade-in;"><button type="button" class="joomla-alert--close" aria-label="Close"><span aria-hidden="true">×</span></button><div class="alert-heading"><span class="warning"></span><span class="visually-hidden">success</span></div><div class="alert-wrapper"><div class="alert-message">' . $systemmessage . '</div></div></joomla-alert></div>';
				return;
			}
			$this->gp_css_js();
		}
	}

	/**
	 * sanitize the token and remove any potentially harmful content
	 *
	 * @param string $input
	 * @return boolean
	 */
	function isValidToken($input)
	{
		if (strlen($input) > 42) {
			return false;
		}
		$sanitizedInput = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
		if ($sanitizedInput !== $input) {
			return false;
		}
		if (preg_match('/<[^>]*>/', $input)) {
			return false;
		}
		$pattern = '/^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+){0,8}$/';
		return preg_match($pattern, $input) === 1;
	}


	/**
	 * Set/Update this plugin params with no form use
	 *
	 * @param [string] $paramToUpdate
	 * @param [void] $value
	 * @return void
	 */
	private function UpdatedRecord($paramToUpdate, $value)
	{

		$table = \Joomla\CMS\Table\Table::getInstance('extension');

		// Look up extension id
		$id = $table->find(array('element' => 'gpfirewall'));
		if ($id === false) {
			$this->setError($table->getError());
			return false;
		}

		// Load the previous data
		if (!$table->load($id)) {
			$this->setError($table->getError());
			return false;
		}

		// Get the params
		$params = $table->params;
		$params = json_decode($params);
		$params->$paramToUpdate = $value;
		$params = json_encode($params);
		$table->params = $params;

		// Check the data.
		if (!$table->check()) {
			$this->setError($table->getError());
			return false;
		}

		// Store the data.
		if (!$table->store()) {
			$this->setError($table->getError());
			return false;
		}
	}

	/**
	 * Returns the id of this plugin
	 *
	 * @param [string] $name (plugin name)
	 * @param [string] $type (plugin,..)
	 * @param [string] $element (plugin name)
	 * @param [string] $folder (plugin type - content)
	 * @return num|false
	 */
	function getId($name, $type, $element, $folder)
	{
		$db = \Joomla\CMS\Factory::getDBO();
		$query = $db->getQuery(true);
		$query
			->select($db->quoteName('a.extension_id'))
			->from($db->quoteName('#__extensions', 'a'))
			->where($db->quoteName('a.name') . ' = ' . $db->quote($name))
			->where($db->quoteName('a.type') . ' = ' . $db->quote($type))
			->where($db->quoteName('a.element') . ' = ' . $db->quote($element))
			->where($db->quoteName('a.folder') . ' = ' . $db->quote($folder));
		$db->setQuery($query);
		$db->execute();
		if ($db->getNumRows()) {
			return $db->loadResult();
		}
		return false;
	}

	/**
	 * Function to Crypt data
	 *
	 * @param [void] $data
	 * @param [string] $key
	 * @return string
	 */
	function encryptClientData($data, $key)
	{
		$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('AES-256-CBC'));
		$encrypted = openssl_encrypt($data, 'AES-256-CBC', $key, 0, $iv);
		$encoded = base64_encode($encrypted . '::' . $iv);
		return $encoded;
	}

	/**
	 * Get application and plugins name, version, status and slug
	 * @return string
	 */
	function app_version()
	{

		define('_JEXEC', 1);
		define('JPATH_BASE', __DIR__);
		require_once JPATH_BASE . '/includes/defines.php';
		require_once JPATH_BASE . '/includes/framework.php';
		jimport('joomla.version');

		// Get Joomla version
		$jversion = new Version;
		$WAF_APPV['Core'] = $jversion->getShortVersion();

		$db = \Joomla\CMS\Factory::getDBO();
		$query = $db->getQuery(true)
			->select('name, element, type, manifest_cache, enabled')
			->from('#__extensions')
			->where('type IN (' . $db->quote('plugin') . ', ' . $db->quote('component') . ', ' . $db->quote('module') . ')');

		$db->setQuery($query);
		$extensions = $db->loadAssocList();
		foreach ($extensions as $extension) {
			if ($extension['enabled'] == 1) {
				$manifest = json_decode($extension['manifest_cache'], true);
				$WAF_APPV[$extension['name']] = $manifest['version'] . ';' . $extension['element'] . ';' . $extension['type'];
			}
		}
		return json_encode($WAF_APPV);
	}

	/**
	 * Main Firewall header modify and implementation. Changes the header of any page, sends request to tower then allow/deny access to user.
	 * @param int $this->WAF_SIDE
	 * @return void
	 */


	function header_modify()
	{
		$this->session = \Joomla\CMS\Factory::getSession();
		$input = \Joomla\CMS\Factory::getApplication()->input;

		// Exit if no token, tower or disabled side
		if (empty($this->WAF_TOKEN)) return;
		if (empty($this->WAF_TOWER)) return;
		if ($this->WAF_SIDE == 1 && $this->WAF_FRONT != 1) return;
		if ($this->WAF_SIDE == -1 && $this->WAF_BACK != 1) return;

		if ($this->WAF_CHECKPOINT != date('YmdH') . substr(date('i'), 0, 1)) {
			if ((date('YmdH') . substr(date('i'), 0, 1)) % 2 == 0)
				$this->getTower();
		}


		if (isset($this->WAF_XFRAME) && !empty($this->WAF_XFRAME) && $this->WAF_XFRAME != -1) {
			$XFRAME = json_decode(base64_decode($this->WAF_XFRAME), true);
			if (is_array($XFRAME)) {
				foreach ($XFRAME as $key => $value) {
					if ($key === 'X-Powered-By') {
						header_remove('X-Powered-By');
					} elseif ($key === 'Server') {
						header_remove('Server');
					} elseif ($key === 'Hmaxsize') {
						$headerSize = 0;
						foreach ($_SERVER as $name => $value) {
							if (strpos($name, 'HTTP_') === 0) {
								$headerSize += strlen($name) + strlen($value);
							}
						}
						if ($headerSize > $value) {
							exit;
						}
					} else {
						header($key . ": " . $value);
					}
				}
			}
		}


		if ($this->session->get('uniquehash') === true) {
			$this->session->set('uniquehash', false);
			$this->checkHash(json_encode($input->post->getArray()));
			exit;
		}
		$this->session->set('uniquehash', false);


		if (isset($this->WAF_CSRF) && !empty($this->WAF_CSRF) && $this->WAF_CSRF == 1 && $this->WAF_SIDE == 1) {
			
			if ($input->server->get('REQUEST_METHOD') === 'GET' && $input->get->count() > 1 && !$input->get->isEmpty()) {
				$csrfToken = $input->get->get('csrf_token', '');
				$csrfStamp = $input->get->get('csrf_stamp', '');

				if (empty($csrfToken) || empty($csrfStamp) || $csrfToken !== hash('sha256', $this->WAF_TOKEN . $csrfStamp)) {
					die('Invalid request.');
				}
			}

			if ($input->getMethod() === 'POST' && $input->post->count() > 1 && !$input->post->isEmpty()) {
				$csrfToken = $input->post->get('csrf_token');
				$csrfStamp = $input->post->get('csrf_stamp');

				if (empty($csrfToken) || empty($csrfStamp) || $csrfToken != hash('sha256', $this->WAF_TOKEN . $csrfStamp)) {
					die('Invalid request.');
				}
			}

			$csrf_stamp =  substr(microtime(true) * 1000, 0, 13);
			$csrf_token = hash('sha256', $this->WAF_TOKEN . $csrf_stamp);

		?>
			<script>
				document.addEventListener("DOMContentLoaded", function() {
					var forms = document.getElementsByTagName("form");

					for (var i = 0; i < forms.length; i++) {
						var form = forms[i];

						var csrfInput = document.createElement("input");
						csrfInput.setAttribute("type", "hidden");
						csrfInput.setAttribute("name", "csrf_token");
						csrfInput.setAttribute("value", "<?php echo $csrf_token; ?>");
						form.appendChild(csrfInput);

						var csrfInput = document.createElement("input");
						csrfInput.setAttribute("type", "hidden");
						csrfInput.setAttribute("name", "csrf_stamp");
						csrfInput.setAttribute("value", "<?php echo $csrf_stamp; ?>");
						form.appendChild(csrfInput);
					}

					// Get all anchor tags on the page
					var anchorTags = document.getElementsByTagName('a');

					// Loop through each anchor tag
					for (var i = 0; i < anchorTags.length; i++) {
						var href = anchorTags[i].getAttribute('href');
						// Check if the href contains a query parameter
						if (href.indexOf('?') !== -1) {
							// Check if the csrf_token and csrf_stamp variables already exist in the URL
							if (href.indexOf('csrf_token=') === -1 || href.indexOf('csrf_stamp=') === -1) {
								// Add the csrf_token and csrf_stamp variables to the URL
								var updatedHref = href + (href.indexOf('?') === -1 ? '?' : '&');

								if (href.indexOf('csrf_token=') === -1) {
									updatedHref += 'csrf_token=' + '<?php echo $csrf_token; ?>' + '&';
								}

								if (href.indexOf('csrf_stamp=') === -1) {
									updatedHref += 'csrf_stamp=' + '<?php echo $csrf_stamp; ?>';
								}

								// Update the href attribute with the modified URL
								anchorTags[i].setAttribute('href', updatedHref);
							}
						}
					}

				});
			</script>
		<?php
		}

		$test_ip = '';
		$agent = '';


		$user_ip = $_SERVER['REMOTE_ADDR'];
		$server_ip = (isset($_SERVER['SERVER_ADDR'])) ? $_SERVER['SERVER_ADDR'] : '';

		if (isset($_SERVER['HTTP_Forwarded-For']) && !empty($_SERVER['HTTP_Forwarded-For'])) {
			$_SERVER['HTTP_Forwarded-For'] = trim(current(explode(',', $_SERVER['HTTP_Forwarded-For'])));
			if (filter_var($_SERVER['HTTP_Forwarded-For'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
				$user_ip = $_SERVER['HTTP_Forwarded-For'];
			}
		}

		if (isset($_SERVER['HTTP_X-Client-IP']) && !empty($_SERVER['HTTP_X-Client-IP'])) {
			$_SERVER['HTTP_X-Client-IP'] = trim(current(explode(',', $_SERVER['HTTP_X-Client-IP'])));
			if (filter_var($_SERVER['HTTP_X-Client-IP'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
				$user_ip = $_SERVER['HTTP_X-Client-IP'];
			}
		}

		if (isset($_SERVER['HTTP_X-Cluster-Client-Ip']) && !empty($_SERVER['HTTP_X-Cluster-Client-Ip'])) {
			$_SERVER['HTTP_X-Cluster-Client-Ip'] = trim(current(explode(',', $_SERVER['HTTP_X-Cluster-Client-Ip'])));
			if (filter_var($_SERVER['HTTP_X-Cluster-Client-Ip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
				$user_ip = $_SERVER['HTTP_X-Cluster-Client-Ip'];
			}
		}

		if (isset($_SERVER['HTTP_Client-IP']) && !empty($_SERVER['HTTP_Client-IP'])) {
			$_SERVER['HTTP_Client-IP'] = trim(current(explode(',', $_SERVER['HTTP_Client-IP'])));
			if (filter_var($_SERVER['HTTP_Client-IP'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
				$user_ip = $_SERVER['HTTP_Client-IP'];
			}
		}

		if (isset($_SERVER['HTTP_CF_CONNECTING_IP']) && !empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
			$_SERVER['HTTP_CF_CONNECTING_IP'] = trim(current(explode(',', $_SERVER['HTTP_CF_CONNECTING_IP'])));
			if (filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
				$user_ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
			}
		}

		if (isset($_SERVER['HTTP_X_REAL_IP']) && !empty($_SERVER['HTTP_X_REAL_IP'])) {
			$_SERVER['HTTP_X_REAL_IP'] = trim(current(explode(',', $_SERVER['HTTP_X_REAL_IP'])));
			if (filter_var($_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
				$user_ip = $_SERVER['HTTP_X_REAL_IP'];
			}
		}

		if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
			$_SERVER['HTTP_X_FORWARDED_FOR'] = trim(current(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])));
			if (filter_var($_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
				$user_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
			}
		}
		if ($user_ip == $server_ip || $user_ip == '::1' || $user_ip == '127.0.0.1' || $user_ip == $_SERVER['SERVER_ADDR']  || empty($user_ip)) {
			return;
		}

		// Check if the 'ip' parameter is set and not empty
		if ($input->get('ip', '', 'STRING') !== '') {
			$test_ip = $input->get('ip', '', 'STRING');
		}

		$protocol = 'http';
		if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 443) $protocol = 'https';
		if (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) $protocol = 'https';
		if (isset($_SERVER['HTTP_X_FORWARDED_PORT']) && $_SERVER['HTTP_X_FORWARDED_PORT'] == 443) $protocol = 'https';
		if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') $protocol = 'https';
		$page = $protocol . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
		if (isset($_SERVER['HTTP_USER_AGENT'])) {
			$agent = base64_encode($_SERVER['HTTP_USER_AGENT']);
		}
		if ($this->WAF_POST == 1) {
			$filteredPost = $input->post->getArray();
			/*
			$dismissedKeys = ['key1', 'key2', 'key3'];
			foreach ($dismissedKeys as $dismissedKey) {
				unset($filteredPost[$dismissedKey]);
			}
			*/
			$sendrequests =  $this->encryptClientData(base64_encode(json_encode($filteredPost)), $this->WAF_TOKEN);
		} else {
			$sendrequests = '';
		}
		if ($this->WAF_SESSION == 1) {
			setcookie('session_cookie', 'value', ['expires' => time() + 3600, 'path' => '/', 'domain' => '', 'secure' => true, 'httponly' => true, 'samesite' => 'Lax']);
			$sessionid =  base64_encode(session_id());
		} else {
			$sessionid = '';
		}
		if ($this->WAF_HEADERS == 1) {
			$filteredServer = getallheaders();
			/*
			$dismissedHeaders = ['HTTP_USER_AGENT', 'HTTP_REFERER'];
			foreach ($dismissedHeaders as $dismissedHeader) {
				unset($filteredServer[$dismissedHeader]);
			}
			*/
			$waf_headers = $this->encryptClientData(base64_encode(json_encode($filteredServer)), $this->WAF_TOKEN);
		} else {
			$waf_headers = '';
		}

		$data = array(
			'token' => $this->WAF_TOKEN,
			'ip' => $user_ip,
			'side' => $this->WAF_SIDE,
			'tip' => $test_ip,
			'ag' => $agent,
			'page' => base64_encode($page),
			'requests' => $sendrequests,
			'session' => $sessionid,
			'headers' => $waf_headers,
			'wafapp' => $this->app_version()
		);

		$url =  $this->WAF_TOWER . '?app='. $this->WAF_APP_NAME.'&v=' . self::WAF_V . '&token=' . $this->WAF_TOKEN;
		$responseText = $this->postData($url, $data);
		if ($this->WAF_update_run === true) {
			try {
				$this->waf_CheckForUpdates(); // Trigger the update check
				//print_r($this->WAF_update_log); // Error Logs for support
			} catch (Exception $e) {
				// No error message displayed for security reasons.
			}
		}

		if (!empty($responseText)) {

			$response = $responseText;
			// Send email if user asked for alert on denied access
			if (strpos($responseText, '-WAFMAIL-') !== false) {
				$response = explode('-WAFMAIL-', $responseText)[0];
				$mailer = explode('-WAFMAIL-', $responseText)[1];
				$mailer = json_decode(base64_decode($mailer));
				mail($mailer[0], $mailer[1], $mailer[2]);
			}
			// Refresh servers on demand
			if (strpos($responseText, '-WAFREDIRECT-') !== false) {
				$response = explode('-WAFREDIRECT-', $responseText)[0];
				$this->getTower();
			}
			// Deny access to the page
			if ($response == 'deny') {
				exit;
			} elseif ($response == '501') {
				// Disable the firewall
				$this->UpdatedRecord("WAF_FRONT", null);
				$this->UpdatedRecord("WAF_BACK", null);
				return;
			} else {
				// Process firewall options
				if (strpos($response, 'uniquehash') !== false) {
					$this->session->set('uniquehash', true);
				}
				echo $response;
				exit;
			}
		}
	}


	private function checkHash($hashes)
	{
		$url = $this->WAF_TOWER . '?app='. $this->WAF_APP_NAME.'&v=' . self::WAF_V;
		$data['hashes'] = $hashes;
		$responseText = $this->postData($url, $data);
		if (!empty($responseText)) {
			echo $responseText;
			exit;
		}
		return;
	}

	/*
	* Output informations on dashboard top; hits limit notification here
	* @return void
	* 
	*/
	function notify_user($dashboard = 0)
	{
		$ch =  curl_init($this->WAF_HUB . '/license.php?v=' . self::WAF_V . '&app='. $this->WAF_APP_NAME.'&section=' . $dashboard . '&action=pluginboard&token=' . $this->WAF_TOKEN);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
		curl_setopt($ch, CURLOPT_TIMEOUT, 3);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
		curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
		curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
		$check_result = curl_exec($ch);
		curl_close($ch);
		if (!empty($check_result)) {
			return base64_decode($check_result);
		}
	}

	function wafDisable()
	{
		$callin_firewall_admin = 'if(!class_exists("PlgContentGPfirewall")){include_once ("../plugins/content/gpfirewall/gpfirewall.php");new PlgContentGPfirewall();}//GPNOHOOKS';
		file_put_contents(JPATH_ADMINISTRATOR . "/includes/app.php", str_replace($callin_firewall_admin, "\r\n", file_get_contents(JPATH_ADMINISTRATOR . "/includes/app.php")));

		$callin_firewall = 'if(!class_exists("PlgContentGPfirewall")){include_once (JPATH_BASE . "/plugins/content/gpfirewall/gpfirewall.php");new PlgContentGPfirewall();}//GPNOHOOKS';
		file_put_contents(JPATH_BASE . "/includes/app.php", str_replace($callin_firewall, "\r\n", file_get_contents(JPATH_BASE . "/includes/app.php")));
	}

	// Add protection to any page witout a hook
	function hooksPoints()
	{
		$callin_firewall_admin = PHP_EOL . 'if(!class_exists("PlgContentGPfirewall")){include_once ("../plugins/content/gpfirewall/gpfirewall.php");new PlgContentGPfirewall();}//GPNOHOOKS' . PHP_EOL . '$app->execute();';
		if (strpos(file_get_contents(JPATH_ADMINISTRATOR . "/includes/app.php"), 'GPNOHOOKS') === false) {
			file_put_contents(JPATH_ADMINISTRATOR . "/includes/app.php", str_replace('$app->execute();', "\r\n" . $callin_firewall_admin, file_get_contents(JPATH_ADMINISTRATOR . "/includes/app.php")));
		}
		$callin_firewall = PHP_EOL . 'if(!class_exists("PlgContentGPfirewall")){include_once (JPATH_BASE . "/plugins/content/gpfirewall/gpfirewall.php");new PlgContentGPfirewall();}//GPNOHOOKS' . PHP_EOL . '$app->execute();';
		if (strpos(file_get_contents(JPATH_BASE . "/includes/app.php"), 'GPNOHOOKS') === false) {
			file_put_contents(JPATH_BASE . "/includes/app.php", str_replace('$app->execute();', "\r\n" . $callin_firewall, file_get_contents(JPATH_BASE . "/includes/app.php")));
		}
	}

	/*
    * Get (new) tower and/or (new) dashboard set for the license. 
    * @return void
    * 
    */
	function getTower()
	{
		$this->session = \Joomla\CMS\Factory::getSession();
		$this->hooksPoints();
		$ch =  curl_init('https://hub.geniusplugin.com/license.php?v=' . self::WAF_V . '&app='. $this->WAF_APP_NAME.'&action=gettower&token=' . $this->WAF_TOKEN);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
		curl_setopt($ch, CURLOPT_TIMEOUT, 3);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
		curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
		curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
		$result = curl_exec($ch);
		curl_close($ch);
		if (!empty($result)) {
			$server = json_decode($result);
			if (is_array($server)) {
				$this->WAF_TOWER = $server[0];
				$this->WAF_HUB = $server[1];
				$this->WAF_CSRF = $server[3];
				$this->WAF_XFRAME = $server[4];
				$this->WAF_POST = $server[5];
				$this->WAF_SESSION = $server[6];
				$this->WAF_HEADERS = $server[7];
				$this->UpdatedRecord("WAF_TOWER", $this->WAF_TOWER);
				$this->UpdatedRecord("WAF_HUB", $this->WAF_HUB);
				$this->UpdatedRecord("WAF_CSRF", $this->WAF_CSRF);
				$this->UpdatedRecord("WAF_XFRAME", $this->WAF_XFRAME);
				$this->UpdatedRecord("WAF_POST", $this->WAF_POST);
				$this->UpdatedRecord("WAF_SESSION", $this->WAF_SESSION);
				$this->UpdatedRecord("WAF_HEADERS", $this->WAF_HEADERS);
				if (isset($server[8]) && strpos($server[8], '-WAFMAIL-') === 0) {
					$mailer = explode('-WAFMAIL-', $server[8])[1];
					$mailer = json_decode(base64_decode($mailer));
					mail($mailer[0], $mailer[1], $mailer[2]);
				}

				if (isset($server[9]) && $server[9] === '-WAFUPDATE-') {
					$this->session->set('WAF_AUTOUPDATE', true);

					// Trigger the update check waf_CheckForUpdates();  
					$this->WAF_update_run = true;
				} else {
					$this->session->set('WAF_AUTOUPDATE', false);
				}
			}
		}
		$this->UpdatedRecord("WAF_CHECKPOINT", date('YmdH') . substr(date('i'), 0, 1));
	}

	/**
	 * Automatic license check
	 * @return string
	 */
	function check_license()
	{

		$ch =  curl_init($this->WAF_HUB . '/license.php?v=' . self::WAF_V . '&app='. $this->WAF_APP_NAME.'&action=licensecheck&token=' . $this->WAF_TOKEN);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
		curl_setopt($ch, CURLOPT_TIMEOUT, 3);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
		curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
		curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
		$check_result = curl_exec($ch);
		curl_close($ch);
		return $check_result;
	}

	function jsValidateForm()
	{
		echo "
		<script>
		document.addEventListener('DOMContentLoaded', function() {
		frontside = '" . $this->WAF_FRONT . "';
		backside = '" . $this->WAF_BACK . "';
		if(frontside != 1) { document.getElementById('jform_params_WAF_FRONT').checked = false;}
		if(backside != 1) {document.getElementById('jform_params_WAF_BACK').checked = false;}});</script>
		";
	}

	/**
	 * Add css and js
	 *
	 * @return void
	 */
	function gp_css_js()
	{
		$style = "
				.waf-live {
					display: inline-block;
					vertical-align: top;
					box-sizing: border-box;
					margin: 1px 10px -1px 2px;
					padding: 0 5px;
					min-width: 18px;
					height: 18px;
					border-radius: 3px;
					background-color: #e82910;
					color: #fff;
					font-size: 11px;
					line-height: 1.6;
					text-align: center;
					float: right;
				}

				a[target=_blank]:before {
					content: '';
				}
			";

		$document = \Joomla\CMS\Factory::getDocument();
		$document->addStyleDeclaration($style);
		$script = "
				document.addEventListener('DOMContentLoaded', function() {
					oldTab = document.getElementById('general').innerHTML;
					var myAnchor = document.getElementById('general');
					var mySpan = document.getElementById('ifr');
					mySpan.innerHTML += '<div class=\"container-fluid\">' + oldTab + '</div>';
					myAnchor.parentNode.replaceChild(mySpan, myAnchor);
					document.getElementById('jform_params_WAF_TOKEN').readOnly = true;
				}, false);
				 var existingElement = document.getElementById('ifr');
    			if (existingElement) {
       			 existingElement.parentNode.removeChild(existingElement);
   				 }
				";
		$document->addScriptDeclaration($script);
	}


	private function waf_CheckForUpdates()
	{
		$this->session = \Joomla\CMS\Factory::getSession();
		$check_update_core_functions = $this->waf_checkRequiredCoreFunctions();
		if ($check_update_core_functions === null) {
			return;
		}

		if ($this->WAF_update_performed) {
			$this->WAF_update_log .= ' Update was already performed';
			return; // Skip update check if an update was already performed
		}

		// Check if an update has been performed in this session
		if ($this->session->get('update_performed') === true) {
			$this->WAF_update_log .= ' Update was already performed in this session';
			return; // Skip update check if an update was already performed
		}

		// Fetch the version information from the server
		$versionInfo = $this->waf_fetchVersionInfo();

		// Check if version information is available
		if (!$versionInfo) {
			$this->WAF_update_log .= ' Version information is not available';
			return;
		}

		// Check if an update is required
		if ($this->waf_isUpdateRequired($versionInfo)) {
			// Perform the update process
			$this->waf_performUpdate($versionInfo);
		}
	}

	private function waf_fetchVersionInfo()
	{
		// Attempt to fetch version information using file_get_contents
		$versionInfoJson = $this->waf_fetchData($this->WAF_update_url . self::WAF_V . '&app=' . $this->WAF_APP_NAME);
		if ($versionInfoJson === false) {
			$this->WAF_update_log .= ' Fetch version information using file_get_contents failed';
			return false;
		}


		// Decode the fetched JSON version information
		$versionInfo = json_decode($versionInfoJson, true);

		// Check if the version information is valid
		if (!is_array($versionInfo) || !isset($versionInfo['new_version'], $versionInfo['download_uri'], $versionInfo['sha256'], $versionInfo['auto_update'], $versionInfo['min_php_version'], $versionInfo['min_script_version'])) {
			$this->WAF_update_log .= ' Version information invalid';
			return false;
		}
		if (
			empty($versionInfo['new_version']) || empty($versionInfo['download_uri']) || empty($versionInfo['sha256']) || empty($versionInfo['auto_update']) || empty($versionInfo['min_php_version']) || empty($versionInfo['min_script_version'])
		) {
			$this->WAF_update_log .= ' Version information invalid';
			return false;
		}
		return $versionInfo;
	}

	private function waf_isUpdateRequired($versionInfo)
	{

		// Check if auto-update is enabled
		if ($versionInfo['auto_update'] !== 1) {
			$this->WAF_update_log .= ' Auto-update is disabled';
			return false;
		}

		// Check if current PHP version meets the minimum required version
		if (version_compare(PHP_VERSION, $versionInfo['min_php_version'], '<')) {
			$this->WAF_update_log .= ' PHP version does not meet the minimum required version';
			return false;
		}

		// Check if current script meets the minimum required version for upgrade
		if (version_compare(self::WAF_V, $versionInfo['min_script_version'], '<')) {
			$this->WAF_update_log .= ' Script version does not meet the minimum required version';
			return false;
		}

		// Check if current script version is older than the new version
		if (version_compare(
			$versionInfo['new_version'],
			self::WAF_V,
			'<'
		)) {
			$this->WAF_update_log .= ' New version is not greater than current version';
			return false;
		}

		// Check if an autoupdate is set by user
		if ($this->WAF_AUTOUPDATE !== true) {
			$this->WAF_update_log .= ' Autoupdate is disabled';
			return false;
		}

		// Verify SHA256
		return  $this->waf_verifySha256($versionInfo['download_uri'], $versionInfo['sha256']);
	}

	private function waf_performUpdate($versionInfo)
	{
		$this->session = \Joomla\CMS\Factory::getSession();
		// Download the updated zip file
		$updatedZip = @file_get_contents($versionInfo['download_uri']);

		if ($updatedZip === false) {
			// file_get_contents function alternative
			// Download the updated zip file using cURL
			$updatedZip = $this->waf_downloadWithCurl($versionInfo['download_uri']);
			if (!$updatedZip) {
				$this->WAF_update_log .= ' Download the updated zip file failed';
				return;
			}
		}


		// Create a backup directory and copy all files and folders for non-universal plugin
		$backupDir = __DIR__ . '/backup_';
		$this->waf_removeDirectory($backupDir);
		if ($this->WAF_APP_NAME != 'n') {
			if ($this->WAF_update_backup_created !== true) {
				if (@mkdir($backupDir)) {
					// Backup directory created successfully
					$this->WAF_update_backup_created = true;

					// Copy all files and folders
					if ($this->waf_copyDirectoryContents(__DIR__, $backupDir) !== true) {
						return;
					}
				} elseif (@is_dir($backupDir)) {
					// Backup directory created successfully
					$this->WAF_update_backup_created = true;

					// Copy all files and folders
					if ($this->waf_copyDirectoryContents(__DIR__, $backupDir) !== true) {
						return;
					}
				} else {
					// Failed to create backup directory
					$this->WAF_update_log .= ' Failed to create backup directory';
					return;
				}
			}
		}


		$tempDir = __DIR__ . '/temp_';
		$this->waf_removeDirectory($tempDir);
		// Create a temporary directory for extraction
		if ($this->WAF_update_tmp_created !== true) {
			if (@mkdir($tempDir)) {
				// Temporary directory created successfully
				$this->WAF_update_tmp_created = true;

				// Attempt to extract the updated files using PHP's ZipArchive
				$extracted = $this->waf_extractZipWithPHP($updatedZip, $tempDir, $versionInfo);

				// If extraction using PHP fails, try using PclZip
				if (!$extracted) {
					$extracted = $this->waf_extractZipWithPclZip($updatedZip, $tempDir, $versionInfo);
					if (!$extracted) {
						$this->WAF_update_log .= ' Failed to extract the zip file';
						return;
					}
				}
			} elseif (@is_dir($backupDir)) {
				// Temporary directory created successfully
				$this->WAF_update_tmp_created = true;

				// Attempt to extract the updated files using PHP's ZipArchive
				$extracted = $this->waf_extractZipWithPHP($updatedZip, $tempDir, $versionInfo);

				// If extraction using PHP fails, try using PclZip
				if (!$extracted) {
					$extracted = $this->waf_extractZipWithPclZip($updatedZip, $tempDir, $versionInfo);
					if (!$extracted) {
						$this->WAF_update_log .= ' Failed to extract the zip file';
						return;
					}
				}
			} else {
				// Failed to create temporary directory
				$this->WAF_update_log .= ' Failed to create temporary directory';
				return;
			}
		}

		// Copy the updated files to the main directory
		if ($this->waf_copyDirectoryContents($tempDir, __DIR__) !== true) {
			return;
		}
		$this->waf_removeDirectory($tempDir); // Remove the temporary directory

		// If a backup directory exists, restore files from backup for non-universal plugin
		if ($this->WAF_APP_NAME != 'n') {
			if (file_exists($backupDir)) {
				if (!$this->session->get('update_performed') || $this->session->get('update_performed') !== true) {
					$this->waf_copyDirectoryContents($backupDir, __DIR__); // Restore from backup
				}

				$this->waf_removeDirectory($backupDir); // Remove the backup directory
			}
		}
		@unlink(__DIR__ . '/update.' . $versionInfo['new_version'] . '.zip'); // remove the zip file
		$this->WAF_update_performed = false;
		
		$this->session->clear('update_performed');
	}

	private function waf_copyDirectoryContents($source,$destination) {
		$this->session = \Joomla\CMS\Factory::getSession();
		// Copy all files and folders from source to destination
		$dir = opendir($source);
		// Check if the destination directory is writable
		if (!is_writable($destination)) {
			$this->WAF_update_log .=  " Destination directory is not writable: $destination";
			return false;
		}

		while (($file = readdir($dir)) !== false) {
			if ($file != '.' && $file != '..') {
				$src = $source . '/' . $file;
				$dst = $destination . '/' . $file;

				// Skip copying the backup directory
				if (@is_dir($src) && strpos($file, 'backup_') === 0) {
					continue; // Skip copying backup_ folders
				}
				// Skip copying hidden directories
				if (
					@is_dir($src) && substr($file, 0, 1) === '.'
				) {
					continue; // Skip copying hidden directories
				}

				if (@is_dir($src)) {
					if (!@mkdir($dst) && !@is_dir($dst)) {
						$this->WAF_update_log .=  " Failed to create directory: $dst";
						return false;
					}
					$this->waf_copyDirectoryContents($src, $dst);
				} else {
					if (!@copy($src, $dst)) {
						$this->WAF_update_log .=  " Failed to copy file: $src to $dst";
						return false;
					}
				}
			}
		}

		closedir($dir);
		if (strpos($source, 'temp_') !== false) {
			//After performing the update set the flag to true
			$this->WAF_update_performed = true;
			$this->session->set('update_performed', true);

		}
		return true;
	}

	private function waf_extractZipWithPHP($zipData, $destination, $versionInfo)
	{
		// Create a unique zip file name based on the version
		$zipFileName = $destination . '/update.' . $versionInfo['new_version'] . '.zip';

		// Attempt to use file_put_contents to save the zip file
		if (!file_put_contents($zipFileName, $zipData)) {
			// If file_put_contents fails, use an alternative method (downloadWithCurl)
			$downloadedZip = $this->waf_downloadWithCurl($versionInfo['download_uri']);
			if ($downloadedZip !== false) {
				// Attempt to save the downloaded zip data using fopen, fwrite, and fclose
				$zipFileHandle = fopen($zipFileName, 'w');
				if ($zipFileHandle !== false) {
					fwrite($zipFileHandle, $downloadedZip);
					fclose($zipFileHandle);
				}
			}
		}

		// Use PHP's ZipArchive to extract the files
		$zip = new ZipArchive();

		if ($zip->open($zipFileName) === true) {
			$zip->extractTo($destination);
			$zip->close();
			return true;
		} else {
			$this->WAF_update_log .= ' Failed to extract the zip file';
			return false;
		}
	}

	private function waf_fetchData($url)
	{
		// Use cURL or file_get_contents to fetch data from a URL
		if (function_exists('curl_init')) {
			$ch = curl_init($url);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
			curl_setopt($ch, CURLOPT_TIMEOUT, 3);
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
			curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
			curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
			$data = curl_exec($ch);

			if (curl_errno($ch)) {
				if (function_exists('file_get_contents')) {
					return @file_get_contents($url);
				} else {
					$this->WAF_update_log .= ' Failed to fetch data from a URL 1';
					return false;
				}
			}
			curl_close($ch);
			return $data;
		} elseif (function_exists('file_get_contents')) {
			return @file_get_contents($url);
		} else {
			$this->WAF_update_log .= ' Failed to fetch data from a URL 2';
			return false;
		}
	}

	private function waf_downloadWithCurl($url)
	{
		// Download data using cURL
		$ch = curl_init($url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
		curl_setopt($ch, CURLOPT_TIMEOUT, 3);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
		curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
		$data = curl_exec($ch);

		if (curl_errno($ch)) {
			$this->WAF_update_log .= ' Failed to download data with curl';
			return false;
		}

		curl_close($ch);
		return $data;
	}

	private function waf_extractZipWithPclZip($zipData,$destination,$versionInfo) {
		require_once 'pclzip.php';  // Include the PclZip library
		// Create a unique zip file name based on the version
		$zipFileName = $destination . '/update.' . $versionInfo['new_version'] . '.zip';
		// Need file_put_contents function alternative
		file_put_contents($zipFileName, $zipData);

		// Use PclZip library to extract the files
		$zip = new PclZip($zipFileName);
		$extractionResult = $zip->extract(PCLZIP_OPT_PATH, $destination);

		if ($extractionResult === 0) {
			$this->WAF_update_log .= ' Failed to Use PclZip library to extract the files';
			return false;
		}

		return true;
	}

	private function waf_removeDirectory($path)
	{
		// Remove a directory and its contents
		if (@is_dir($path)) {
			$objects = @scandir($path);

			foreach ($objects as $object) {
				if ($object != '.' && $object != '..') {
					if (@is_dir($path . '/' . $object)) {
						$this->waf_removeDirectory($path . '/' . $object);
					} else {
						@unlink($path . '/' . $object);
					}
				}
			}

			@rmdir($path);
		}
	}


	private function waf_verifySha256($fileUri, $expectedSha256)
	{

		$downloadedFile = @file_get_contents($fileUri);

		if ($downloadedFile === false) {
			// file_get_contents function alternative
			$downloadedFile = $this->waf_downloadWithCurl($fileUri);
			if ($downloadedFile === false) {
				$this->WAF_update_log .= ' Failed to download with curl the zip file';
				return false;
			}
		}

		// Calculate SHA256 hash and compare
		$calculatedSha256 = hash('sha256', $downloadedFile);

		if ($calculatedSha256 !== $expectedSha256) {
			$this->WAF_update_log .= ' Failed zip file checksum verification';
		}
		return $calculatedSha256 === $expectedSha256;
	}

	private function waf_checkRequiredCoreFunctions()
	{
		$requiredFunctions = array('rmdir', 'scandir', 'file_put_contents', 'mkdir', 'unlink', 'copy', 'is_dir');

		foreach ($requiredFunctions as $function) {
			if (!function_exists($function)) {
				return null;
			}
		}

		return true; // All required functions are available
	}

	private function postData($url, $data)
	{
		if (function_exists('curl_init')) {
			// Use cURL if available
			$ch = curl_init($url);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
			curl_setopt($ch, CURLOPT_TIMEOUT, 3);
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
			curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
			curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
			curl_setopt($ch, CURLOPT_POST, true);
			curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

			$response = curl_exec($ch);
			$error = curl_error($ch);

			curl_close($ch);

			if ($error) {
				return false;
			}

			return $response;
		} elseif (function_exists('stream_context_create')) {
			// Use file_get_contents with stream context if available
			$options = [
				'http' => [
					'method' => 'POST',
					'header' => 'Content-type: application/x-www-form-urlencoded',
					'content' => http_build_query($data),
				],
			];

			$context = stream_context_create($options);
			$response = @file_get_contents($url, false, $context);

			if ($response === false) {
				return false;
			}

			return $response;
		} else {
			// Neither is available
			return false;
		}
	}
}