HEX
Server: Apache
System: Linux 185.122.168.184.host.secureserver.net 5.14.0-570.52.1.el9_6.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Oct 15 06:39:08 EDT 2025 x86_64
User: barbeatleanalyti (1024)
PHP: 8.1.33
Disabled: NONE
Upload Files
File: /home/barbeatleanalyti/public_html/public_html/webmail/system/Utils/Ldap.php
<?php
/*
 * This code is licensed under AGPLv3 license or Afterlogic Software License
 * if commercial version of the product was purchased.
 * For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
 */

namespace Aurora\System\Utils;

/**
 * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
 * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
 * @copyright Copyright (c) 2018, Afterlogic Corp.
 */
class Ldap
{
	/**
	 * @var resource 
	 */
	private $rLink;
	
	/**
	 * @var resource
	 */
	private $rSearch;

	/**
	 * @var string
	 */
	private $sSearchDN;

	public function __construct($sSearchDN = '')
	{
		$this->rLink = null;
		$this->rSearch = null;
		$this->sSearchDN = $sSearchDN;
	}

	public function Escape($sStr, $bForDn = false)
	{
		if  ($bForDn)
		{
			$aMetaChars = array(',', '=', '+', '<', '>', ';', '\\', '"', '#');
		}
		else
		{
			$aMetaChars = array('*', '(', ')', '\\', chr(0));
		}

		$aQuotedMetaChars = array();
		foreach ($aMetaChars as $iKey => $sValue)
		{
			$aQuotedMetaChars[$iKey] = '\\'.str_pad(dechex(ord($sValue)), 2, '0');
		}
		
		return str_replace($aMetaChars,$aQuotedMetaChars, $sStr);
	}

	/**
	 * @param string $sSearchDN
	 * @return Ldap
	 */
	public function SetSearchDN($sSearchDN)
	{
		$this->sSearchDN = $sSearchDN;
		return $this;
	}

	/**
	 * @return string
	 */
	public function GetSearchDN()
	{
		return $this->sSearchDN;
	}

	/**
	 * @param string $sHost
	 * @param int $iPort
	 * @param string $sBindDb = ''
	 * @param string $sBindPassword = ''
	 * @param string $sHostBack = ''
	 * @param int $iPortBack = null
	 * @return bool
	 */
	public function Connect($sHost, $iPort, $sBindDb = '', $sBindPassword = '', $sHostBack = '', $iPortBack = null)
	{
		if (!extension_loaded('ldap'))
		{
			\Aurora\System\Api::Log('LDAP: Can\'t load LDAP extension.', \Aurora\System\Enums\LogLevel::Error);
			return false;
		}

		if (!is_resource($this->rLink))
		{
			\Aurora\System\Api::Log('LDAP: connect to '.$sHost.':'.$iPort);
			
			$rLink = ldap_connect($sHost, $iPort);
			if ($rLink)
			{
				@ldap_set_option($rLink, LDAP_OPT_PROTOCOL_VERSION, 3);
				@ldap_set_option($rLink, LDAP_OPT_REFERRALS, 0);
				@ldap_set_option($rLink, LDAP_SCOPE_SUBTREE, 0);
				
				\Aurora\System\Api::Log('LDAP: bind = "'.$sBindDb.'" / "'.$sBindPassword.'"');
				if (0 < strlen($sBindDb) && 0 < strlen($sBindPassword) ?
					!@ldap_bind($rLink, $sBindDb, $sBindPassword) : !@ldap_bind($rLink)
				)
				{
					$this->rLink = $rLink;

					$this->validateLdapErrorOnFalse(false);

					$this->rLink = null;
					if (0 < strlen($sHostBack))
					{
						return $this->Connect($sHostBack, $iPortBack, $sBindDb, $sBindPassword);
					}

					return false;
				}
				else
				{
//					@register_shutdown_function(array(&$this, 'Disconnect'));
					$this->rLink = $rLink;
				}
			}
			else
			{
				$this->validateLdapErrorOnFalse(false);
				if (0 < strlen($sHostBack))
				{
					return $this->Connect($sHostBack, $iPortBack, $sBindDb, $sBindPassword);
				}

				return false;
			}
		}

		return true;
	}

	/**
	 * @param string $sBindDb
	 * @param string $sBindPassword
	 * @return bool
	 */
	public function ReBind($sBindDb, $sBindPassword)
	{
		if (is_resource($this->rLink))
		{
			\Aurora\System\Api::Log('LDAP: rebind '.$sBindDb);

			if (!@ldap_bind($this->rLink, $sBindDb, $sBindPassword))
			{
				$this->validateLdapErrorOnFalse(false);
				$this->rLink = null;
			}
			else
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * @param mixed $mReturn
	 * @return mixed
	 */
	private function validateLdapErrorOnFalse($mReturn)
	{
		if (false === $mReturn)
		{
			if ($this->rLink)
			{
				\Aurora\System\Api::Log('LDAP: error #'.@ldap_errno($this->rLink).': '.@ldap_error($this->rLink), \Aurora\System\Enums\LogLevel::Error);
			}
			else
			{
				\Aurora\System\Api::Log('LDAP: unknown ldap error', \Aurora\System\Enums\LogLevel::Error);
			}
		}

		return $mReturn;
	}

	/**
	 * @param string $sObjectFilter
	 * @return bool
	 */
	public function Search($sObjectFilter)
	{
		if ($this->rSearch && $this->sLastRequest === $this->sSearchDN.$sObjectFilter)
		{
			\Aurora\System\Api::Log('LDAP: search repeat = "'.$this->sSearchDN.'" / '.$sObjectFilter);

			$this->validateLdapErrorOnFalse($this->rSearch);
			return is_resource($this->rSearch);
		}
		else
		{
			\Aurora\System\Api::Log('LDAP: search = "'.$this->sSearchDN.'" / '.$sObjectFilter);
			$this->rSearch = @ldap_search($this->rLink, $this->sSearchDN, $sObjectFilter, array('*'), 0, 3000);

			$this->validateLdapErrorOnFalse($this->rSearch);

			$this->sLastRequest = $this->sSearchDN.$sObjectFilter;
			return is_resource($this->rSearch);
		}

		return false;
	}

	/**
	 * @return bool
	 */
	public function Add($sNewDn, $aEntry)
	{
		\Aurora\System\Api::Log('ldap_add = '.((empty($sNewDn) ? '' : $sNewDn.',').$this->sSearchDN));
		\Aurora\System\Api::LogObject($aEntry);

		$bResult = !!@ldap_add($this->rLink, (empty($sNewDn) ? '' : $sNewDn.',').$this->sSearchDN, $aEntry);
		$this->validateLdapErrorOnFalse($bResult);

		return $bResult;
	}

	/**
	 * @return bool
	 */
	public function Delete($sDeleteDn)
	{
		$bResult = false;
		if (!empty($sDeleteDn))
		{
			\Aurora\System\Api::Log('ldap_delete = '.($sDeleteDn.','.$this->sSearchDN));
			$bResult = !!@ldap_delete($this->rLink, $sDeleteDn.','.$this->sSearchDN);
			$this->validateLdapErrorOnFalse($bResult);
		}

		return $bResult;
	}

	/**
	 * @return bool
	 */
	public function Modify($sModifyDn, $aModifyEntry)
	{
		$bResult = false;
		if (!empty($sModifyDn))
		{
			if (!empty($this->sSearchDN))
			{
				$sModifyDn = $sModifyDn.','.$this->sSearchDN;
			}
			
			\Aurora\System\Api::Log('ldap_modify = '.$sModifyDn);
			\Aurora\System\Api::LogObject($aModifyEntry);

			$bResult = !!@ldap_modify($this->rLink, $sModifyDn, $aModifyEntry);
			$this->validateLdapErrorOnFalse($bResult);
		}

		return $bResult;
	}
	
	/**
	 * @return int
	 */
	public function ResultCount()
	{
		$iResult = 0;
		
		$iCount = ldap_count_entries($this->rLink, $this->rSearch);
		$this->validateLdapErrorOnFalse($iCount);
		if (false !== $iCount)
		{
			$iResult = $iCount;
		}

		return $iResult;
	}

	/**
	 * @return mixed
	 */
	public function ResultItem()
	{
		$mResult = false;

		$aResurn = @ldap_get_entries($this->rLink, $this->rSearch);
		$this->validateLdapErrorOnFalse($aResurn);
		if (false !== $aResurn && isset($aResurn[0]) && is_array($aResurn[0]))
		{
			$mResult = $aResurn[0];
		}

		return $mResult;
	}

	/**
	 * @param string $sSortField
	 * @param string $bAsc 'asc' or 'desc'
	 * @param int $iOffset = null
	 * @param int $iRequestLimit = null
	 * @return array
	 */
	public function SortPaginate($sSortField, $bAsc = true, $iOffset = null, $iRequestLimit = null)
	{
		$iTotalEntries = @ldap_count_entries($this->rLink, $this->rSearch);

		$iEnd = 0;
		$iStart = 0;
		if ($iOffset === null || $iRequestLimit === null)
		{
			$iStart = 0;
			$iEnd = $iTotalEntries - 1;
		}
		else
		{
			$iStart = $iOffset;
			$iStart = ($iStart < 0) ? 0 : $iStart;

			$iEnd = $iStart + $iRequestLimit;
			$iEnd = ($iEnd > $iTotalEntries) ? $iTotalEntries : $iEnd;
		}

		if (0 < strlen($sSortField))
		{
			@ldap_sort($this->rLink, $this->rSearch, $sSortField);
		}

		$aList = array();
		for ($iCurrent = 0, $rEntry = ldap_first_entry($this->rLink, $this->rSearch);
			$iCurrent < $iEnd && is_resource($rEntry);
			$iCurrent++, $rEntry = ldap_next_entry($this->rLink, $rEntry)
		)
		{
			if ($iCurrent >= $iStart)
			{
				array_push($aList, ldap_get_attributes($this->rLink, $rEntry));
			}
		}

		return $bAsc ? $aList : array_reverse($aList);
	}
}