PageRenderTime 23ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/ldap_services.php

https://github.com/dmolsen/MIT-Mobile-Web
PHP | 358 lines | 262 code | 60 blank | 36 comment | 37 complexity | 0345b02cbeae4ec7592473e0aecb7365 MD5 | raw file
  1. <?
  2. /**
  3. * Copyright (c) 2008 Massachusetts Institute of Technology
  4. *
  5. * Licensed under the MIT License
  6. * Redistributions of files must retain the above copyright notice.
  7. *
  8. */
  9. ## CONFIGURE BASIC LDAP CONNECTION INFO ##
  10. define("SERVER", "ldap.wvu.edu");
  11. define("DN","ou=people,dc=wvu,dc=edu");
  12. ## USING LDAP BIND FOR PASSWORD PROTECTED LDAP IS NOT TESTED ##
  13. define("AUTH",false); # use authentication?
  14. define("USER","cn=webservices,ou=people,dc=heu,dc=edu");
  15. define("PASS","password");
  16. ## look at line 205 to edit how your LDAP fields match display keys
  17. function mit_search($search) {
  18. $results = do_query(standard_query($search));
  19. if($email_query = email_query($search)) {
  20. $results = do_query($email_query, $results);
  21. }
  22. return order_results($results, $search);
  23. }
  24. function order_results($results, $search) {
  25. $low_priority = array();
  26. $high_priority = array();
  27. foreach($results as $result) {
  28. $item = make_person($result);
  29. if(has_priority($item, $search)) {
  30. $high_priority[] = $item;
  31. } else {
  32. $low_priority[] = $item;
  33. }
  34. }
  35. usort($low_priority, "compare_people");
  36. return array_merge($high_priority, $low_priority);
  37. }
  38. function has_priority($item, $search) {
  39. $words = explode(' ', trim($search));
  40. if(count($words) == 1) {
  41. $word = strtolower($words[0]);
  42. $emails = $item['email'];
  43. foreach($emails as $email) {
  44. $email = strtolower($email);
  45. if( ($email == $word) ||
  46. (substr($email, 0, strlen($word)+1) == "$word@") ) {
  47. return True;
  48. }
  49. }
  50. }
  51. return False;
  52. }
  53. function email_query($search) {
  54. $words = explode(' ', trim($search));
  55. if(count($words) == 1) {
  56. $word = $words[0];
  57. if(strpos($words, '@') === False) {
  58. //turns blpatt into blpatt@*
  59. $word .= '@*';
  60. }
  61. return new QueryElement('mail', $word);
  62. }
  63. }
  64. function standard_query($search) {
  65. //remove commas and periods
  66. $search = str_replace(',', ' ', $search);
  67. $search = str_replace('.', '*', $search);
  68. $query = new JoinAndQuery();
  69. foreach(split(" ", $search) as $word) {
  70. if($word != "") {
  71. $token_query = new LdapOrFilter();
  72. if(strlen($word) == 1) {
  73. //handle the special case of first initials
  74. $query_word = "$word*";
  75. //check for first or middle initial
  76. $token_query->_OR("cn", "$word*");
  77. /*****************************************************
  78. * an ugly hack which forces ldap not to ignore spaces
  79. *****************************************************/
  80. for($cnt = 0; $cnt < 26; $cnt++) {
  81. $chr = chr(ord('a') + $cnt);
  82. $token_query->_OR("cn", "*$chr $word*");
  83. }
  84. $token_query->_OR("cn", "*-$word*");
  85. } else {
  86. $query_word = "*$word*";
  87. }
  88. $token_query
  89. ->_OR('cn', $query_word)
  90. ->_OR('mail', $query_word);
  91. //remove all non-digits from phone number before
  92. //attempting phone number searches
  93. $phone_word = '*' . preg_replace('/\D/', '', $word) . '*';
  94. if(strlen($phone_word) >= 5) {
  95. $token_query
  96. ->_OR('homePhone', $phone_word)
  97. ->_OR('telephoneNumber', $phone_word)
  98. ->_OR('facsimileTelePhonenumber', $phone_word);
  99. }
  100. $query->_AND($token_query);
  101. }
  102. }
  103. return $query;
  104. }
  105. function do_query($query, $search_results=array()) {
  106. $ds = ldap_connect(SERVER) or ldap_die("cannot connect");
  107. if (AUTH == true) {
  108. $ldapbind = ldap_bind($ds, USER, PASS);
  109. }
  110. //turn off php Warnings, during ldap search
  111. //since it complains about search that go over the limit of 100
  112. $error_reporting = ini_get('error_reporting');
  113. error_reporting($error_reporting & ~E_WARNING);
  114. $sr = ldap_search($ds, DN, $query->out())
  115. or ldap_die("could not search");
  116. error_reporting($error_reporting);
  117. $entries = ldap_get_entries($ds, $sr)
  118. or ldap_die("could not get entries");
  119. for ($i = 0; $i < $entries["count"]; $i++) {
  120. $entry = $entries[$i];
  121. //some ldap entries have no usefull information
  122. //we dont want to return those
  123. if(lkey($entry, "sn", True)) {
  124. //if one person has multiple ldap records
  125. //this code attempts to combine the data in the records
  126. if($old = $search_results[id_key($entry)]) {
  127. } else {
  128. $old = array();
  129. }
  130. $search_results[id_key($entry)] = array_merge($old, $entry);
  131. }
  132. }
  133. return $search_results;
  134. }
  135. /*********************************************
  136. *
  137. * this function compares people by firstname then lastname
  138. *
  139. *********************************************/
  140. function compare_people($person1, $person2) {
  141. if($person1['surname'] != $person2['surname']) {
  142. return ($person1['surname'] < $person2['surname']) ? -1 : 1;
  143. } elseif($person1['givenname'] == $person2['givenname']) {
  144. return 0;
  145. } else {
  146. return ($person1['givenname'] < $person2['givenname']) ? -1 : 1;
  147. }
  148. }
  149. function lookup_username($id) {
  150. if(strstr($id, '=')) {
  151. //look up person by "dn" (distinct ldap name)
  152. $ds = ldap_connect(SERVER);
  153. $sr = ldap_read($ds, $id, "(objectclass=*)");
  154. $entries = ldap_get_entries($ds, $sr);
  155. return make_person($entries[0]);
  156. } else {
  157. $tmp = do_query(new QueryElement("uid", $id));
  158. foreach($tmp as $key => $first) {
  159. return make_person($first);
  160. }
  161. }
  162. }
  163. function lkey($array, $key, $single=False) {
  164. if($single) {
  165. return $array[$key][0];
  166. } else {
  167. $result = $array[$key];
  168. if($result === NULL) {
  169. return array();
  170. }
  171. unset($result["count"]);
  172. return $result;
  173. }
  174. }
  175. function id_key($info) {
  176. if($username = lkey($info, "uid", True)) {
  177. return $username;
  178. } else {
  179. return $info["dn"];
  180. }
  181. }
  182. function make_person($info) {
  183. $person = array(
  184. "surname" => lkey($info, "sn"),
  185. "givenname" => lkey($info, "givenname"),
  186. "fullname" => lkey($info, "cn"),
  187. "title" => lkey($info, "title"),
  188. "dept" => lkey($info, "department"),
  189. "affiliation" => lkey($info, "wvuptype"),
  190. "address" => lkey($info, "postaladdress"),
  191. "homephone" => lkey($info, "homephone"),
  192. "email" => lkey($info, "mail"),
  193. "room" => lkey($info, "roomnumber"),
  194. "id" => id_key($info),
  195. "telephone" => lkey($info, "telephonenumber"),
  196. "fax" => lkey($info, "facsimiletelephonenumber"),
  197. "office" => lkey($info, "physicaldeliveryofficename")
  198. );
  199. foreach($person["office"] as $office) {
  200. if(!in_array($office, $person["room"])) {
  201. $person["room"][] = $office;
  202. }
  203. }
  204. return $person;
  205. }
  206. /** *
  207. * a series of classes alowing for the construction *
  208. * of ldap queries *
  209. * */
  210. abstract class LdapQuery {
  211. abstract public function out();
  212. public static function escape($str) {
  213. $specials = array("*", "+", "=" , ",");
  214. foreach($specials as $special) {
  215. $str = str_replace($special, "\\" . $special, $str);
  216. }
  217. return $str;
  218. }
  219. }
  220. class LdapQueryList extends LdapQuery {
  221. protected $symbol;
  222. protected $queries=array();
  223. public function out() {
  224. $out = '(' . $this->symbol;
  225. foreach($this->queries as $query) {
  226. $out .= $query->out();
  227. }
  228. $out .= ')';
  229. return $out;
  230. }
  231. }
  232. class QueryElementList extends LdapQueryList {
  233. public function __construct($cond_arr=array()) {
  234. foreach($cond_arr as $field => $value) {
  235. $this->add($field, $value);
  236. }
  237. }
  238. public function add($field, $value) {
  239. $this->queries[] = new QueryElement($field, $value);
  240. return $this;
  241. }
  242. }
  243. class LdapAndFilter extends QueryElementList {
  244. protected $symbol = '&';
  245. public function _AND($field, $value) {
  246. return $this->add($field, $value);
  247. }
  248. }
  249. class LdapOrFilter extends QueryElementList {
  250. protected $symbol = '|';
  251. public function _OR($field, $value) {
  252. return $this->add($field, $value);
  253. }
  254. }
  255. class JoinQuery extends LdapQueryList {
  256. public function __construct() {
  257. $this->queries = func_get_args();
  258. }
  259. }
  260. class JoinAndQuery extends JoinQuery {
  261. protected $symbol = '&';
  262. public function _AND(LdapQuery $query) {
  263. $this->queries[] = $query;
  264. return $this;
  265. }
  266. }
  267. class JoinOrQuery extends JoinQuery {
  268. protected $symbol = '|';
  269. public function _OR(LdapQuery $query) {
  270. $this->queries[] = $query;
  271. return $this;
  272. }
  273. }
  274. class QueryElement extends LdapQuery {
  275. protected $field;
  276. protected $value;
  277. public function __construct($field, $value) {
  278. $this->field = $field;
  279. //convert all multiple wildcards to a single wildcard
  280. $this->value = preg_replace('/\*+/', '*', $value);
  281. }
  282. public function out() {
  283. return '(' . $this->field . '=' . $this->value . ')';
  284. }
  285. }
  286. class RawQuery extends LdapQuery {
  287. protected $raw_query;
  288. public function __construct($raw_query) {
  289. $this->raw_query = $raw_query;
  290. }
  291. public function out() {
  292. return $this->raw_query;
  293. }
  294. }
  295. function ldap_die($message) {
  296. return $message;
  297. }
  298. ?>