EN 
06.12.2025 Mikuláš WELCOME IN MY WORLD

This website is originally written in the Czech language. Most content is machine (AI) translated into English. The translation may not be exact and may contain errors.

Tento článek si můžete zobrazit v originální české verzi. You can view this article in the original Czech version.
Jak na LDAP a LDAPS v PHP pod Windows

How to use LDAP and LDAPS in PHP under Windows

| Petr Bouška - Samuraj |
This article serves as a reminder of the possibilities that PHP gives us. In PHP we can access directory services such as Active Directory, which is useful for many applications (such as intranets). It also shows how to get started using LDAPS under Windows.
displayed: 37 535x (34 090 CZ, 3 445 EN) | Comments [5]

The theoretical description of LDAP is in the article Directory Services and LDAP. If we look at the issue very roughly, the directory is a database and LDAP are functions for accessing the database. Therefore, there's no problem in the theoretical use of LDAP from PHP. For PHP, there's an extension php_ldap that implements LDAP operations.

LDAP

To enable LDAP in PHP on the Windows operating system, we only need to turn on the PHP extension php_ldap. We do this by adding a line to the extension section in the php.ini file (or uncommenting it).

extension=php_ldap.dll

Then we can easily access LDAP. The description of functions is in the manual LDAP Functions, all 9 standard operations from LDAP v3 are implemented here. Some are divided into multiple functions and there are a number of additional functions for easier use. I'll briefly mention the basic functions.

ldap_connect()
Creates a connection to the specified LDAP server, returns a link ID or false. If not specified, the standard port 389 is used for LDAP.
ldap_set_option()
Sets the value of a specified property, such as the LDAP version.
ldap_bind()
Binds to the directory using the link ID. Authentication is performed using a name and password; if not provided, it attempts an anonymous connection. It usually behaves this way even if only the name is filled in and not the password. The server then often returns true, this happens even in the case of AD, even if anonymous connection is not allowed (and further access to the directory is not functional). The name should be entered using DN (CN=User,OU=Users,DC=company,DC=local), but for AD, entering only username (user) or UPN (user@company.local) also works.
ldap_search()
The search operation from LDAP. We specify the starting point of the search and filter, other parameters are optional. Returns a result ID or false.
ldap_get_entries()
One of the ways to get records returned by the search function (and others). Returns a multidimensional array where individual records are and for each record its attributes.
ldap_add()
Inserts a new record with the given DN and specified attributes.
ldap_compare()
Compares an attribute with a value for a given record.
ldap_close()
Correctly terminates the session, it's just an alias to ldap_unbind().

I'm also providing a simple example that connects to AD under a user and performs a simple search and listing of a few values. For proper use, handling of many events etc. is missing.

<?php
function ldapQuery($filter, $baseDN = "OU=company,DC=company,DC=local", $server = "192.168.0.1") {
  $ldapCon = ldap_connect($server);
  if($ldapCon) {
    ldap_set_option($ldapCon, LDAP_OPT_PROTOCOL_VERSION, 3);    // AD supports LDAPv3
    ldap_set_option($ldapCon, LDAP_OPT_REFERRALS, 0);           // it's recommended to turn off referrals for AD
    $res = ldap_bind($ldapCon, "CN=User,OU=Users,DC=company,DC=local", "Password");
    if($res === false) { echo "<p>Authentication failed.</p>";  ldap_close($ldapCon); return false; }
    $rec = ldap_search($ldapCon, $baseDN, $filter); 
    echo "<p>Number of records found: " . ldap_count_entries($ldapCon, $rec) . "</p>";
    $info = ldap_get_entries($ldapCon, $rec);      
    for($i=0; $i<$info["count"]; $i++) {
      echo "DN: ".iconv("UTF-8", "ISO-8859-2", $info[$i]["dn"])."<br />";
      echo "First CN: ".iconv("UTF-8", "ISO-8859-2", $info[$i]["cn"][0])."<br />";
      echo "First email: ".$info[$i]["mail"][0]."<br /><hr />";
    }
    ldap_close($ldapCon);
  } else { echo "<p>Failed to connect to LDAP server.</p>"; ldap_close($ldapCon); return false; }
}
ldapQuery("(memberOf=CN=Group,OU=company,DC=company,DC=local)");
?>

Note: Directory services use UTF-8 encoding, so if we have a different one on the page, we need to convert the values.

Note: If we use diacritics in names (in DN) in AD, we can use characters without diacritics in commands (and then we don't have to deal with the encoding problem).

LDAPS

In normal use of LDAP, communication between the web server and the directory server (I'll consider AD) takes place in an open form and when communication is intercepted, everything is readable. The greatest danger is with the authentication of bind operations.

If authentication is our only problem, we can use the SASL authentication method. If we need to secure all data, we need to encrypt all communication, which we can do either using SSL or TLS. I'll focus on SSL. LDAP that runs over SSL is referred to as LDAPS.

Note: If there's still some important data (for example, user authentication to AD) being sent from the client to the web server, it's good to encrypt this communication as well using SSL (HTTPS).

How to get LDAPS working

  1. LDAPS uses the same library as LDAP, so first we need to enable the php_ldap.dll extension
  2. Because we want to use SSL, we need to get Apache working with SSL, which is described in the article Apache server (EasyPHP) with SSL on Windows.
  3. We must have LDAPS working on the directory server, so the AD server must have a certificate.
  4. The php_ldap.dll library has a hard-coded path to its configuration file, which is C:\openldap\sysconf\ldap.conf (in Linux /etc/openldap/ldap.conf). So we need to create these directories and a file in them, into which we insert the following line
TLS_REQCERT never    // the server certificate is not checked

And that's all, now we can use encrypted LDAPS. To use LDAPS in PHP, it's enough to use the server address ldaps://192.168.0.1 in the ldap_connect function, or specify the standard port 636 ldap_connect("192.168.0.1", 636).

The above procedure is simplified, we don't use a client certificate and we don't check the server certificate. Most guides on the internet contain steps where the root authority certificate, from which the directory server has its certificate, is downloaded. This is converted to PEM format using OpenSSL and added to the ldap.conf configuration file using the TLS_CACERT parameter.

Note: I encountered a problem when Apache was starting and php_ldap.dll was trying to load the certificate, the whole server crashed. Overwriting the php_ldap.dll library from the latest version of PHP (php-4.4.7-Win32.zip) helped.

Debugging

To solve problems with LDAP, we can turn on debug mode. We do this by entering the following command into the code before ldap_connect.

ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);

Subsequently, all operations performed with LDAP are written in detail to the errors.log file of the Apache server.

For example, if we use LDAPS and don't have the certificate correctly or don't use TLS_REQCERT never (for instance when ldap.conf doesn't exist at all), the following error appears in the log and the bind doesn't occur.

TLS certificate verification: Error, unable to get local issuer certificate
TLS trace: SSL3 alert write:fatal:unknown CA

If we don't turn on debug, we won't find out why the bind failed.

Author:

Related articles:

Active Directory and the LDAP protocol

Managing a corporate computer network using Microsoft OS usually means managing Active Directory Domain Services (AD DS). It is a very extensive group of technologies, protocols and services. The basis is directory services, authentication and the LDAP communication protocol.

If you want write something about this article use comments.

Comments
  1. [1] B0biN

    Pekny clanek, diky za nej ;-)

    Saturday, 03.11.2007 16:36 | answer
  2. [2] LaYosH

    Pekne clanky, ale nerozumim tomuto:

    3.Musíme mít zprovozněné LDAPS na adresářovém serveru, takže AD server musí mít certifikát.

    a pak kdyz pouziji:

    "TLS_REQCERT never"

    tak ctu "nekontroluje se certifikát serveru"

    To znamena, ze AD server nemusi mit certifikat pri tomto nastaveni?

    Monday, 15.09.2008 19:52 | answer
  3. [3] Samuraj

    respond to [2]LaYosH: Aby mohla být komunikace šifrovaný (při SSL nebo TLS) tak se využívá certifikát a jeho klíč. Takže vždy tam ten certifikát musí být.

    Druhá věc je, že certifikát se dá použít i k ověření, že server je opravdu ten, za který se vydává. To se provádí na straně klienta, ale tuto kontrolu nemusím použít.

    Friday, 19.09.2008 15:11 | answer
  4. [4] Otto

    Ahoj,

    řeším také tento problém.

    Mám XAMPP, kde SSL funguje (https://localhost běží).

    Ale když se zkusím připojit na ldaps, tak dostanu přesně tu chybu, která je zmíněná na konci textu.

    Žádný z návodů, které jsem našel nezabral.

    Neví někdo, co s tím? (případně: otto.kovarik@gmail.com)

    Wednesday, 05.06.2013 21:53 | answer
  5. [5] JeLiTo

    Díky, to je super článek. S Active Directory všeobecně jsem se pral hrozně dlouhou dobu než sem na je nějak "zdolal":-) Jinak PHP mi přijde jako jeden z nejlepších jazyků, nejen srozumitelně, ale i v rámci nějakýho uplatnění. A nejlépe uplatnění v cizině. Zkoušel jsem najít nějaké weby, které se tím specializují, nevíte nějaké osvědčené? Mě říkal kámoš o itprace-nemecko.cz/,prý mu tam sehnali nějakou brigádu, akorát jsem se ještě nedostal k tomu, abych tam napsal životopis... :D (snad neva ten odkaz, nemyslel jsem to jako spam, spíš jestli s touhle konkrétní firmou má někdo nějaké zkušenosti)

    Monday, 18.11.2013 20:58 | answer
Add comment

Insert tag: strong em link

Help:
  • maximum length of comment is 2000 characters
  • HTML tags are not allowed (they will be removed), you can use only the special tags listed above the input field
  • new line (ENTER) ends paragraph and start new one
  • when you respond to a comment, put the original comment number in squar brackets at the beginning of the paragraph (line)