Added Canvas 1.1.0, originally not under SCM so no historical development records...
[canvas.git] / extensions / LDAP.php
blob31e0e7a58fa39b91d89bce4a3f51946d1b76331b
1 <?php
2 // @title LDAP class
3 // @author Matt Todd <matt@matttoddphoto.com>
4 // @created 2005-11-28
5 // @desc Handles LDAP authentication and information retreival
7 /* @usage
9 // show one completed
13 class LDAP {
14 // properties
15 public $is_connected = false;
16 public $is_bound = false;
17 private $handlers = array();
18 private $results = array();
19 public $count = 0;
20 private $results_order = array();
22 // constructor
23 public function __construct($config = null) {
24 $this->config = (empty($config) ? Config2::$config['adapters']['ldap'] : $config);
27 // accessors
28 public function __get($name) {
29 $entry = current($this->results);
30 return $entry[$name];
32 public function as_array() {
33 return $this->results;
36 // iteration and navigation
37 public function current() {
38 return current($this->results);
40 public function next() {
41 next($this->results);
42 return $this;
44 public function previous() {
45 prev($this->results);
46 return $this;
48 public function first() {
49 reset($this->results);
50 return $this;
52 public function last() {
53 end($this->results);
54 return $this;
57 // data functions
58 protected function full_domain($username = null) {
59 foreach($this->config['domain']['offices'] as $office) { // assemble offices
60 if(!empty($offices)) $offices .= ',';
61 $offices .= sprintf('OU=%s', $office);
63 if($username === null) return "{$offices},DC={$this->config[domain][subdomain]},DC={$this->config[domain][domain]},DC={$this->config[domain][top_level_domain]}";
64 return "CN={$username},{$offices},DC={$this->config[domain][subdomain]},DC={$this->config[domain][domain]},DC={$this->config[domain][top_level_domain]}";
66 protected function short_domain($username = null) {
67 if($username === null) return "{$this->config[domain][short_domain]}";
68 return "{$username}@{$this->config[domain][short_domain]}";
71 // clean results to a sensible structure
72 protected function clean($results) {
73 if(is_array($results)) {
74 // remove 'count' keys
75 if(!empty($results['count'])) unset($results['count']);
77 // if results has only one value, return it
78 if((count($results) == 1) && (!empty($results[0])) && (!is_array($results[0]))) {
79 return $results[0];
82 // cleans repetitive data, et al
83 foreach($results as $key=>$entry) {
84 # (int)0 == "count", so we need to use ===
85 if($k = array_search($key, $results)) unset($results[$k]);
87 // remove all integer keys except for those with valuable data
88 if(is_int($key) && is_string($entry) && is_array($results[$entry])) {
89 unset($results[$key]);
90 continue;
93 // clean children too
94 if(is_array($entry)) {
95 $results[$key] = $this->clean($entry);
99 // return data
100 return $results;
103 // overridden functions
104 public function connect() {
105 // connect to LDAP server
106 if(!($this->handlers['connection'] = ldap_connect($this->config['server']))) { // , 636
107 // could not connect to the LDAP server, throw error
108 throw new Exception("Could not connect to LDAP server {$this->config[server]}");
109 } else {
110 // ldap_set_option($this->handlers['connection'], LDAP_OPT_PROTOCOL_VERSION, 3);
111 // set connection status
112 $this->is_connected = true;
113 return true;
116 public function user_bind($username, $password, $full_domain = false) {
117 // get proper username
118 // $username = (($full_domain) ? $this->full_domain($username) : $this->short_domain($username));
120 // set default bind status
121 $bound = false;
123 // bind to LDAP server
124 // this takes the provided departments and if one level doesn't work, removes it and attempts to bind again
125 while($this->config['domain']['offices']) {
126 if($this->handlers['binding'] = @ldap_bind($this->handlers['connection'], $this->full_domain($username), $password)) {
127 $bound = true;
128 break;
129 } else {
130 array_shift($this->config['domain']['offices']);
133 if(!$bound) {
134 // could not bind to the server as $username
135 throw new Exception("Could not bind the LDAP server as <em>{$username}</em>");
136 } else {
137 // successfully connected and bound server as $username
138 $this->is_bound = true;
139 return true;
142 public function bind($full_domain = false) {
143 // ldap reader binding
144 $username = $this->config['domain']['reader']['username'];
145 $password = $this->config['domain']['reader']['password'];
147 // bind to LDAP server
148 if(!($this->handlers['binding'] = @ldap_bind($this->handlers['connection'], $username, $password))) {
149 // could not bind to the server as $username
150 throw new Exception("Could not bind the LDAP server as <em>{$username}</em>");
151 } else {
152 // successfully connected and bound server as $username
153 $this->is_bound = true;
154 return true;
157 public function disconnect() {
158 // unbind/disconnect LDAP server
159 if(!(ldap_unbind($this->handlers['connection']))) return false;
161 $this->is_bound = false;
162 $this->is_connected = false;
163 $this->handlers['connection'] = null;
165 return true;
167 public function find($params, $full_domain = false) {
168 // remove previous results
169 $this->handlers['results'] = null;
171 // set default params
172 $restrict_to = array();
173 $filter = array();
174 $sort = array();
176 // get settings from config
177 if(!empty($this->config['restrict_to'])) $restrict_to = $this->config['restrict_to'];
178 if(!empty($this->config['filter'])) $filter = $this->config['filter'];
179 if(!empty($this->config['sort'])) $sort = $this->config['sort'];
181 // get parameters for search
182 $domain = (($full_domain) ? $this->full_domain() : $this->short_domain());
183 if(!empty($params['filter'])) $filter = $params['filter']; // such as: "(|(sn=$person*)(givenname=$person*))";
184 if(!empty($params['restrict_to'])) $restrict_to = $params['restrict_to']; // such as: array("ou", "sn", "givenname", "mail");
185 if(!empty($params['sort'])) $sort = $params['sort']; // such as: array("department", "sn");
187 // find
188 $this->handlers['results'] = @ldap_search($this->handlers['connection'], $domain, $filter, $restrict_to);
190 // if sort param set, sort results
191 if(!empty($sort)) {
192 foreach($sort as $key) {
193 @ldap_sort($this->handlers['connection'], $this->handlers['results'], $key);
197 // get entries
198 $results = @ldap_get_entries($this->handlers['connection'], $this->handlers['results']);
200 // get count
201 $this->count = $results['count'];
203 // clean results
204 $results = $this->clean($results);
206 // process results
207 foreach($results as $key=>$entry) {
208 $this->results_order[$key] = $entry['name'];
209 $this->results[$entry['name']] = new entry($entry);
212 // remove results handle
213 $this->handlers['results'] = array();
215 // return this object for more actions
216 return $this;
218 public function locate($name) {
219 return $this->results[$name];
221 public function save($entry, $params = null, $full_domain = false) {
222 // save entry
224 public function insert($params, $entry, $full_domain = false) {
225 // get domain
226 if(empty($params['domain'])) $domain = (($full_domain) ? $this->full_domain() : $this->short_domain()); else $domain = $params['domain'];
228 // insert data
229 if(!(ldap_add($this->handlers['connection'], $domain, $entry))) return false;
231 return true;
233 public function update($params, $entry, $full_domain = false) {
234 // get domain
235 if(empty($params['domain'])) $domain = (($full_domain) ? $this->full_domain() : $this->short_domain()); else $domain = $params['domain'];
237 // insert data
238 if(!(ldap_modify($this->handlers['connection'], $domain, $entry))) return false;
240 return true;
242 public function delete($params, $full_domain = false) {
243 // get domain
244 if(empty($params['domain'])) $domain = (($full_domain) ? $this->full_domain() : $this->short_domain()); else $domain = $params['domain'];
246 // insert data
247 if(!(ldap_delete($this->handlers['connection'], $domain))) return false;
249 return true;
252 // retrieve LDAP error on failures
253 public function error() {
254 return ldap_error($this->handlers['connection']);
258 class entry {
259 private $properties = array();
261 // constructor
262 public function __construct($properties) {
263 $this->properties = $properties;
266 // accessors
267 public function __get($name) {
268 return $this->properties[$name];
270 public function as_array() {
271 return $this->properties;