December 19, 2014
Hot Topics:

Integrating Active Directory with PHP

  • October 29, 2003
  • By W. Jason Gilmore
  • Send Email »
  • More Articles »

Searching and Manipulating Active Directory Data

In this section, you'll learn how to search and retrieve data from the directory server, as well as add, modify, and delete entries.

ldap_search()

resource ldap_search ( resource link_identifier, string base_dn, string filter [, array attributes [, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]])
The ldap_search() function offers a powerful means for searching the directory server pointed to by link_identifier. It will search to a depth of LDAP_SCOPE_SUBTREE, a value that can be set via the previously introduced function ldap_set_option(). By default, this value is set to search to an infinite depth, or through the entire scope of the tree as defined by the base_dn. The search filter, equivalent to a relational database query, is passed in via the filter parameter. Finally, you can specify exactly which attributes should be returned within the search results via the attributes parameter. The remaining four parameters are optional, and therefore in the interests of space, I'll leave it as an exercise to you to learn more about them. Let's consider an example:

<?php

    $dn = "OU=People,OU=staff,DN=ad,DN=wjgilmore,DN=com";

    $attributes = array("displayname", "l");

    $filter = "(cn=*)";

    $ad = ldap_connect("ldap://ad.wjgilmore.com")
          or die("Couldn't connect to AD!");
  
    ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3);

    $bd = ldap_bind($ad,"ad-web@ad.wjgilmore.com","secret")
          or die("Couldn't bind to AD!");

    $result = ldap_search($ad, $dn, $filter, $attributes);

    $entries = ldap_get_entries($ad, $result);

    for ($i=0; $i<$entries["count"]; $i++)
    {
        echo $entries[$i]["displayname"]
             [0]."(".$entries[$i]["l"][0].")<br />";
    }

    ldap_unbind($ad);

?>

A sampling of the results follow:

Gilmore, Jason (Columbus)
Shoberg, Jon (Columbus)
Streicher, Martin (San Francisco)
Wade, Matt (Orlando)

Most of this is likely straightforward, save for the potentially odd way in which attribute values are referenced. All attribute rows are ultimately multi-dimensional arrays, with each attribute value referenced by a combination of row number, attribute name, and attribute array index. So, for example, even attributes such as "sn", the attribute name for the user's last name, is an indexed array.

ldap_mod_add()

boolean ldap_mod_add(resource link_id, string dn, array entry)
Adding entries to the directory server is accomplished via the ldap_mod_add() function. A new entry is added simply by creating an array consisting of the attribute/value mappings intended to comprise the new row. This process is perhaps best explained with an example:

<?php
    $dn = "OU=People,OU=staff,DN=ad,DN=wjgilmore,DN=com";

    $ad = ldap_connect("ldap://ad.wjgilmore.com")
          or die("Couldn't connect to AD!");

    ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3);

    $bd = ldap_bind($ad,"ad-web@ad.wjgilmore.com","secret") 
          or die("Couldn't bind to AD!");

    $user["givenname"] = "Jason";
    $user["sn"] = "Gilmore";
    $user["mail"][] = "jason@wjgilmore.com";

    $result = ldap_mod_add($ad, $dn, $user);

    if ($result) echo "User added!" else
                 echo "There was a problem!";

    ldap_unbind($ad);

?>

As is the case with all directory server tasks, be sure that the binding user has proper permissions to add the target data; otherwise, errors will occur.

ldap_mod_replace()

boolean ldap_mod_replace(resource link_id, string dn, array entry)
Modifying entry attributes is accomplished via the ldap_mod_replace() function. It operates exactly like ldap_add(), save for the added step of identifying the entry you'd like to modify. This is done by pointing to a very specific dn. Like ldap_add(), both a valid link identifier and an array consisting of the entries you'd like to update must be provided. An example follows, demonstrating how a user's telephone number would be modified. In particular, take note of the very specific DN (pointing to my particular entry).

<?php
    $dn = "CN=Jason Gilmore,OU=People,OU=staff,DN=ad,
           DN=wjgilmore,DN=com";

    $ad = ldap_connect("ldap://ad.wjgilmore.com")
          or die("Couldn't connect to AD!");

    ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3);

    $bd = ldap_bind($ad,"ad-web@ad.wjgilmore.com","secret")
          or die("Couldn't bind to AD!");

    $user["telephonenumber"] = "614-999-9999";

    $result = ldap_mod_replace($ad, $dn, $user);
    if ($result) echo "User modified!" else
                 echo "There was a problem!";

    ldap_unbind($ad);

?>

As is the case with all directory server tasks, be sure that the binding user has proper permissions to modify the target data; otherwise, unexpected errors will occur.

ldap_delete()

boolean ldap_delete(resource link_id, string dn)
Rounding out our survey of key PHP LDAP functions is ldap_delete(). This function is used to delete an existing entry. Like ldap_mod_replace(), a very specific DN must be provided to effect the deletion. The following example demonstrates how to remove the "Jason Gilmore" user entry from Active Directory:

<?php
    $dn = "CN=Jason Gilmore,OU=People,OU=staff,DN=ad,
           DN=wjgilmore,DN=com";

    $ad = ldap_connect("ldap://ad.wjgilmore.com")
          or die("Couldn't connect to AD!");
  
    ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3);

    $bd = ldap_bind($ad,"ad-web@ad.wjgilmore.com","secret") 
          or die("Couldn't bind to AD!");

    $result = ldap_delete($ad, $dn);
    if ($result) echo "User deleted!" else
                 echo "There was a problem!";

    ldap_unbind($ad);

?>

As is the case with all directory server tasks, be sure that the binding user has proper permissions to delete the target data; otherwise, unexpected errors will occur.

Searching Active Directory via the Web

I always like to round out a tutorial with an applicable example that readers can immediately adapt to their own needs. In this tutorial, I'll show you how to create a search interface capable of searching by name, location, or phone number. All you'll need to do is modify the connection variables and base DN. To begin, let's create the search interface, which will be saved as "search.html":

<p>
  <form action="search.html" method="post">
    Search criteria:<br />
    <input type="text" name="keyword" size="20"
           maxlength="20" value="" /><br />
    Filter:<br />
    <select name="filter">
        <option value="">Choose One:</option>
        <option value="sn">Last Name</option>
        <option value="telephonenumber">Phone</option>
        <option value="l">City</option>
    </select><br />
    <input type="submit" value="Search!" />
  </form>
</p>

Figure 1 offers an example of what this search form would look like in the browser.

Figure 1. The Active Directory Search Form

Next, we'll need to create the logic that effects the search. This short bit of code is shown here:

<?php

// Designate a few variables
$host = "ldap://ad.gilmore.com";
$user = "ad-web@ad.wjgilmore.com";
$pswd = "secret";

$ad = ldap_connect($host)
      or die( "Could not connect!" );

// Set version number
ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3)
     or die ("Could not set ldap protocol");

// Binding to ldap server
$bd = ldap_bind($ad, $user, $pswd)
      or die ("Could not bind");

// Create the DN
$dn = "OU=People,OU=staff,DN=ad,DN=wjgilmore,DN=com";

// Specify only those parameters we're interested in displaying
$attrs = array("displayname","mail","telephonenumber");

// Create the filter from the search parameters
$filter = $_POST['filter']."=".$_POST['keyword']."*";

$search = ldap_search($ad, $dn, $filter, $attrs)
          or die ("ldap search failed");

$entries = ldap_get_entries($ad, $search);

if ($entries["count"] > 0) {

for ($i=0; $i<$entries["count"]; $i++) {
   echo "<p>Name: ".$entries[$i]["displayname"][0]."<br />";
   echo "Phone: ".$entries[$i]["telephonenumber"][0]."<br />";
   echo "Email: ".$entries[$i]["mail"][0]."</p>";
}

} else {
   echo "<p>No results found!</p>";
}

ldap_unbind($ad);

?>

You can either change the action destination specified in the search interface, pointing it to a file consisting of the above script, or you can bundle it into the same file as the search interface, and use isset() and an if conditional to trigger execution in the case that the search submit button is depressed. Of course, you'll want to add some additional data validation criteria prior to deploying such a script. Figure 2 offers a sampling of the search results.

Figure 2. Search Results

Conclusion

Although PHP has long been my primary language for developing Web applications, I've found Perl to be an integral part of my programmer's toolkit. When working with directory servers, this sentiment is no different. Therefore, the next article is devoted to Perl/LDAP basics. As was the case with this article, all examples are specific to Microsoft's Active Directory, although you should be able to easily apply them to any directory server implementation. We'll round out that article with an example demonstrating how to create statically cached Web-based user directories using a Perl script and CRON (or Windows Task Scheduler).

I welcome questions and comments! E-mail me at jason@wjgilmore.com. I'd also like to hear more about your experiences integrating Microsoft and Open Source technologies!

About the Author

W. Jason Gilmore (http://www.wjgilmore.com/ ) is an Internet application developer for the Fisher College of Business. He's the author of the upcoming book, PHP 5 and MySQL: Novice to Pro, due out by Apress in 2004. His work has been featured within many of the computing industry's leading publications, including Linux Magazine, O'Reillynet, Devshed, Zend.com, and Webreview. Jason is also the author of A Programmer's Introduction to PHP 4.0 (453pp., Apress). Along with colleague Jon Shoberg, he's co-author of "Out in the Open," a monthly column published within Linux magazine.



Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel