PHPのお勉強!

PHP TOP

ldap_connect

(PHP 4, PHP 5, PHP 7, PHP 8)

ldap_connectLDAP サーバーへ接続する

説明

ldap_connect(?string $uri = null): LDAP\Connection|false
警告

PHP 8.3.0 以降では、次の シグネチャは推奨されなくなりました。

ldap_connect(?string $host = null, int $port = 389): LDAP\Connection|false

LDAP\Connection クラスのインスタンスを作成し、指定した uri が妥当であるかどうかを調べます。

注意: 注意: この関数は、接続を確立するするわけでは ありません。 指定したパラメータが妥当であり、必要に応じて接続をオープンできるかどうかを調べるだけです。

パラメータ

uri

完全な LDAP URI を指定します。ldap://hostname:port 形式、あるいは SSL を用いる場合は ldaps://hostname:port 形式が使えます。

複数の LDAP URI を指定する場合は、間にスペースをはさんだひとつの文字列とします。

hostname:port 形式は LDAP URI としてサポートされないことに注意しましょう。 スキーマが抜けているからです。

host

接続するホスト名

port

接続するポート。

戻り値

LDAP URI が妥当であると思われる場合には LDAP\Connection クラスのインスタンスを返します。 これは単なる構文チェックであり、実際にサーバーに接続するわけではありません。 構文チェックに失敗した場合は false を返します。 失敗していない場合は、ldap_connect() は常に LDAP\Connection クラスのインスタンスを返しますが、 実際には接続せずにパラメータの初期化だけを行います。 実際に接続するのは次に ldap_* 関数がコールされた際で、これは 通常は ldap_bind() です。

引数が指定されない場合、既に開かれている接続を示す LDAP\Connection クラスのインスタンスを返します。

変更履歴

バージョン 説明
8.3.0 ldap_connect() に、 hostnameport を別々に渡してコールすることは、推奨されなくなりました。
8.1.0 LDAP\Connection クラスのインスタンスを返すようになりました。 これより前のバージョンでは、 リソース を返していました。

例1 LDAP サーバーに接続する例

<?php

// LDAP 変数
$ldapuri = "ldap://ldap.example.com:389"; // ldap-uri

// LDAP に接続します
$ldapconn = ldap_connect($ldapuri)
or die(
"That LDAP-URI was not parseable");

?>

例2 LDAP サーバーへのセキュアな接続の例

<?php

// サーバー証明書が証明するホストであることを
// 確認する
$ldaphost = "ldaps://ldap.example.com/";

// LDAP に接続します
$ldapconn = ldap_connect($ldaphost)
or die(
"That LDAP-URI was not parseable");

?>

参考

  • ldap_bind() - LDAP ディレクトリにバインドする

add a note

User Contributed Notes 27 notes

up
47
nemanja at prolux-universal dot com
10 years ago
If you don't want your PHP program to wait XXX seconds before giving up in a case when one of your corporate DC have failed, and since ldap_connect() does not have a mechanism to timeout on a user specified time, this is my workaround which shows excellent practical results.

===========================================================
function serviceping($host, $port=389, $timeout=1)
{
$op = fsockopen($host, $port, $errno, $errstr, $timeout);
if (!$op) return 0; //DC is N/A
else {
fclose($opanak); //explicitly close open socket connection
return 1; //DC is up & running, we can safely connect with ldap_connect
}
}

// ##### STATIC DC LIST, if your DNS round robin is not setup
//$dclist = array('10.111.222.111', '10.111.222.100', '10.111.222.200');

// ##### DYNAMIC DC LIST, reverse DNS lookup sorted by round-robin result
$dclist = gethostbynamel('domain.name');

foreach ($dclist as $k => $dc) if (serviceping($dc) == true) break; else $dc = 0;
//after this loop, either there will be at least one DC which is available at present, or $dc would return bool false while the next line stops program from further execution

if (!$dc) exit("NO DOMAIN CONTROLLERS AVAILABLE AT PRESENT, PLEASE TRY AGAIN LATER!"); //user being notified

//now, ldap_connect would certainly connect succesfully to DC tested previously and no timeout will occur
$ldapconn = ldap_connect($dc) or die("DC N/A, PLEASE TRY AGAIN LATER.");
===========================================================

Also with this approach, you get a real nice failover functionality, take for an example a company with a dozen of DC-a distributed along distant places, this way your PHP program will always have high availability if at least one DC is active at present.
up
26
Andrew (a.whyte at cqu.edu.au)
21 years ago
To be able to make modifications to Active Directory via the LDAP connector you must bind to the LDAP service over SSL. Otherwise Active Directory provides a mostly readonly connection. You cannot add objects or modify certain properties without LDAPS, e.g. passwords can only be changed using LDAPS connections to Active Directory.

Therefore, for those wishing to securely connect to Active Directory, from a Unix host using PHP+OpenLDAP+OpenSSL I spent some time getting this going myself, and came across a few gotcha's. Hope this proves fruitfull for others like me when you couldn't find answers out there.

Make sure you compile OpenLDAP with OpenSSL support, and that you compile PHP with OpenLDAP and OpenSSL.

This provides PHP with what it needs to make use of ldaps:// connections.

Configure OpenSSL:

Extract your Root CA certificate from Active Directory, this is achived through the use of Certificate Services, a startard component of Windows 2000 Server, but may not be installed by default, (The usual Add/Remove Software method will work here). I extracted this in Base64 not DER format.

Place the extracted CAcert into the certs folder for openssl. (e.g. /usr/local/ssl/certs) and setup the hashed symlinks. This is easily done by simply running:

/usr/local/ssl/bin/c_rehash

Once this is done you can test it is worked by running:

/usr/local/ssl/bin/openssl verify -verbose -CApath /usr/local/ssl/certs /tmp/exported_cacert.pem

(Should return: OK).

Configure OpenLDAP:

Add the following to your ldap.conf file.
(found as /usr/local/openldap/etc/openldap/ldap.conf)

#--begin--

# Instruct client to NOT request a server's cert.
#
# WARNING: This will open up the server vor Man-in-the-middle
# attacs and should *not* be used on production systems or outside
# of test-scenarios!
#
# If you use this setting you will not need any other settings as
# no certificate is requested and therefore will not be validated
#
# For a proper solution check out https://andreas.heigl.org/2020/01/31/handle-self-signed-certificates-with-phps-ldap-extension/
TLS_REQCERT never

# Define location of CA Cert
TLS_CACERT /usr/local/ssl/certs/AD_CA_CERT.pem
TLS_CACERTDIR /usr/local/ssl/certs

#--end--

You also need to place those same settings in a file within the Apache Web user homedir called .ldaprc

e.g.:

cp /usr/local/openldap/etc/openldap/ldap.conf ~www/.ldaprc )

You can then test that you're able to establish a LDAPS connection to Active Directory from the OpenLDAP command tools:

/usr/local/openldap/bin/ldapsearch -H "ldaps://adserver.ad.com"

This should return some output in extended LDIF format and will indicate no matching objects, but it proves the connection works.

The name of the server you're connecting to is important. If they server name you specify in the "ldaps://" URI does not match the name of the server in it's certificate, it will complain like so:

ldap_bind: Can't contact LDAP server (81)
additional info: TLS: hostname does not match CN in peer certificate

Once you've gotten the ldapsearch tool working correctly PHP should work also.

One important gotcha however is that the Web user must be able to locate it's HOME folder. You must check that Apache is providing a HOME variable set to the Web users home directory, so that php can locate the .ldaprc file and the settings contained within. This may well be different between Unix variants but it is such a simple and stupid thing if you miss it and it causes you grief. Simply use a SetEnv directive in Apache's httpd.conf:

SetEnv HOME /usr/local/www

With all that done, you can now code up a simple connect function:

function connect_AD()
{
$ldap_server = "ldaps://adserver.ad.com" ;
$ldap_user = "CN=web service account,OU=Service Accounts,DC=ad,DC=com" ;
$ldap_pass = "password" ;

$ad = ldap_connect($ldap_server) ;
ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3) ;
$bound = ldap_bind($ad, $ldap_user, $ldap_pass);

return $ad ;
}

Optionally you can avoid the URI style server string and use something like ldap_connect("adserver.ad.com", 636) ; But work fine with Active Directory servers.

Hope this proves usefull.
up
3
lee at lareck70 dot net
9 years ago
To use LDAPS on Windows whitout "c:\openldap\sysconf\ldap.conf":
Generate a file like ldap.conf, name it "ldaprc".
For PHP script running on command line put the file to the script.
For PHP script running on webserver put the file in home directory of PHP.
up
7
harrison at glsan dot com
9 years ago
To override the ssl ca file can be done by setting an environmental variable within php.

I found using saving the ca certificate (and intermediate ca's) to a file called ca.pem and then adding

putenv('LDAPTLS_CACERT=./ca.pem');

before ldap_connect works for me.
Code example:
<?php
putenv
('LDAPTLS_CACERT=./ca.pem');
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
$l = ldap_connect("ldaps://ldap/");
ldap_set_option($l, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_bind($l, "cn=apache,dc=example", "xxxxxxx");
echo(
ldap_error($l)."\n");
$s = ldap_search($l, "dc=example", "uid=test");
echo(
ldap_count_entries($l, $s)."\n");
?>
in the file ca.pem in the same directory we have our ca's:
-----BEGIN CERTIFICATE-----
<cert here>
-----END CERTIFICATE-----
up
2
peter dot burden at gmail dot com
15 years ago
The host name parameter can be a space separated list of host names. This means that the LDAP code will talk to a backup server if the main server is not operational. There will be a delay while the code times out trying to talk to the main server but things will still work. This is particularly useful with a typical Microsoft Active Directory setup of primary and backup domain controllers.
<?php
$ldaphost
= "192.168.0.100 192.168.0.101";
$ldapconn = ldap_connect($ldaphost);
?>
up
3
mwilmes at avc dot edu
9 years ago
I support a LAMP stack with PHP-FPM on CentOS 7 that needs to connect to Active Directory over SSL. We have a root certificate for the domain. I was able to set this up in five steps.

1. Get the domain's root SSL certificate in base64. (Must be an Enterprise Administrator - talk with your admin if you are not one.)
Run mmc.exe
File -> Add/Remove Snap-in
Select Certification Authority, then the server that generates certificates for your domain.
Expand the tree until you find the entry for the root certificate, then right click->Properties.
Click the "View Certificate" button, The "Details" tab, then the "Copy to File..." button.
Use the wizard to export the root certificate to your computer. Ensure you use the Base-64 format.

2. Copy the root cert to the Linux server. You can open the certificate in notepad and copy and paste the contents.

3. Convert the certificate to pem format. Substitute the names of files as needed.
openssl x509 -in <copied certificate file> -out /etc/openldap/certs/<cert>.pem

4. Add a line in ldap.conf to use new root cert.
vi /etc/openldap/ldap.conf
TLS_CACERT /etc/openldap/certs/<cert>.pem

5.Restart the PHP service.
systemctl restart php-fpm.service
up
1
blizzards at libero dot it
20 years ago
To complete questions about how to connect to a LDAP ACTIVE DIRECTORY 2000/2003 server with SASL on port 636, you can refer to prevous notes, and the following directives:

A)Create CA certificates from AD;
B)Export in .pem (DER) format;
C)Install OPENSSL,CYRUS SASL,OPENLDAP,KERBEROS 5;
D)Copy exported AD ca cert into openssl certs dir on your unix system;
E)Reash with c_reash command;
F)Get a kerberos ticket form AD for your user;
G)Compile PHP with SSL and LDAP support;
H)Test with ldapsearch -D <binddn> -W -H ldaps://ad.secure.com:636 -x

If all works right, create your php script.

Note: For writing parameters to AD you need to renew ticket each 10 hours or less (AD default lifetime ticket), for reading pourpose you can maintain expired ticket.
When querying a windows 2000/2003 AD you MUST use only SASL and not TLS (non supported).
up
1
nateshull at gmail dot com
4 years ago
Implementing LDAPS on a WISP stack - Win, IIS, SQL, PHP
PHP 7.0.19:

Had some issues with some of the instructions and I needed LDAPS for an upcoming Active Directory update that removes insecure LDAP connections.

Enable modules for ldap and openssl in php.ini

Also ensure the extensions are in the ext folder

Verify the modules are loaded: phpinfo()

Notes:
The ldap or openssl config file is not needed if the environment variables are set in the code. Also the ca path does not like double quotations around the path.

*** code sample:

<?php
$ldapuser
= "domain\\user";
$ldappass = "Passsword";
$ldapserver = "ldaps://server.domain.com";

//options are require, never, allow
//require is most secure, the others could allow for man in the middle attacks
putenv('LDAPTLS_REQCERT=require');

//tell ldap where the root ca certificate is
//note that the space is allowed in the path without escape or quotes
//I have not tested the permissions, but I would assume the service should have read.
putenv('LDAPTLS_CACERT=C:\\Program Files\\php\\certs\\rootca.pem');

//test to ensure the certificate is able to be read and path is right.
echo file_get_contents("LDAPTLS_CACERT=C:\\Program Files\\php\\certs\\rootca.pem");

// Set debugging
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);

// connect to ldap server
$ldapconn = ldap_connect($ldapserver) or die ("Couldn't connect");

// binding to ldap server
$ldapbind = false;
$ldapbind = ldap_bind($ldapconn, $ldapuser, $ldappass);

//easy view of success or failure
if ($ldapbind) {
print(
"\n logged in! \n\n");
} else {
print(
"\n log on failure \n\n");
}
?>
up
2
Nixahnung
9 years ago
I have spent a lot of time to make an LDAPS connection to a MS AD Global Catalog port 3269

My five Cents:

ldap_connect("ldaps://example.com", 3269)
=> Connection to 636.... :(, DC only

ldap_connect("ldaps://example.com:3269")
=> Connection to 3269.... :), GC as expected

May it helps...
up
2
avel at noc uoa gr
22 years ago
Note that hostname can be a space-separated list of LDAP host names. This is very useful for failover; if the first ldap host is down, ldap_connect will ask the second LDAP host. Of course, you _must_ have LDAP replicates before doing this. :) Read the LDAP API documentation for more information.

This can also be useful, apart from failover, for LDAP load balancing. Just use a random generator function that will return a different space-separated list every time. This is because the first host in the list is always tried first.

Be careful when doing LDAP writes; be sure to always connect to your master host when you are about to modify the database, so that the replicates will get the changes as expected.

Alexandros Vellis
up
1
allie at lsu dot edu
17 years ago
I sure do wish there was some way I could get this information out to all programmers in the world about binding and searching MS AD. This is the second time I was bit by the "I need to search the entire tree" problem.

For php (and apache auth_ldap ) you need to specify port 3268 when you want to search the entire tree. Otherwise it will spit out the partial results error.

ldap_connect($server,3268);

I'm just fortunate enough to have won this same battle with apache searching the whole directory. When I noticed our php application failing auth's for users, I was immediately able to fix the problem by adding this port specification (and the ldap_set_option($ldapserver, LDAP_OPT_REFERRALS, 0) option).

I really hope this helps someone else before they pull all their hair out. I know I miss mine.
up
0
heiglandreas at php dot net
9 months ago
If you have trouble using TLS on ldap-conjnect: Despite what a lot of people are saying: TLS_REQCERT=never is NEVER the correct answer.

Check out https://andreas.heigl.org/2020/01/31/handle-self-signed-certificates-with-phps-ldap-extension/ for the solution to do it with propper certificate checking!
up
0
titanrat at bk dot ru
7 years ago
I found some difference between php7.0 and php5.5 on this function

Php5 ldap_connect ('host', 0) try to connect default port - host:389
Php7 ldap_connect ('host', 0) try to connect host:0 and crashes.
up
0
antoine dot php dot net at bonnefoy dot eu
9 years ago
Hello,

Little corrections to nemanja post.
- There was a warning if connection is denied by firewall (adding @ before fsockopen)
- fclose parameter was incorrect.

With this approach, you get a real nice failover functionality, take for an example a company with a dozen of DC-a distributed along distant places, this way your PHP program will always have high availability if at least one DC is active at present.
<?php
function serviceping($_host, $_port = 389, $_timeout = 1) {
$op = @fsockopen($_host, $_port, $errno, $errstr, $_timeout);
if (!
$op) {
echo
"KO!";
return
0;

}
//DC is N/A
else {
fclose($op); //explicitly close open socket connection
return 1; //DC is up & running, we can safely connect with ldap_connect
}
}

function
ldap_connect_failover($_domain) {
// ##### STATIC DC LIST, if your DNS round robin is not setup
//$dclist = array('10.111.222.111', '10.111.222.100', '10.111.222.200');
// ##### DYNAMIC DC LIST, reverse DNS lookup sorted by round-robin result
$dclist = gethostbynamel($_domain);

foreach (
$dclist as $dc) {
if (
serviceping($dc) == true) {
break;
} else {
$dc = 0;
}
}
//after this loop, either there will be at least one DC which is available at present, or $dc would return bool false while the next line stops program from further execution

if (!$dc) {
return
false;
}
//user being notified

return ldap_connect($dc);
}
?>
up
0
TheThinkingMan
9 years ago
I have spent hours and hours trying to get an LDAPS connection happening with my local AD LDS instance (running on Windows 8.1 64bit).

I tried certificate after certificate. OpenSSL, Thawte and Self-signed - all with no success.

I ended up deleting all of my certificates and created a Self-signed certificate using IIS 7 (running on Windows 8.1).

I then downloaded the Softerra LDAP browser and it was able to connect to my AD LDS instance via SSL with no problems.

Sure if it could PHP could.

I used the following code to connect:
<?php
$ldap_server
= "ldaps://delllappy:636";
$ldap_conn = ldap_connect($ldap_server) or die("Failed to connect to LDAP server.");
?>
I added the following above the ldap_connect:
<?php
putenv
('LDAPTLS_REQCERT=allow');
putenv("LDAPCONF=C:\OpenLDAP\sysconf\ldap.conf");
?>

That did nothing.

The ldap_bind command I used was:
<?php
if (!ldap_bind($ldap_conn, $ldap_user, $ldap_pass)) {
echo
"error";
}else{
echo
"success";
}
?>
BTW: I added a heap of debug in the code too - which is referenced elsewhere - so I didn't add it in here.

The error that I kept on getting was:
Error Binding to LDAP: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

I then ran ProcMon (Process Monitor from Microsoft).

I monitored when I restarted my web server (Z-WAMP). At that point there was no attempt to read ldap.conf.

I then loaded up my web page with my test.php file.

At that point I noticed that it was ldap.conf that was being read but openldap.conf.

Of course as my file was called ldap.conf, openldap.conf failed. I renamed my ldap.conf to openldap.conf and everything worked.

On Z-WAMP running OpenLDAP don't used ldap.conf, use openldap.conf.

The openldap.conf file was placed in C:\openldap\sysconf\.

As the PUTENV values did not do anything, I removed them.