This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Public License along with this package; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Change Log: 2003.01.29 - display port number with the host name in LDAP tree - fix a bug that LDAP Explorer cann't display entries correctly if the entries in grand children's level and objectclass is not "*". Thanks for suggestions from Jenni Bennett 2002.12.13 - fix a bug that variables $row and $filerecords are undefined. New version PHP complains with it 2001.01.10 - add sorting entries feature while displaying the LDAP tree which required by Jon Fortier - add set_time_limit (0), i.e., no time limit is imposed while script is executed. This hint is generously supported by Sergio Ballestrero 2000.11.16 - rename files from *.php3 to *.php 2000.03.24 - rewrite whole module. two parts: generate tree structure and display tree - search and display subtree feature added - remove entries limitation 2000.03.20 - fix a secure hole in temporary file "/tmp/LE00****". which never check the link is followed. - a bug on solaris that temporary file directory default is "/var/tmp" 2000.03.17 - fix a minor bug that Netscape Directory Server will return "Unable to bind to server" if $bindpw is empty 2000.03.13 - cascading Style Sheet support added - use function rawurlencode () to pass parameters - fix security hold bug in temporary file (including binddn and bindpw) 1999.10.20 - modify the bug that characters ", #, &, + can not as password parameters passed correctly 1999.09.10 - Add expand/collapse feature for base DN; row number for base DN is -1 */ // used to sort entries // Usage: usort ($info, EntryCompare) function EntryCompare ($a, $b) { // $sortfield = "userid"; // if ($a[$sortfield] == $b[$sortfield]) // { // return 0; // } // if ($a[$sortfield] > $b[$sortfield]) // { // return 1; // } // else // { // return -1; // } return strcmp ($a, $b); } function search_subtree ($ds, $dn, $filter) { global $level; global $row; global $ecs; global $dns; global $rdns; global $levels; $subdns_sorted = array (); $sr = ldap_list ($ds, $dn, $filter); $entries_count = ldap_count_entries ($ds, $sr); if ($entries_count == 0) { $newsr = ldap_search ($ds, $dn, $filter); $newentries_count = ldap_count_entries ($ds, $newsr); /* if yes, do a new search. filter is "objectclass=*" */ if ($newentries_count != 0) { $sr = ldap_list ($ds, $dn, "objectclass=*"); $entries_count = ldap_count_entries ($ds, $sr); } else return; } for ($i = 0; $i < $entries_count; $i++) { if ($i == 0) $entry = ldap_first_entry ($ds, $sr); else $entry = ldap_next_entry ($ds, $entry); $newdn = ldap_get_dn ($ds, $entry); $subdns_sorted[$i] = $newdn; } usort ($subdns_sorted, "EntryCompare"); while (list ($key, $newdn) = each ($subdns_sorted)) { $rdn = ldap_explode_dn ($newdn, 0); $newsr = ldap_list ($ds, $newdn, $filter); $newentries_count = ldap_count_entries ($ds, $newsr); if ($newentries_count == 0) { $newsr = ldap_search ($ds, $newdn, $filter); $newentries_count = ldap_count_entries ($ds, $newsr); } if ($newentries_count != 0) { $row++; $dns[$row] = $newdn; $rdns[$row] = $rdn[0]; $ecs[$row] = 0; /* expanded */ $levels[$row] = $level; $level++; search_subtree ($ds, $newdn, $filter); $level--; } } return; } require ("template/header.inc"); require ('default.php'); /* no time limit is imposed while script is executing */ set_time_limit (0); /* levels array */ $levels = array (); /* ecs (expand/collapse) array: 0 - expanded; 1 - collapsed; */ $ecs = array (); /* dns (distinguish name) and rdns (relative distinguish name) array */ $dns = array (); $rdns = array (); /* dns (distinguish name) and array - sorted */ $dns_sorted = array (); /* temporary directory to keep all the temporary files , including tree structure info and mime type files */ $tmpdir = $default->root_html . $default->tmpdir; /* action flag: 0 - initial; 1 - to expand; 2 - to collapse */ $flag = 0; if (isset ($actionID)) { if (strcmp ($actionID, "expand") == 0 ) $flag = 1; elseif (strcmp ($actionID, "collapse") == 0 ) $flag = 2; else echo "Wrong Action!"; /* read all of the content of the file. no need to cal fopen */ $fullcontent = file ($tmpdir . $fileID); $filelength = count ($fullcontent); $filerecords = $filelength / $default->numofrows; } /* generate a temporary file, keep all tree struction info */ $tmpfname = tempnam (".", $default->tmpfile_prefix); // echo "tmpfname = $tmpfname"; /* get rid of nasty prefix in file path "." */ $tmpfname = substr ($tmpfname, 1); $fp = fopen ($tmpdir . $tmpfname, "w+"); /* tree level from 1. display the level 1 of the tree - Base DN */ $level = 1; $ds = ldap_connect ($host, $port); if ($ds) { /* Netscape Directory Server will return "Unable to bind to server" if $bindpw is empty */ if ((strcmp ($binddn, "") == 0) or (strcmp ($bindpw, "") == 0)) $r = ldap_bind ($ds); else $r = ldap_bind ($ds, $binddn, $bindpw); /* get the first half info of the tree */ /* $row will be a parameter if action is expand or collapse */ if (isset ($row)) { for ($i = 1; $i <= $row; $i++) { $levels[$i] = chop ($fullcontent[($i - 1) * $default->numofrows + 0]); $ecs[$i] = chop ($fullcontent[($i - 1) * $default->numofrows + 1]); $dns[$i] = chop ($fullcontent[($i - 1) * $default->numofrows + 2]); $rdns[$i] = chop ($fullcontent[($i - 1) * $default->numofrows + 3]); } } /* initialize OR expand the one branch of the tree */ if (($flag == 0) or ($flag == 1)) { /* if it initilizes LDAP tree */ if ($flag == 0) { /* initialize $row. rows begin at 1 */ $row = 1; $levels[$row] = $level; $ecs[$row] = 0; /* expanded */ $dns[$row] = $basedn; $rdns[$row] = $basedn; } if ($flag == 0) { /* initialize tree */ $searchdn = $basedn; $sr = ldap_list ($ds, $searchdn, $filter); } elseif ($flag == 1) { $searchdn = $dns[$row]; /* expand tree */ $sr = ldap_list ($ds, $searchdn, $filter); $level = $levels[$row]; $ecs[$row] = 0; /* expanded */ } $entries_count = ldap_count_entries ($ds, $sr); /* if there're entries satisfy $filter but not on one level */ if (($entries_count == 0) and (strcmp ($searchscope, "subtree") == 0)) { $newsr = ldap_search ($ds, $searchdn, $filter); $newentries_count = ldap_count_entries ($ds, $newsr); /* if yes, do a new search. filter is "objectclass=*" */ if ($newentries_count != 0) { /* if next level of the tree has the entries */ $sr = ldap_list ($ds, $searchdn, $filter); $entries_count = ldap_count_entries ($ds, $sr); if ($entries_count == 0) { /* in case of Warning: LDAP: Partial search results returned: Sizelimit exceeded. in ... */ $info = ldap_get_entries ($ds, $newsr); // echo "info[count]: " . $info["count"] . "
"; for ($i = 0; $i < $info["count"]; $i++) { // echo "i: " . $i . "
"; // echo "dn: " . $info[$i]["dn"] . "
"; // echo "searchdn: " . $searchdn . "
"; /* entries_count is 0 now */ if (strcmp ($info[$i]["dn"], $searchdn) == 0) { } else { $str1 = substr ($info[$i]["dn"], 0, strpos ($info[$i]["dn"], $searchdn)); $str2 = substr ($str1, 0, strrpos ($str1, ",")); $str3 = trim (substr ($info[$i]["dn"], strrpos ($str2, ",") + 1)); $str4 = trim ($str3); // echo "str1: " . $str1 . "
"; // echo "str2: " . $str2 . "
"; // echo "str3: " . $str3 . "
"; // echo "str4: " . $str4 . "
"; $dns_sorted[$i] = $str4; } } } } } for ($i = 0; $i < $entries_count; $i++) { if ($i == 0) $entry = ldap_first_entry ($ds, $sr); else $entry = ldap_next_entry ($ds, $entry); $dn = ldap_get_dn ($ds, $entry); $dns_sorted[$i] = $dn; } $level++; $oldrow = $row; usort ($dns_sorted, "EntryCompare"); while (list ($key, $dn) = each ($dns_sorted)) { $rdn = ldap_explode_dn ($dn, 0); if (strcmp ($searchscope, "subtree") == 0) { // echo "dn = $dn
"; // echo "filter = $filter
"; $newsr = ldap_list ($ds, $dn, $filter); $newentries_count = ldap_count_entries ($ds, $newsr); /* if yes, do a new search */ if ($newentries_count == 0) { $newsr = ldap_search ($ds, $dn, $filter); $newentries_count = ldap_count_entries ($ds, $newsr); } if ($newentries_count != 0) { $row++; $dns[$row] = $dn; $rdns[$row] = $rdn[0]; $ecs[$row] = 0; /* expanded */ $levels[$row] = $level; $level++; search_subtree ($ds, $dn, $filter); $level--; } } else { $row++; $dns[$row] = $dn; $rdns[$row] = $rdn[0]; $ecs[$row] = 1; /* collapsed */ $levels[$row] = $level; } } } /* end of if (($flag == 0) or ($flag == 1)) */ elseif ($flag == 2) { $ecs[$row] = 1; /* collapsed */ $oldrow = $row; for ($i = $row + 1; $i <= $filerecords; $i++) { $nextlevel = chop ($fullcontent[($i - 1) * $default->numofrows + 0]); if ($nextlevel <= $levels[$row]) { $oldrow = $i - 1; break; } } if ($i > $filerecords) $oldrow = $filerecords; } /* end of else if ($flag == 2) */ /* get the second half info of the tree */ if (isset ($filerecords)) { for ($i = $oldrow + 1; $i <= $filerecords; $i++) { $row++; $levels[$row] = chop ($fullcontent[($i - 1) * $default->numofrows + 0]); $ecs[$row] = chop ($fullcontent[($i - 1) * $default->numofrows + 1]); $dns[$row] = chop ($fullcontent[($i - 1) * $default->numofrows + 2]); $rdns[$row] = chop ($fullcontent[($i - 1) * $default->numofrows + 3]); } } ldap_unbind ($ds); } else { echo "Can not create LDAP connection\n"; } /* display LDAP root at first - host name */ echo "
\n"; echo "\n"; echo "\n"; echo "\n"; echo "\n"; echo "\n"; echo "
 " . $host . " : " . $port . "
\n"; /* display tree $row from 1 */ for ($i = 1; $i <= $row; $i++) { echo "\n"; echo "\n"; echo "\n"; echo "\n"; echo "\n"; echo "
"; /* display blank, vertline images */ for ($j = 1; $j < $levels[$i]; $j++) { if ($j == 1) { echo ""; continue; } /* draw a vertline if there is same level item after it, otherwise draw a blank image */ $k = $i + 1; for ( ; $k <= $row; $k++) { if ($j == $levels[$k]) { echo ""; break; } elseif ($j > $levels[$k]) { echo ""; break; } } if ($k > $row) { echo ""; } } echo ""; if ($ecs[$i] == 0) { for ($j = $i + 1; $j <= $row; $j++) { if ($levels[$i] == $levels[$j]) { echo ""; break; } elseif ($levels[$i] > $levels[$j]) { echo ""; break; } } if ($j > $row) echo ""; echo ""; } elseif ($ecs[$i] == 1) { for ($j = $i + 1; $j <= $row; $j++) { if ($levels[$i] == $levels[$j]) { echo ""; break; } elseif ($levels[$i] > $levels[$j]) { echo ""; break; } } if ($j > $row) echo ""; echo ""; } echo ""; echo "\n"; // echo ""; echo ""; echo $rdns[$i]; echo ""; echo ""; echo "
\n"; fputs ($fp, $levels[$i]); fputs ($fp, "\n"); fputs ($fp, $ecs[$i]); fputs ($fp, "\n"); fputs ($fp, $dns[$i]); fputs ($fp, "\n"); fputs ($fp, $rdns[$i]); fputs ($fp, "\n"); } /* end of for ($i = 1; $i <= $row; $i++) */ fclose ($fp); require ("template/footer.inc"); ?>