<?php
defined("ABSPATH") or die("");

/**
 * Class for server type enum setup
 * .htaccess, web.config and .user.ini
 *
 */
abstract class DUPX_ServerConfigTypes
{
    const Apache		= 0;
    const IIS			= 1;
    const WordFence     = 2;
}


/**
 * Class used to update and edit web server configuration files
 * for .htaccess, web.config and .user.ini
 *
 * Standard: PSR-2
 * @link http://www.php-fig.org/psr/psr-2 Full Documentation
 *
 */
class DUPX_ServerConfig
{
	protected static $fileHash;
	protected static $timeStamp;
	protected static $confFileApache;
	protected static $confFileApacheOrig;
	protected static $confFileIIS;
	protected static $confFileIISOrig;
	protected static $confFileWordFence;
	protected static $configMode;
	protected static $newSiteURL;
	protected static $rootPath;

	/**
	 *  Setup this classes properties
	 */
	public static function init()
	{
		self::$fileHash				= date("ymdHis") . '-' . uniqid();
		self::$timeStamp			= date("Y-m-d H:i:s");
		self::$rootPath				= "{$GLOBALS['DUPX_ROOT']}";
		self::$confFileApache		= "{$GLOBALS['DUPX_ROOT']}/.htaccess";
		self::$confFileApacheOrig	= "{$GLOBALS['DUPX_ROOT']}/htaccess.orig";
		self::$confFileIIS			= "{$GLOBALS['DUPX_ROOT']}/web.config";
		self::$confFileIISOrig		= "{$GLOBALS['DUPX_ROOT']}/web.config.orig";
		self::$confFileWordFence	= "{$GLOBALS['DUPX_ROOT']}/.user.ini";
		self::$configMode           = isset($_POST['config_mode']) ? DUPX_U::sanitize_text_field($_POST['config_mode'])  : null;
		self::$newSiteURL           = isset($_POST['url_new']) ? DUPX_U::sanitize_text_field($_POST['url_new']) : null;
	}

	/**
	 * After the archive is extracted run setup checks
	 *
	 * @return null
	 */
	public static function afterExtractionSetup()
	{
		if (self::$configMode  != 'IGNORE') {
			//WORDFENCE: Only the WordFence file needs to be removed
			//completly from setup to avoid any issues
			self::removeFile(self::$confFileWordFence, DUPX_ServerConfigTypes::WordFence);
		} else {
			DUPX_Log::info("** CONFIG FILE SET TO IGNORE ALL CHANGES **");
		}
	}

	/**
	 * Before the archive is extracted run a series of back and remove checks
	 * This is for existing config files that may exist before the ones in the
	 * archive are extracted.
	 *
	 * @return void
	 */
	public static function beforeExtractionSetup()
	{
		if (self::$configMode != 'IGNORE') {
			//---------------------
			//APACHE
			if (self::createBackup(self::$confFileApache, DUPX_ServerConfigTypes::Apache))
				self::removeFile(self::$confFileApache, DUPX_ServerConfigTypes::Apache);

			//---------------------
			//MICROSOFT IIS
			if (self::createBackup(self::$confFileIIS, DUPX_ServerConfigTypes::IIS))
				 self::removeFile(self::$confFileIIS, DUPX_ServerConfigTypes::IIS);

			//---------------------
			//WORDFENCE
			if (self::createBackup(self::$confFileWordFence, DUPX_ServerConfigTypes::WordFence))
				 self::removeFile(self::$confFileWordFence, DUPX_ServerConfigTypes::WordFence);
		}
	}

    /**
     * Copies the code in htaccess.orig and web.config.orig
	 * to .htaccess and web.config
     *
	 * @return void
     */
	public static function renameOrigConfigs()
	{
		//APACHE
		if(rename(self::$confFileApacheOrig, self::$confFileApache)){
			DUPX_Log::info("\n- PASS: The orginal htaccess.orig was renamed");
		} else {
			DUPX_Log::info("\n- WARN: The orginal htaccess.orig was NOT renamed");
		}

		//IIS
		if(rename(self::$confFileIISOrig, self::$confFileIIS)){
			DUPX_Log::info("\n- PASS: The orginal htaccess.orig was renamed");
		} else {
			DUPX_Log::info("\n- WARN: The orginal htaccess.orig was NOT renamed");
		}
    }

	 /**
     * Creates the new config file
     *
	 * @return void
     */
	public static function createNewConfigs()
	{
		$config_made = false;

		//APACHE
		if(file_exists(self::$confFileApacheOrig)){
			self::createNewApacheConfig();
			self::removeFile(self::$confFileApacheOrig, DUPX_ServerConfigTypes::Apache);
			$config_made = true;
		}

		if(file_exists(self::$confFileIISOrig)){
			self::createNewIISConfig();
			self::removeFile(self::$confFileIISOrig, DUPX_ServerConfigTypes::IIS);
			$config_made = true;
		}

		//No config was made so try to guess which one
		//95% of the time it will be Apache
		if (! $config_made) {
			if (DUPX_Server::isIISRunning()) {
				self::createNewIISConfig();
			} else {
				self::createNewApacheConfig();
			}
		}
    }

	/**
	 * Sets up the web config file based on the inputs from the installer forms.
	 *
	 * @return void
	 */
	private static function createNewApacheConfig()
	{
		$timestamp   = self::$timeStamp;
		$newdata	 = parse_url(self::$newSiteURL);
		$newpath	 = DUPX_U::addSlash(isset($newdata['path']) ? $newdata['path'] : "");
		$update_msg  = "#This Apache config file was created by Duplicator Installer on {$timestamp}.\n";
		$update_msg .= "#The original can be found in archived file with the name htaccess.orig\n";

        $tmp_htaccess = <<<HTACCESS
{$update_msg}
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase {$newpath}
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . {$newpath}index.php [L]
</IfModule>
# END WordPress
HTACCESS;

		if (@file_put_contents(self::$confFileApache, $tmp_htaccess) === FALSE) {
			DUPX_Log::info("- WARN: Unable to create the .htaccess file! Please check the permission on the root directory and make sure the .htaccess exists.");
		} else {
			DUPX_Log::info("- PASS: Successfully created a new .htaccess file.");
			@chmod(self::$confFileApache, 0644);
		}
    }

	/**
	 * Sets up the web config file based on the inputs from the installer forms.
	 *
	 * @return void
	 */
	private static function createNewIISConfig()
	{
		$timestamp = self::$timeStamp;
		$xml_contents  = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
		$xml_contents .= "<!-- This new IIS config file was created by Duplicator Installer on {$timestamp}.\n"
					  .  "The original can be found in archived file with the name web.config.orig -->\n";
		$xml_contents .=  "<configuration></configuration>\n";
		@file_put_contents(self::$confFileIIS, $xml_contents);
    }
	
	/**
	 * Creates a copy of any existing file and hashes it with a .bak extension
	 *
	 * @param string $file_path					The full path of the config file
	 * @param DUPX_ServerConfigTypes $type		A valid DUPX_ServerConfigTypes
	 *
	 * @return bool		Returns true if the file was backed-up.
	 */
	private static function createBackup($file_path, $type)
	{
		$status		= false;
		$file_name  = SnapLibIOU::getFileName($file_path);
		$hash		= self::$fileHash;
		if (is_file($file_path)) {
			$source = self::getTypeName($type);
			if (! self::backupExists($type)) {
				$status = copy($file_path, "{$file_path}-{$hash}-duplicator.bak");
				$status ? DUPX_Log::info("- PASS: {$source} '{$file_name}' backed-up to {$file_name}-{$hash}-duplicator.bak")
						: DUPX_Log::info("- WARN: {$source} '{$file_name}' unable to create backup copy, a possible permission error?");
			}
		} else {
			DUPX_Log::info("- PASS: {$source} '{$file_name}' not found - no backup needed.");
		}

		return $status;
	}

	/**
	 * Removes the specified file
	 *
	 * @param string $file_path					The full path of the config file
	 * @param DUPX_ServerConfigTypes $type		A valid DUPX_ServerConfigTypes
	 *
	 * @return bool		Returns true if the file was removed
	 */
	private static function removeFile($file_path, $type)
	{
		$status = false;
		if (is_file($file_path)) {
			$source		= self::getTypeName($type);
			$file_name  = SnapLibIOU::getFileName($file_path);
			$status = @unlink($file_path);
			if ($status === FALSE) {
				@chmod($file_path, 0777);
				$status = @unlink($file_path);
			}
			$status ? DUPX_Log::info("- PASS: Existing {$source} '{$file_name}' was removed")
					: DUPX_Log::info("- WARN: Existing {$source} '{$file_path}' not removed, a possible permission error?");
		}
		return $status;
	}

	/**
	 * Check if a backup file already exists
	 *
	 * @param DUPX_ServerConfigTypes $type		A valid DUPX_ServerConfigTypes
	 *
	 * @return bool		Returns true if the file was removed
	 */
	private static function backupExists($type)
	{
		$pattern = 'unknown-duplicator-type-set';

		switch ($type) {
			case DUPX_ServerConfigTypes::Apache:
				$pattern = '/.htaccess-.*-duplicator.bak/';
				break;
			case DUPX_ServerConfigTypes::IIS:
				$pattern = '/web.config-.*-duplicator.bak/';
				break;
			case DUPX_ServerConfigTypes::WordFence:
				$pattern = '/.user.ini-.*-duplicator.bak/';
				break;
		}

		if (is_dir(self::$rootPath)){
			$dir = new DirectoryIterator(self::$rootPath);
			foreach ($dir as $file) {
				if ($file->isFile()) {
					$name = $file->getFilename();
					if (strpos($name, '-duplicator.bak')) {
						if (preg_match($pattern, $name))
							return true;
					}
				}
			}
		}

		return false;
	}

	/**
	 * Gets the friendly type name
	 *
	 * @param DUPX_ServerConfigTypes $type		A valid DUPX_ServerConfigTypes
	 *
	 * @return string		The friendly enum name
	 */
	private static function getTypeName($type)
	{
		switch ($type) {
			case DUPX_ServerConfigTypes::Apache:
				return 'Apache';
				break;
			case DUPX_ServerConfigTypes::IIS:
				return 'Microsoft IIS';
				break;
			case DUPX_ServerConfigTypes::WordFence:
				return 'WordFence';
				break;			

			default:
				throw new Exception('The param $type must be of type DUPX_ServerConfigTypes');
				break;
		}
	}


}

DUPX_ServerConfig::init();
