<?php
/**
 * @package   admintoolswp
 * @copyright Copyright (c)2017-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU GPL version 3 or later
 */

defined('ADMINTOOLSINC') or die;

use Akeeba\AdminTools\Admin\Helper\Language;
use Akeeba\AdminTools\Admin\Helper\Wordpress;

class AtsystemFeatureCriticalfilesmonitoring extends AtsystemFeatureAbstract
{
	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		return $this->cparams->getValue('criticalfiles', 0) == 1;
	}

	/**
	 * Run the check on every request
	 */
	public function onWordPressInit()
	{
		$mustSaveData = false;

		$criticalFiles = $this->getCriticalFiles();
		$loadedFiles   = $this->cparams->getValue('criticalfiles_data', []);
		$alteredFiles  = [];
		$filesToSave   = [];

		if (is_object($loadedFiles))
		{
			$loadedFiles = (array) $loadedFiles;
		}
		elseif (!is_array($loadedFiles))
		{
			$loadedFiles = [];
		}

		$loadedFiles = array_map(fn($x) => (array) $x, $loadedFiles);

		foreach ($criticalFiles ?: [] as $relPath)
		{
			$curInfo = $this->getFileInfo($relPath);

			if ($curInfo == null)
			{
				// Did that file exist? If so, we need to save the critical files list.
				if (is_array($loadedFiles) && array_key_exists($relPath, $loadedFiles))
				{
					$mustSaveData = true;
				}

				continue;
			}

			$filesToSave[$relPath] = $curInfo;

			// Did the file change?
			$oldInfo = $loadedFiles[$relPath] ?? [];

			if ($oldInfo !== $curInfo)
			{
				$mustSaveData = true;

				if (isset($loadedFiles[$relPath]))
				{
					$alteredFiles[$relPath] = [$oldInfo, $curInfo];
				}
			}
		}

		if ($mustSaveData)
		{
			$this->cparams->setValue('criticalfiles_data', $filesToSave, true);
		}

		// Send out the email only if we have some altered files AND we have some previous data (otherwise we will scare
		// the user as soon as they enable the feature)
		if (!empty($alteredFiles) && !empty($loadedFiles))
		{
			$this->sendEmail($alteredFiles);
		}
	}

	/**
	 * Get the critical files: index.php and all the wp-*.php file in WordPress' root, and the wp-admin/index.php file.
	 *
	 * @return  array  The list of critical files (relative paths)
	 */
	protected function getCriticalFiles()
	{
		$root = ABSPATH;
		$criticalFiles = [
			'index.php',
			'wp-admin/index.php',
		];

		$wpFiles = glob($root . 'wp-*.php');

		if ($wpFiles)
		{
			foreach ($wpFiles as $file)
			{
				$relPath = basename($file);

				if ($relPath == 'index.php') {
					continue;
				}

				$criticalFiles[] = $relPath;
			}
		}

		return array_unique($criticalFiles);
	}

	/**
	 * Returns information about a file
	 *
	 * @param   string  $relPath  The path to the file relative to the site's root
	 *
	 * @return  null|array  Null if the file is not there, object with information otherwise
	 */
	protected function getFileInfo($relPath)
	{
		$absolutePath = ABSPATH . $relPath;

		if (!file_exists($absolutePath) || !is_file($absolutePath) || !is_readable($absolutePath))
		{
			return null;
		}

		return [
			'size'      => @filesize($absolutePath),
			'timestamp' => @filemtime($absolutePath),
			'md5'       => @hash_file('md5', $absolutePath),
			'sha1'      => @hash_file('sha1', $absolutePath),
		];
	}

	/**
	 * Sends a warning email
	 *
	 * @param   array  $alteredFiles  The files which were modified
	 *
	 * @return  void
	 */
	private function sendEmail($alteredFiles)
	{
		if (empty($alteredFiles))
		{
			return;
		}

		$plainTextInfo = implode(
			"\n", array_map(
			function ($line) {
				return "* $line";
			}, array_keys($alteredFiles)
		)
		);

		$email = $this->cparams->getValue('criticalfiles_email', '');

		if (empty($email))
		{
			$email = $this->cparams->getValue('emailafteripautoban', '');
		}

		$recipients = [];

		if (empty($email))
		{
			// Get all active admins
			$admins = get_users(['role' => 'administrator']);
			foreach ($admins as $admin)
			{
				$recipients[] = $admin->user_email;
			}
		}
		else
		{
			$recipients = explode(',', $email);
		}

		$recipients = array_map('trim', $recipients);
		$recipients = array_unique(array_filter($recipients));

		if (empty($recipients))
		{
			return;
		}

		$subjectTemplate = Language::_('COM_ADMINTOOLS_LBL_CRITICALFILES_EMAIL_SUBJECT');
		$bodyTemplate    = Language::_('COM_ADMINTOOLS_LBL_CRITICALFILES_EMAIL_BODY');

		$sitename = get_option('blogname');

		$subject = str_replace('[SITENAME]', $sitename, $subjectTemplate);
		$body    = str_replace('[SITENAME]', $sitename, $bodyTemplate);
		$body    = str_replace('[INFO]', $plainTextInfo, $body);
		$body    = str_replace('\n', "\n", $body);

		Wordpress::sendEmail($recipients, $subject, $body, true, false);
	}
}
