3

Hi this has been going around a little but hopefully I can get some light shone on the problem. Basically I would like to do a search in my active directory using ldap and paginate the results.

I've seen code like this around but it doesn't make any sense to me

// $ds is a valid link identifier (see ldap_connect)
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);

$dn        = 'ou=example,dc=org';
$filter    = '(|(sn=Doe*)(givenname=John*))';
$justthese = array('ou', 'sn', 'givenname', 'mail');

// enable pagination with a page size of 100.
$pageSize = 100;

$cookie = '';
do {
  ldap_control_paged_result($ds, $pageSize, true, $cookie);

  $result  = ldap_search($ds, $dn, $filter, $justthese);
  $entries = ldap_get_entries($ds, $result);

  foreach ($entries as $e) {
    echo $e['dn'] . PHP_EOL;
  }

  ldap_control_paged_result_response($ds, $result, $cookie);

} while($cookie !== null && $cookie != '');

What does this actually do? What is the cookie all about?

I could replace

$result  = ldap_search($ds, $dn, $filter, $justthese); 

with

$result  = ldap_search($ds, $dn, $filter, $justthese,0,100);

Which would do with filter and get me the first 100 rows.

The question in hand is how do I control ldap pagination successfully. i.e giving the number of results to return and the page that I want them from.


Update

Right the code above, I've given it a run and what it does is run the search, several times - returning in each iteration a new page until the end. So it seems that the cookie has some control over that.

2 Answers 2

2

The cookie holds an internal pointer (a ressource) to the currently returned part of the result set. So for the server to know where to continue you have to provide the pointer back as parameter. ThaT is at least currently the case but there are thoughts of changing that. I'll have to do some digging to find the current status of that.

Your second idea of setting the number of returned items to 100 will return the same results over and over again as it sets the maximum number of values that the server will return for each request.

You will have to be carefull with sorting though! currently there is only ldap_sort (which is deprecated as of PHP 7) which sorts the resultset on clientside. But as the pagination is done on the serverside and there currently is no way of doing serversided sorting (we are working on that) the result will not be what you might expect.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for your comments, with ldap and PHP it's good that they are having another go at t in PHP 7 - does feel a little lacking for advanced things. Your comment about the cookie got me thinking, that it could be stored and then used to go back and forth through the pages. It all though would be a little cumbersome and not useable with sorting. I would hence prefer people to look at my answer to get all the results from the search, do the sort (ldap_sort) and then for pagination use array_slice. That is until PHP 7 has been released ldap is given a new lease of life
you might not be able to get all results as there might be a server side limit of the number of returned items which is often 1000. Therefore currently sorting is not considered a good idea on the ldap-side. If you want to do ldap more easily you should have a look at Zend/Ldap as Abstraction layer. It will give you more ease in retrieving the results without needing to get into every detail.
so the search would return 1000 and then the sort would only sort that 1000
yes. Even though there might be more than 1000 results. Thats where the pagination gets interesting. as you always only fetch a few items the server never reaches it's max number and you will eventually get every item. But not sorted. So on the first page you might have a "z" and on the last one an "a"... currently! We are working on it.
Well I guess I'm just lucky that my server doesn't seem to have such restrictions and although I guess the array_slice and the ldap_sort aren't the most efficient, at least it works reasonably quickly. The only other idea that I have is to connect active directory to microsoft sql server, but that's got speed problems as well. I think we can agree that there isn't a ideal solution to this
1

Right, I think the answers are this.

a) The $cookie parameter, is an internal thing to do with searching and pagination, you can't edit/control this (or at least I can't find how).

b) The reason to use the code above is if your server has some restrictions on the amount of users ldap can return.

c) If you do use the code above you might want to search, you can't use ldap_sortbecause this just sorts each page.

d) So that leads you into creating an array and then using a php function e.g asort to sort the array, then to get your page use array_splice

So the solution into ldap pagination is to use some code like this

$filter = "(&(displayName=*".ldap_escape('r')."*)(samaccountname=*)(givenname=*)(sn=*)(lastlogontimestamp=*))";


$justthese = array('ou', 'sn', 'givenname', 'mail');

$sr  = ldap_search($conn['connect'], $conn['base_dn'], $filter, $justthese);
ldap_sort ( $conn['connect'], $sr, 'givenname' ) ; 
$info = ldap_get_entries($conn['connect'], $sr);

$offset = $page_number*$number;
$length = $number;


unset($info['count']);

$info = array_slice ($info, $offset ,$length);


echo '<pre>';
print_r($info);
echo '</pre>';

Just one more thing the ldap_sort, looks a little rubbish because it's case sensitive. I guess you can write your own after you have the results, if it's not your cup of tea. Update - if there is a lot of results this isn't workable, also with the order you are prob best using something like array_reverse

So they you go, not great but workable. Other solutions to try and improve on this is when a search happens query ldap, store the results in a sql table. Let the user manipulate the results (sort/pagination) using the sql table. Each search gets a new set of results for the table. Then you get the speed of the sql table and the benefit of it's sorting/pagination, but the inserting will cost you.

So no great solutions, just a few ideas that kinda work. Hope it helps someone.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.