<commit_before><?php

// Copyright (C) 2013 <NAME>
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is furnished
// to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


namespace ADX\Core;
use ADX\Enums;

/**
 * Represents a connection to an ldap server
 *
 * This class is an encapsulation of the Resource ldap_link, returned by php's
 * <a href="http://www.php.net/manual/en/function.ldap-connect.php">ldap_connect()</a> function and
 * serves to simplify the configuration tasks of this link. You perform operations like connecting,
 * binding, configuring the connection and reading the RootDSE entry using this object.
 * <br>
 * <br>
 * If you typecast this object into a string you will get the current domain name the link is connected to.
 *
 * <h3>Method Chaining</h3>
 * Methods may be chained together to simplify configuration. Ensure that the methods you wish to chain
 * together return the {@link self} object to avoid issues. See the example code below.
 *
 * <h3>Serialisation support</h3>
 * You can serialise / unserialise the object to preserve the configuration across server requests.
 * This allows you to configure a link with the needed features, perform an operation on the server,
 * then store the link to i.e. a database for later re-use. If the user requests next operation, you can
 * restore the object from the serialised data and continue using the link without any further configuration
 * ( you will have to {@link self::bind()} again with the same credentials, though ).<br>
 * This is especially useful when performing paged search results - you get the first page, store the link in
 * database, present the data to user and if user requests the next page, you use the same link to retrieve
 * next batch of results.<br>
 * <br>
 * <p class="alert">Make sure you import the class into current namespace before trying to use it:<br>
 * <code>use ADX\Core\Link;</code><br>
 * To simplify the examples, the above line is not present in the examples but it is assumed you have
 * it in your implementation.</p>
 *
 * <h2>Example:</h2>
 * <code>
 * $link = new Link( 'example.com' );	// Connect to example.com over standard port 389
 * // Typecasting to string gives you the domain name this link is connected to
 * echo "$link";	// example.com
 *
 * // Chaining methods...
 * $link->use_tls()->bind( '<EMAIL>', '<PASSWORD>' );
 *
 * // Serialisation support
 * $serialised = serialize( $link );
 * // Save $serialised to a database...
 * // WARNING - $link is no longer usable after being serialised!
 *
 * // In a later server request...
 * $link = unserialize( $serialised ); // Retrieve $serialised from your storage first
 * $link->bind( '<EMAIL>', '<PASSWORD>' );	// Use the link with previously configured features
 * </code>
 *
 * @see			{@link Task} - perform lookup operations on directory servers
 */
class Link
{
	/**
	 * {@link Object} that represents the RootDSE of a directory server.
	 *
	 * This information is generated automatically for each new Link object and the information
	 * is used across the library. You should not attempt to modify the object.
	 *
	 * These attributes ( represented as {@link Attribute} ) are available by default:<br>
	 * - dnshostname
	 * - defaultnamingcontext
	 * - supportedcontrol
	 * - supportedldapversion
	 * - supportedsaslmechanisms
	 * - rootdomainnamingcontext
	 * - configurationnamingcontext
	 * - schemanamingcontext
	 * - namingcontexts
	 * - currenttime
	 *
	 * <h4>Example</h4>
	 * <code>
	 * // Read the current time of the directory server
	 * $link		= new Link( 'example.com' );
	 * $server_time	= $link->rootDSE->currenttime->value( 0 );
	 * // Do something with $server_time...
	 * </code>
	 *
	 * @var			Object
	 * @see			<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms684291%28v=vs.85%29.aspx">MSDN - RootDSE</a>
	 */
	public $rootDSE;

	protected $link_id;				// Resource link_identifier ( as returned by ldap_connect() )

	protected $domain;				// Domain to which this Link is connected
	protected $port;				// Port for the connection
	protected $username;			// Username used for binding
	protected $password;			// <PASSWORD> binding

	protected $isBound	= false;	// Is the connection already bound using ldap_bind() ?
	protected $use_tls	= false;	// Is the connection TLS-enabled?

	protected $options	= array();	// Array with user-supplied ( or default ) ldap options

	/**
	 * Create a new connection to a directory server
	 *
	 * Connects to a directory server and reads the RootDSE entry ( via anonymous bind ).
	 * Note that <b>ldap v3 is enforced</b> for all operations and cannot be overriden.
	 *
	 * <h4>Example</h4>
	 * <code>
	 * $link = new Link( 'example.com' );	// Uses default ldap port 389
	 * $link = new Link( 'example.com', 636 );	// Uses ssl-specific port 636
	 * $link = new Link( 'example.com', 389, [ServerControl::ShowDeleted] );	// Allows listing of deleted objects
	 * </code>
	 *
	 * @param		string		DNS name of the directory server, i.e. <i>example.com</i>
	 * @param		integer		Port to use for connection
	 * @param		array		Optional list of options to use. See {@link Enums\ServerControl} for available options
	 *
	 * @see			<a href="http://www.php.net/manual/en/function.ldap-connect.php">PHP - ldap_connect()</a>
	 * @see			<a href="http://www.php.net/manual/en/function.ldap-set-option.php">PHP - ldap_set_option()</a>
	 */
	public function __construct( $domain, $port = 389, $options = array() )
	{
		// Store the provided options in the options property of this object
		foreach ( $options as $option => $value ) $this->options[$option] = $value;

		$this->domain	= $domain;
		$this->port		= $port;
		$this->link_id	= ldap_connect( $domain, $port );	// Connect to ldap

		// Load the rootDSE object
		if ( ! $this->rootDSE )
		{
			$get = [
				'dnshostname',
				'defaultnamingcontext',
				'highestcommitedusn',
				'supportedcontrol',
				'supportedldapversion',
				'supportedsaslmechanisms',
				'rootdomainnamingcontext',
				'configurationnamingcontext',
				'schemanamingcontext',
				'namingcontexts',
				'currenttime',
			];

			$this->rootDSE = $this->rootDSE( $get );
		}

		// Make sure that the server supports ldap v3 protocol, otherwise no need to continue
		if ( ! in_array( 3, $this->rootDSE->supportedldapversion() ) ) throw new UnsupportedPlatformException();

		// Force the link to use ldap v3 and disable native referrals handling as it is required by this implementation
		ldap_set_option( $this->link_id, LDAP_OPT_PROTOCOL_VERSION,	3 );
		ldap_set_option( $this->link_id, LDAP_OPT_REFERRALS,		0 );
	}

	/**
	 * Bind to the directory server using provided credentials ( or anonymously if none provided )
	 *
	 * This method performs the standard <code>ldap_bind()</code> operation on the ldap link. Before that, it performs<commit_msg>[dev] Fix typo, it's double T in highestcommittedusn<commit_after><?php

// Copyright (C) 2013 <NAME>
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is furnished
// to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


namespace ADX\Core;
use ADX\Enums;

/**
 * Represents a connection to an ldap server
 *
 * This class is an encapsulation of the Resource ldap_link, returned by php's
 * <a href="http://www.php.net/manual/en/function.ldap-connect.php">ldap_connect()</a> function and
 * serves to simplify the configuration tasks of this link. You perform operations like connecting,
 * binding, configuring the connection and reading the RootDSE entry using this object.
 * <br>
 * <br>
 * If you typecast this object into a string you will get the current domain name the link is connected to.
 *
 * <h3>Method Chaining</h3>
 * Methods may be chained together to simplify configuration. Ensure that the methods you wish to chain
 * together return the {@link self} object to avoid issues. See the example code below.
 *
 * <h3>Serialisation support</h3>
 * You can serialise / unserialise the object to preserve the configuration across server requests.
 * This allows you to configure a link with the needed features, perform an operation on the server,
 * then store the link to i.e. a database for later re-use. If the user requests next operation, you can
 * restore the object from the serialised data and continue using the link without any further configuration
 * ( you will have to {@link self::bind()} again with the same credentials, though ).<br>
 * This is especially useful when performing paged search results - you get the first page, store the link in
 * database, present the data to user and if user requests the next page, you use the same link to retrieve
 * next batch of results.<br>
 * <br>
 * <p class="alert">Make sure you import the class into current namespace before trying to use it:<br>
 * <code>use ADX\Core\Link;</code><br>
 * To simplify the examples, the above line is not present in the examples but it is assumed you have
 * it in your implementation.</p>
 *
 * <h2>Example:</h2>
 * <code>
 * $link = new Link( 'example.com' );	// Connect to example.com over standard port 389
 * // Typecasting to string gives you the domain name this link is connected to
 * echo "$link";	// example.com
 *
 * // Chaining methods...
 * $link->use_tls()->bind( '<EMAIL>', '<PASSWORD>' );
 *
 * // Serialisation support
 * $serialised = serialize( $link );
 * // Save $serialised to a database...
 * // WARNING - $link is no longer usable after being serialised!
 *
 * // In a later server request...
 * $link = unserialize( $serialised ); // Retrieve $serialised from your storage first
 * $link->bind( '<EMAIL>', '<PASSWORD>' );	// Use the link with previously configured features
 * </code>
 *
 * @see			{@link Task} - perform lookup operations on directory servers
 */
class Link
{
	/**
	 * {@link Object} that represents the RootDSE of a directory server.
	 *
	 * This information is generated automatically for each new Link object and the information
	 * is used across the library. You should not attempt to modify the object.
	 *
	 * These attributes ( represented as {@link Attribute} ) are available by default:<br>
	 * - dnshostname
	 * - defaultnamingcontext
	 * - supportedcontrol
	 * - supportedldapversion
	 * - supportedsaslmechanisms
	 * - rootdomainnamingcontext
	 * - configurationnamingcontext
	 * - schemanamingcontext
	 * - namingcontexts
	 * - currenttime
	 *
	 * <h4>Example</h4>
	 * <code>
	 * // Read the current time of the directory server
	 * $link		= new Link( 'example.com' );
	 * $server_time	= $link->rootDSE->currenttime->value( 0 );
	 * // Do something with $server_time...
	 * </code>
	 *
	 * @var			Object
	 * @see			<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms684291%28v=vs.85%29.aspx">MSDN - RootDSE</a>
	 */
	public $rootDSE;

	protected $link_id;				// Resource link_identifier ( as returned by ldap_connect() )

	protected $domain;				// Domain to which this Link is connected
	protected $port;				// Port for the connection
	protected $username;			// Username used for binding
	protected $password;			// Password used for binding

	protected $isBound	= false;	// Is the connection already bound using ldap_bind() ?
	protected $use_tls	= false;	// Is the connection TLS-enabled?

	protected $options	= array();	// Array with user-supplied ( or default ) ldap options

	/**
	 * Create a new connection to a directory server
	 *
	 * Connects to a directory server and reads the RootDSE entry ( via anonymous bind ).
	 * Note that <b>ldap v3 is enforced</b> for all operations and cannot be overriden.
	 *
	 * <h4>Example</h4>
	 * <code>
	 * $link = new Link( 'example.com' );	// Uses default ldap port 389
	 * $link = new Link( 'example.com', 636 );	// Uses ssl-specific port 636
	 * $link = new Link( 'example.com', 389, [ServerControl::ShowDeleted] );	// Allows listing of deleted objects
	 * </code>
	 *
	 * @param		string		DNS name of the directory server, i.e. <i>example.com</i>
	 * @param		integer		Port to use for connection
	 * @param		array		Optional list of options to use. See {@link Enums\ServerControl} for available options
	 *
	 * @see			<a href="http://www.php.net/manual/en/function.ldap-connect.php">PHP - ldap_connect()</a>
	 * @see			<a href="http://www.php.net/manual/en/function.ldap-set-option.php">PHP - ldap_set_option()</a>
	 */
	public function __construct( $domain, $port = 389, $options = array() )
	{
		// Store the provided options in the options property of this object
		foreach ( $options as $option => $value ) $this->options[$option] = $value;

		$this->domain	= $domain;
		$this->port		= $port;
		$this->link_id	= ldap_connect( $domain, $port );	// Connect to ldap

		// Load the rootDSE object
		if ( ! $this->rootDSE )
		{
			$get = [
				'dnshostname',
				'defaultnamingcontext',
				'highestcommittedusn',
				'supportedcontrol',
				'supportedldapversion',
				'supportedsaslmechanisms',
				'rootdomainnamingcontext',
				'configurationnamingcontext',
				'schemanamingcontext',
				'namingcontexts',
				'currenttime',
			];

			$this->rootDSE = $this->rootDSE( $get );
		}

		// Make sure that the server supports ldap v3 protocol, otherwise no need to continue
		if ( ! in_array( 3, $this->rootDSE->supportedldapversion() ) ) throw new UnsupportedPlatformException();

		// Force the link to use ldap v3 and disable native referrals handling as it is required by this implementation
		ldap_set_option( $this->link_id, LDAP_OPT_PROTOCOL_VERSION,	3 );
		ldap_set_option( $this->link_id, LDAP_OPT_REFERRALS,		0 );
	}

	/**
	 * Bind to the directory server using provided credentials ( or anonymously if none provided )
	 *
	 * This method performs the standard <code>ldap_bind()</code> operation on the ldap link. Before that, it performs
{'fraction_non_alphanumeric': 0.10710396515277688, 'fraction_numerical': 0.006533854333482801, 'mean_word_length': 3.6271487848251334, 'pattern_counts': {'":': 0, '<': 100, '<?xml version=': 0, '>': 134, 'https://': 0, 'lorem ipsum': 0, 'www.': 6, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4757455', 'n_tokens_mistral': 4810, 'n_tokens_neox': 4426, 'n_words': 1832}