How to sort LDAP Result with LDAP filter?

Viewed 2178

I'm creating a LDAP directory search using PHP.

I'm able to successfully search and return results.

I want to be able to sort results according to hierarchy. Now I have:

 ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com  
 ou=IT,ou=Employees,ou=People,dc=instatsport,dc=com  
 ou=Video,ou=Employees,ou=People,dc=instatsport,dc=com  
 ou=HR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com  
 ou=aHR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com  
 ou=HR2,ou=HR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com

Using php.net/manual/en/function.ldap-sort.php what filter should be applied to get this result?:

ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com
ou=HR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com
ou=HR2,ou=HR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com
ou=aHR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com
ou=IT,ou=Employees,ou=People,dc=instatsport,dc=com
ou=Video,ou=Employees,ou=People,dc=instatsport,dc=com 
2 Answers

You can't with ldap_sort.

What this function do is apply an strcmp on an attribute of the entries returned.

Here you try to order the DN of the entries returned, and not on an alphabetical way, but on the hierarchical level.

You have to implement this (or find someone who already did this).

The easiest implementation would be to create a tree with all the RDN and print this tree from root to leaf recursively imploding each RDN with a comma.

EDIT :

I took some time to try to implement it quickly, this is not the best code you can find, but it can ba a base for what you want to achieve :

function hierarchySort ($a, $b){
        $rdn1 = ldap_explode_dn($a,0);
        $rdn2 = ldap_explode_dn($b,0);

        $count = $rdn1["count"] < $rdn2["count"] ? $rdn1["count"] : $rdn2["count"];

        for ($i=0; $i<$count; $i++) {
                $j1 = $rdn1["count"] - 1 - $i;
                $j2 = $rdn2["count"] - 1 - $i;
                $ret = strnatcasecmp($rdn1[$j1], $rdn2[$j2]);
                if ($ret != 0) break;
        }

        if ($rdn1["count"] == $rdn2["count"]) {
                return $ret;
        }else {
                if ($ret != 0) return $ret;
                else return  $rdn1["count"] < $rdn2["count"] ? -1 : 1;
        }
}

// Some simulated LDAP result
$entries = [
        0 => [ "dn" => "ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com" ],
        1 => [ "dn" => "ou=IT,ou=Employees,ou=People,dc=instatsport,dc=com" ],
        2 => [ "dn" => "ou=Video,ou=Employees,ou=People,dc=instatsport,dc=com" ],
        3 => [ "dn" => "ou=HR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com" ],
        4 => [ "dn" => "ou=aHR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com" ],
        5 => [ "dn" => "ou=HR2,ou=HR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com" ],
        "count" => 6
];

for ($i=0; $i<$entries['count']; $i++) {
        $e = $entries[$i];
        $dns[] = $e["dn"];
}

print_r($dns);
usort($dns, 'hierarchySort');
print_r($dns);

Ouput :

Array
(
    [0] => ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com
    [1] => ou=IT,ou=Employees,ou=People,dc=instatsport,dc=com
    [2] => ou=Video,ou=Employees,ou=People,dc=instatsport,dc=com
    [3] => ou=HR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com
    [4] => ou=aHR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com
    [5] => ou=HR2,ou=HR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com
)
Array
(
    [0] => ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com
    [1] => ou=aHR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com
    [2] => ou=HR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com
    [3] => ou=HR2,ou=HR1,ou=HR,ou=Employees,ou=People,dc=instatsport,dc=com
    [4] => ou=IT,ou=Employees,ou=People,dc=instatsport,dc=com
    [5] => ou=Video,ou=Employees,ou=People,dc=instatsport,dc=com
)

ldap_sort is deprecated by now as it only sorts the result set returned by the server. For small result sets that might not be an issue, but on larger (paged) result sets that means that you get results from "a" to "z" on the first page which will then be sorted. And on the second page you will also get results from "a" to "z" that will then be sorted and so on. Therefore the sort does not really what most people expect.

Also ldap_sort can only sort on fields that where actually retrieved. So you are not able to only retrieve the "first name" and sort by "second name".

To answer your question: I would write a sort function like the following and use that with f.e. usort:

function sortByDn($a, $b) {
    return strnatcasecmp($a['dn'], $b['dn']);
}


$result = ldap_get_Entries($handle, $resulthandle);
unset($result['count']);
usort($result, 'sortByDn');

Something along these lines might actually help ;)

Depending on what you want to sort by your sort function might need to be different!

Related