<?php
/**
 * This file contains the class for the utility functions.
 *
 * @package miniOrange_LDAP_Directory_Search
 * @subpackage Main
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( 'MO_LDAP_Directory_Search_Utility' ) ) {
	/**
	 * MO_LDAP_Directory_Search_Utility : Contains utility functions.
	 */
	class MO_LDAP_Directory_Search_Utility {


		const DEFAULT_CUSTOMER_TOKEN = 'MlSdBdp1';

		/**
		 * Function is_customer_registered : Check if the customer is registered.
		 *
		 * @return boolean
		 */
		public static function is_customer_registered() {
			$email        = ! empty( get_option( 'mo_ldap_ds_admin_email' ) ) ? get_option( 'mo_ldap_ds_admin_email' ) : '';
			$customer_key = ! empty( get_option( 'mo_ldap_ds_admin_customer_key' ) ) ? get_option( 'mo_ldap_ds_admin_customer_key' ) : '';
			if ( ! $email || ! $customer_key || ! is_numeric( trim( $customer_key ) ) ) {
				return 0;
			} else {
				return 1;
			}
		}

		/**
		 * Function encrypt : Encrypts the string.
		 *
		 * @param  string $str String to be encrypted.
		 * @return string
		 */
		public static function encrypt( $str ) {
			if ( ! self::is_extension_installed( 'openssl' ) ) {
				return;
			}
			$key       = get_option( 'mo_ldap_ds_customer_token' );
			$method    = 'AES-128-ECB';
			$str_crypt = openssl_encrypt( $str, $method, $key, OPENSSL_RAW_DATA || OPENSSL_ZERO_PADDING );
			return base64_encode( $str_crypt ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- function not being used to obfuscate the code
		}

		/**
		 * Function decrypt : Decrypts the string.
		 *
		 * @param  string $value String to be decrypted.
		 * @return string
		 */
		public static function decrypt( $value ) {
			if ( ! self::is_extension_installed( 'openssl' ) ) {
				return;
			}
			$str_in  = base64_decode( strval( $value ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -- function not being used to obfuscate the code
			$key     = get_option( 'mo_ldap_ds_customer_token' );
			$method  = 'AES-128-ECB';
			$iv_size = openssl_cipher_iv_length( $method );
			$data    = substr( $str_in, $iv_size );
			$clear   = openssl_decrypt( $data, $method, $key, OPENSSL_RAW_DATA || OPENSSL_ZERO_PADDING );

			return $clear;
		}

		/**
		 * Securely unserialize data from WordPress options
		 * Prevents PHP Object Injection by restricting allowed classes
		 *
		 * @param string $option_value The serialized data to unserialize.
		 * @return array|false Returns array on success, empty array on failure
		 */
		public static function secure_unserialize_option( $option_value ) {

			if ( ! preg_match( '/^[aOs]:[0-9]+:/', $option_value ) ) {
				return array();
			}

			try {

				$unserialized = maybe_unserialize(
					$option_value,
					array( 'allowed_classes' => false ) // prevents PHP object injection.
				);
				if ( false !== $unserialized && is_array( $unserialized ) ) {
					return $unserialized;
				}
			} catch ( Exception $e ) {
				return array();
			}

			return array();
		}


		/**
		 * Function is_extension_installed : check if the extension is installed.
		 *
		 * @param  string $name Name of the extention.
		 * @return boolean
		 */
		public static function is_extension_installed( $name ) {
			if ( in_array( $name, get_loaded_extensions(), true ) ) {
				return true;
			} else {
				return false;
			}
		}

		/**
		 * Function perform_ldap_paginated_search : Perform LDAP search with pagination logic.
		 *
		 * @param  resource $ldapconn LDAP connection resource.
		 * @param  string   $search_base_string Search base.
		 * @param  string   $filter Search filter.
		 * @param  array    $attr_values_array Attributes to retrieve.
		 * @return array|false
		 */
		public static function perform_ldap_paginated_search( $ldapconn, $search_base_string, $filter, $attr_values_array ) {
			$entries        = array();
			$unique_entries = array();
			$page_size      = 1000;
			$cookie         = '';

			if ( version_compare( PHP_VERSION, '7.4.0' ) <= 0 ) {
				do {
					@ldap_control_paged_result( $ldapconn, $page_size, true, $cookie );// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged

					if ( ldap_search( $ldapconn, $search_base_string, $filter ) ) {
						$user_search_result = ldap_search( $ldapconn, $search_base_string, $filter, $attr_values_array );
					} else {
						return false;
					}
					$entry = ldap_get_entries( $ldapconn, $user_search_result );
					foreach ( $entry as $user ) {
						if ( ! is_array( $user ) || ! isset( $user['dn'] ) ) {
							continue;
						}

						$dn = $user['dn'];
						if ( ! isset( $unique_entries[ $dn ] ) ) {
							$unique_entries[ $dn ] = true;
							$entries[]             = $user;
						}
					}
					@ldap_control_paged_result_response( $ldapconn, $user_search_result, $cookie );// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
				} while ( ! empty( $cookie ) );
			} else {
				do {
					$user_search_result = @ldap_search(// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
						$ldapconn,
						$search_base_string,
						$filter,
						$attr_values_array,
						0,
						0,
						0,
						LDAP_DEREF_NEVER,
						array(
							array(
								'oid'   => LDAP_CONTROL_PAGEDRESULTS,
								'value' => array(
									'size'   => $page_size,
									'cookie' => $cookie,
								),
							),
						)
					);
					if ( ! $user_search_result ) {
						return false;
					}
					$controls = array();
					ldap_parse_result( $ldapconn, $user_search_result, $errcode, $matcheddn, $errmsg, $referrals, $controls );
					$entry = ldap_get_entries( $ldapconn, $user_search_result );
					foreach ( $entry as $user ) {
						if ( ! is_array( $user ) || ! isset( $user['dn'] ) ) {
							continue;
						}
						$dn = $user['dn'];
						if ( ! isset( $unique_entries[ $dn ] ) ) {
							$unique_entries[ $dn ] = true;
							$entries[]             = $user;
						}
					}
					if ( isset( $controls[ LDAP_CONTROL_PAGEDRESULTS ]['value']['cookie'] ) ) {
						$cookie = $controls[ LDAP_CONTROL_PAGEDRESULTS ]['value']['cookie'];
					} else {
						$cookie = '';
					}
				} while ( ! empty( $cookie ) );
			}

			return $entries;
		}
	}
}
