HEX
Server: Apache/2.4.58 (Ubuntu)
System: Linux ns3133907 6.8.0-86-generic #87-Ubuntu SMP PREEMPT_DYNAMIC Mon Sep 22 18:03:36 UTC 2025 x86_64
User: cssnetorguk (1024)
PHP: 8.2.28
Disabled: NONE
Upload Files
File: //home/surrey.me.uk/public_html/wp-content/plugins/zotya-htaccess-protect/class.htaccess.php
<?php
/**
* Main class for htaccess protect
* @package zotya_htaccess_protect
*/

class ZOTYA_HP {
	public $htpasswd_file;
	public $htaccess_root;
	public $htaccess_admin;

	function __construct() {
		$this->htpasswd_file = ABSPATH . '.htpasswd';
		$this->htaccess_root = ABSPATH . '.htaccess';
		$this->htaccess_admin = ABSPATH . 'wp-admin/.htaccess';
	}

	/**
	* Adds new user to the .htpasswd file
	* @return boolean
	*/
	function add_user() {
		// Check the referer
		check_admin_referer( 'zotya_hp_add_user' );
		// If the fields are set
		if ( isset( $_POST['new_username'] ) ) {
			// sanitize the text field
			$username = sanitize_user( $_POST['new_username'] );
		}
		// If the password field is set
		if ( isset( $_POST['new_password'] ) ) {
			$password = sanitize_text_field( $_POST['new_password'] );
		}
		// if both fields exists
		if ( !empty( $username ) && !empty( $password ) ) {
			// If user can manage options
			if ( current_user_can( 'manage_options' ) ) {
				$this->modify_htpasswd( $username, $password, 'add' );
				$_SESSION['zotya_hp_msg'] = esc_html__( 'New user added', 'zotya-htaccess-protect' );
				return true;
			}
		}
		return false;
		$_SESSION['zotya_hp_msg'] = esc_html__( 'Something went wrong. Please try again.', 'zotya-htaccess-protect' );
	}

	/**
	* Removes user from .htpasswd file
	* @return boolean
	*/
	function remove_user() {
		// If current user can manage options
		if ( current_user_can( 'manage_options' ) ) {
			// If the username to remove is set
			if ( isset( $_POST['username'] ) ){
				$username = sanitize_user( $_POST['username'] );
			}
			if ( !empty( $username ) ){
				// Check the admin referer
				check_admin_referer( "zotya_hp_user_$username" );
				// Remove the user
				$this->modify_htpasswd( $username, '', 'delete' );
				$_SESSION['zotya_hp_msg'] = esc_html__( 'User removed.', 'zotya-htaccess-protect' );

				// If there are no users left after deleting
				if ( ! count( $this->get_htpasswd_users() ) ) {
					// Disable the plugin by removing the htaccess rows not to get locked out
					$this->remove_wp_admin_protection();
					$this->remove_wp_root_protection();
					// Modify the saved options
					$options = array( 'zotya_hp_admin'=>0, 'zotya_hp_login'=>0, 'zotya_hp_site'=>0, 'zotya_hp_fix_auth'=>0 );
					update_option( 'zotya_hp_options', serialize( $options ) );
					$_SESSION['zotya_hp_msg'] = esc_html__( 'User removed. The locks were disabled: there are no users left.', 'zotya-htaccess-protect' );
				}
				return true;
			}
		}
		return false;
		$_SESSION['zotya_hp_msg'] = esc_html__( 'Something went wrong. Please try again.', 'zotya-htaccess-protect' );
	}

	/**
	* Change user password in the htpasswd file
	* @return boolean
	*/
	function modify_user() {
		// If user has admin permissions
		if ( current_user_can( 'manage_options' ) ) {
			// If username is set
			if ( isset( $_POST['username'] ) ) {
				$username = sanitize_user( $_POST['username'] );
			}
			// If the password is set
			if ( isset( $_POST['pwd_user'] ) ) {
				$password = sanitize_text_field( $_POST['pwd_user'] );
			}
			if ( !empty( $username ) && !empty( $password ) ) {
				// Check the referer
				check_admin_referer( "zotya_hp_user_$username" );
				// Modify the file
				$this->modify_htpasswd( $username, $password, 'modify' );
				$_SESSION['zotya_hp_msg'] = esc_html__( 'User password changed.', 'zotya-htaccess-protect' );
				return true;
			}
		}
		$_SESSION['zotya_hp_msg'] = esc_html__( 'Something went wrong. Please try again.', 'zotya-htaccess-protect' );
	}

	/**
	* Modifies the .htpasswd file
	*
	* @param String $username
	* @param String $pass
	* @param String $action
	* @return boolean
	*/
	function modify_htpasswd( $username, $pass, $action ) {
		if ( !file_exists( $this->htpasswd_file ) || is_writeable( $this->htpasswd_file ) ) {
			// Encrypt the password
			$password = base64_encode( sha1( $pass, true ) );
			$content = '';
			// If file doesn't exist
			if ( ! file_exists( $this->htpasswd_file ) ) {
				// Take the content of the file as empty
				$lines = '';
			}
			// Otherwise get the content
			else {
				$lines = explode( "\n", implode( '', file( $this->htpasswd_file ) ) );
			}

			if ( ! $f = @fopen( $this->htpasswd_file, 'w' ) ) return false;

			// If any lines exist in the file
			if ( $lines ){
				$found = false;
				// render the lines and compare the the username
				foreach ( $lines as $line ) {
					$line = preg_replace( '/\s+/', '', $line ); // remove spaces
					if ( $line ) {
						if ( strpos( $line, ':{SHA}') !== false ) {
							list( $user, $pass ) = explode( ":{SHA}", $line, 2 );
						} else {
							$user = $pass = false;
						}
						// If it's for removing the user
						if ( $action == 'delete' ) {
							// If the line isn't for the user being removed, add the line to the file
							if ( $user != $username && ( $user && $pass ) ) {
								$content .= $user . ':{SHA}' . $pass . "\n";
							}
						}
						// In other cases
						else {
							// If user found
							if ( $user == $username ) {
								// Add new password
								$content .= $username . ':{SHA}' . $password . "\n";
								// Mark the user found
								$found = true;
							} else {
								if ( $user && $pass ) {
									$content .= $user . ':{SHA}' . $pass . "\n";
								}
							}
						}
					}
				}
			}
			// If it's not removing the user
			if ( $action != 'delete' ) {
				// If there is no content, or the user to modify wasn't find, add the user to the end
				if ( ! strlen( trim( $content ) ) || !$found ) {
					$content .= $username . ':{SHA}' . $password;
				}
			}
			$content = explode( "\n", $content );
			// Write the content to the file
			foreach ( $content as $contentline ) {
				fwrite( $f, $contentline . "\n" );
			}
			fclose( $f );
		}
	}

	/**
	* Removes the rows from .htaccess that password protect wp-login.php
	*/
	function remove_wp_root_protection() {
		$this->zotya_hp_remove_with_markers( $this->htaccess_root, 'ZOTYA htaccess protect' );
	}

	/**
	* Remove the added rows from .htaccess file for locking up wp-admin
	*/
	function remove_wp_admin_protection() {
		$this->zotya_hp_remove_with_markers( $this->htaccess_admin, 'ZOTYA htaccess protect' );
	}

	/**
	* Gets the list of the users entered to .htpasswd
	*/
	function get_htpasswd_users() {
		//Create an empty array for users
		$users = array();
		//If the file doesn't exist or isn't readable, return
		if ( ! file_exists( $this->htpasswd_file ) || ! is_readable( $this->htpasswd_file ) ) {
			return $users;
		}
		// If can't open the file, return
		if ( !$f = @fopen( $this->htpasswd_file, 'r' ) ) {
			return $users;
		}
		// Create an array of the lines in file
		$lines = explode( "\n", implode( '', file( $this->htpasswd_file ) ) );
		// If no lines, return
		if ( !$lines ) {
			return $users;
		}
		// Loop the lines
		foreach ($lines as $line) {
			// If line exists after trim
			if ( trim( $line ) ) {
				// Split the line by ':{SHA}'
				if ( strpos( $line, ':{SHA}') !== false ) {
					list( $user, $pass ) = explode( ":{SHA}", $line, 2 );
					// Add the found user to users' array
					$users[] = $user;
				}
			}
		}
		fclose( $f );
		// Return the found users
		return $users;
	}

	/**
	* Register plugin scripts
	*/
	function register_plugin_scripts(){
		wp_enqueue_script( 'jquery' );
		wp_enqueue_script( 'zotya-hp-script', plugin_dir_url( ZOTYA_HP_FILE ) . 'js/script.js', array( 'jquery' ) );
		wp_enqueue_style( 'zotya-hp-style', plugin_dir_url( ZOTYA_HP_FILE ) . 'css/style.css' );

	}

	/**
	* Enable or disable the wp-admin and/or wp-login.php password protection
	*/
	function change_settings() {
		//C heck the form referer for security reasons
		check_admin_referer( "zotya_hp_settings" );
		// Only allow is the user can manage options
		if ( current_user_can( 'manage_options' ) ) {
			//Get the existing options
			$options = unserialize( get_option( 'zotya_hp_options' ) );
			//Modify and update the options
			$options['zotya_hp_admin'] = (int) rest_sanitize_boolean( $_POST['zotya_hp_admin'] );
			$options['zotya_hp_login'] = (int) rest_sanitize_boolean( $_POST['zotya_hp_login'] );
			$options['zotya_hp_site'] = (int) rest_sanitize_boolean( $_POST['zotya_hp_site'] );
			$options['zotya_hp_fix_auth'] = (int) rest_sanitize_boolean( $_POST['zotya_hp_fix_auth'] );
			update_option( 'zotya_hp_options', serialize( $options ) );

			// If the wp-admin lock was enabled
			if ( $options['zotya_hp_admin'] ) $this->add_wp_admin_protection($options['zotya_hp_fix_auth']);
			else $this->remove_wp_admin_protection();

			$this->remove_wp_root_protection();

			// If all the site protection was enabled
			if ( $options['zotya_hp_site'] ) $this->add_wp_root_protection( 'all', $options['zotya_hp_fix_auth'] );

			// If the wp-login.php lock was enabled
			elseif ( $options['zotya_hp_login'] ) $this->add_wp_root_protection( 'login', $options['zotya_hp_fix_auth'] );

			$_SESSION['zotya_hp_msg'] = esc_html__( 'Settings saved.', 'zotya-htaccess-protect' );
		}
	}

	/**
	* Add wp-admin password protection
	*/
	function add_wp_admin_protection( $fix_auth = false ){
		if ( ! function_exists( 'insert_with_markers' ) ) {
			require_once( ABSPATH . 'wp-admin/includes/misc.php' );
		}
		$insertion = '';
		if ( $fix_auth ) $insertion .= "\tSetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0\n";
		$insertion .= "\tAuthUserFile " . $this->htpasswd_file . "\n\tAuthType basic\n\tAuthName \"Restricted\"\n\trequire valid-user\n\tErrorDocument 401 \"Authorization Required\"\n\t# Stop Apache from serving .ht* files\n\t<Files ~ \"^\.ht\">\n\tOrder allow,deny\n\tDeny from all\n\t</Files>\n\t<Files admin-ajax.php>\n\tOrder allow,deny\n\tAllow from all\n\tSatisfy any\n\t</Files>\n\t<Files ~ \"\.(css|js|svg|png|jpeg|jpg|gif)$\">\n\tOrder allow,deny\n\tAllow from all\n\tSatisfy any\n\t</Files>";

		// Since it has to be an array, explode
		$insertion = explode( "\n", $insertion );
		insert_with_markers( $this->htaccess_admin, 'ZOTYA htaccess protect', $insertion );
	}

	/**
	* Add root password protection
	*/
	function add_wp_root_protection( $type, $fix_auth = false ){
		if ( ! function_exists( 'insert_with_markers' ) ) {
			require_once( ABSPATH . 'wp-admin/includes/misc.php' );
		}
		$insertion = "\t# Stop Apache from serving .ht* files\n\t<Files ~ \"^\.ht\">\n\tOrder allow,deny\n\tDeny from all\n\t</Files>\n";
		if ( $type == 'login' ) $insertion .= "\t# Protect wp-login\n\t<Files wp-login.php>\n";
		if ( $fix_auth ) $insertion .= "\tSetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0\n";
		$insertion .= "\tAuthUserFile " . $this->htpasswd_file . "\n\tAuthType basic\n\tAuthName \"Restricted\"\n\trequire valid-user\n\tErrorDocument 401 \"Authorization Required\"\n";
		if ( $type == 'login' ) $insertion .= "\t</Files>\n";
		$insertion .= "\t<Files admin-ajax.php>\n\torder allow,deny\n\tallow from all\n\t</Files>";

		//Since it has to be an array, explode
		$insertion = explode( "\n", $insertion );
		insert_with_markers( $this->htaccess_root, 'ZOTYA htaccess protect', $insertion );
	}

	/**
	* Check if the plugin has sufficient permissions
	* @return boolean
	*/
	function plugin_has_sufficient_permissions() {
		$_SESSION['htaccess_admin'] = 1;
		$_SESSION['htaccess_root'] = 1;
		$_SESSION['htpasswd'] = 1;
		// Check if .htaccess for admin folder is writeable
		$has_permissions = true;
		// If file exists but is not writeable, return false
		if ( file_exists( $this->htaccess_admin ) && !is_writeable( $this->htaccess_admin  ) ) {
			$_SESSION['htaccess_admin'] = 0;
			$has_permissions = false;
		}
		// If file doesn't exist and the folder isn't writeable, return false
		elseif ( !file_exists( $this->htaccess_admin  ) && !is_writeable( ABSPATH.'wp-admin/'  ) ) {
			$_SESSION['htaccess_admin'] = 0;
			$has_permissions = false;
		}
		// Check if .htpasswd file is writeable
		// If file doesn't exist and the folder isn't writeable
		if ( !file_exists( $this->htpasswd_file ) && !is_writeable( ABSPATH ) ) {
			$_SESSION['htpasswd'] = 0;
			$has_permissions = false;
		}
		elseif ( file_exists( $this->htpasswd_file ) && !is_writeable( $this->htpasswd_file ) ) {
			$_SESSION['htpasswd'] = 0;
			$has_permissions = false;
		}
		// Check if .htaccess file for wp-login.php is writeable
		// If file doesn't exist and the folder isn't writeable
		if ( !file_exists( $this->htaccess_root ) && !is_writeable( ABSPATH ) ) {
			$_SESSION['htaccess_root'] = 0;
			$has_permissions = false;
		}
		elseif ( file_exists( $this->htaccess_root ) && !is_writeable( $this->htaccess_root ) ) {
			$_SESSION['htaccess_root'] = 0;
			$has_permissions = false;
		}
		return $has_permissions;
	}

	/**
	* Remove lines from .htaccess files with markers
	* @param string $filename
	* @param string $marker
	* @return boolean
	*/
	function zotya_hp_remove_with_markers( $filename, $marker ) {
		if ( !file_exists( $filename ) || is_writeable( $filename ) ) {
			$marker_regex = '/# BEGIN ' . $marker . '+?# END ' . $marker . '/s';
			$content = file_get_contents( $filename );
			$new_content = preg_replace( $marker_regex, '', $content );
			file_put_contents( $filename, $new_content );
			return true;
		} else {
			return false;
		}
	}

	/**
	* On plugin activation
	*/
	function activate() {
		// Create the default options
		$options = array( 'zotya_hp_admin'=>0, 'zotya_hp_login'=>0, 'zotya_hp_site'=>0, 'zotya_hp_fix_auth'=>0 );
		update_option( 'zotya_hp_options', serialize( $options ), true );
	}

	/**
	* On plugin deactivation
	*/
	function deactivate() {
		// Remove rows for locking up
		$this->remove_wp_root_protection();
		$this->remove_wp_admin_protection();

		// Set options to default
		$options = array( 'zotya_hp_admin'=>0, 'zotya_hp_login'=>0, 'zotya_hp_site'=>0, 'zotya_hp_fix_auth'=>0 );
		update_option( 'zotya_hp_options', serialize( $options ) );
	}
}