|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_Ldap |
|
17 * @subpackage Schema |
|
18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
19 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
20 * @version $Id: OpenLdap.php 20096 2010-01-06 02:05:09Z bkarwin $ |
|
21 */ |
|
22 |
|
23 /** |
|
24 * @see Zend_Ldap_Node_Schema |
|
25 */ |
|
26 require_once 'Zend/Ldap/Node/Schema.php'; |
|
27 /** |
|
28 * @see Zend_Ldap_Node_Schema_AttributeType_OpenLdap |
|
29 */ |
|
30 require_once 'Zend/Ldap/Node/Schema/AttributeType/OpenLdap.php'; |
|
31 /** |
|
32 * @see Zend_Ldap_Node_Schema_ObjectClass_OpenLdap |
|
33 */ |
|
34 require_once 'Zend/Ldap/Node/Schema/ObjectClass/OpenLdap.php'; |
|
35 |
|
36 /** |
|
37 * Zend_Ldap_Node_Schema_OpenLdap provides a simple data-container for the Schema node of |
|
38 * an OpenLDAP server. |
|
39 * |
|
40 * @category Zend |
|
41 * @package Zend_Ldap |
|
42 * @subpackage Schema |
|
43 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
44 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
45 */ |
|
46 class Zend_Ldap_Node_Schema_OpenLdap extends Zend_Ldap_Node_Schema |
|
47 { |
|
48 /** |
|
49 * The attribute Types |
|
50 * |
|
51 * @var array |
|
52 */ |
|
53 protected $_attributeTypes = null; |
|
54 /** |
|
55 * The object classes |
|
56 * |
|
57 * @var array |
|
58 */ |
|
59 protected $_objectClasses = null; |
|
60 /** |
|
61 * The LDAP syntaxes |
|
62 * |
|
63 * @var array |
|
64 */ |
|
65 protected $_ldapSyntaxes = null; |
|
66 /** |
|
67 * The matching rules |
|
68 * |
|
69 * @var array |
|
70 */ |
|
71 protected $_matchingRules = null; |
|
72 /** |
|
73 * The matching rule use |
|
74 * |
|
75 * @var array |
|
76 */ |
|
77 protected $_matchingRuleUse = null; |
|
78 |
|
79 /** |
|
80 * Parses the schema |
|
81 * |
|
82 * @param Zend_Ldap_Dn $dn |
|
83 * @param Zend_Ldap $ldap |
|
84 * @return Zend_Ldap_Node_Schema Provides a fluid interface |
|
85 */ |
|
86 protected function _parseSchema(Zend_Ldap_Dn $dn, Zend_Ldap $ldap) |
|
87 { |
|
88 parent::_parseSchema($dn, $ldap); |
|
89 $this->_loadAttributeTypes(); |
|
90 $this->_loadLdapSyntaxes(); |
|
91 $this->_loadMatchingRules(); |
|
92 $this->_loadMatchingRuleUse(); |
|
93 $this->_loadObjectClasses(); |
|
94 return $this; |
|
95 } |
|
96 |
|
97 /** |
|
98 * Gets the attribute Types |
|
99 * |
|
100 * @return array |
|
101 */ |
|
102 public function getAttributeTypes() |
|
103 { |
|
104 return $this->_attributeTypes; |
|
105 } |
|
106 |
|
107 /** |
|
108 * Gets the object classes |
|
109 * |
|
110 * @return array |
|
111 */ |
|
112 public function getObjectClasses() |
|
113 { |
|
114 return $this->_objectClasses; |
|
115 } |
|
116 |
|
117 /** |
|
118 * Gets the LDAP syntaxes |
|
119 * |
|
120 * @return array |
|
121 */ |
|
122 public function getLdapSyntaxes() |
|
123 { |
|
124 return $this->_ldapSyntaxes; |
|
125 } |
|
126 |
|
127 /** |
|
128 * Gets the matching rules |
|
129 * |
|
130 * @return array |
|
131 */ |
|
132 public function getMatchingRules() |
|
133 { |
|
134 return $this->_matchingRules; |
|
135 } |
|
136 |
|
137 /** |
|
138 * Gets the matching rule use |
|
139 * |
|
140 * @return array |
|
141 */ |
|
142 public function getMatchingRuleUse() |
|
143 { |
|
144 return $this->_matchingRuleUse; |
|
145 } |
|
146 |
|
147 /** |
|
148 * Loads the attribute Types |
|
149 * |
|
150 * @return void |
|
151 */ |
|
152 protected function _loadAttributeTypes() |
|
153 { |
|
154 $this->_attributeTypes = array(); |
|
155 foreach ($this->getAttribute('attributeTypes') as $value) { |
|
156 $val = $this->_parseAttributeType($value); |
|
157 $val = new Zend_Ldap_Node_Schema_AttributeType_OpenLdap($val); |
|
158 $this->_attributeTypes[$val->getName()] = $val; |
|
159 |
|
160 } |
|
161 foreach ($this->_attributeTypes as $val) { |
|
162 if (count($val->sup) > 0) { |
|
163 $this->_resolveInheritance($val, $this->_attributeTypes); |
|
164 } |
|
165 foreach ($val->aliases as $alias) { |
|
166 $this->_attributeTypes[$alias] = $val; |
|
167 } |
|
168 } |
|
169 ksort($this->_attributeTypes, SORT_STRING); |
|
170 } |
|
171 |
|
172 /** |
|
173 * Parses an attributeType value |
|
174 * |
|
175 * @param string $value |
|
176 * @return array |
|
177 */ |
|
178 protected function _parseAttributeType($value) |
|
179 { |
|
180 $attributeType = array( |
|
181 'oid' => null, |
|
182 'name' => null, |
|
183 'desc' => null, |
|
184 'obsolete' => false, |
|
185 'sup' => null, |
|
186 'equality' => null, |
|
187 'ordering' => null, |
|
188 'substr' => null, |
|
189 'syntax' => null, |
|
190 'max-length' => null, |
|
191 'single-value' => false, |
|
192 'collective' => false, |
|
193 'no-user-modification' => false, |
|
194 'usage' => 'userApplications', |
|
195 '_string' => $value, |
|
196 '_parents' => array()); |
|
197 |
|
198 $tokens = $this->_tokenizeString($value); |
|
199 $attributeType['oid'] = array_shift($tokens); // first token is the oid |
|
200 $this->_parseLdapSchemaSyntax($attributeType, $tokens); |
|
201 |
|
202 if (array_key_exists('syntax', $attributeType)) { |
|
203 // get max length from syntax |
|
204 if (preg_match('/^(.+){(\d+)}$/', $attributeType['syntax'], $matches)) { |
|
205 $attributeType['syntax'] = $matches[1]; |
|
206 $attributeType['max-length'] = $matches[2]; |
|
207 } |
|
208 } |
|
209 |
|
210 $this->_ensureNameAttribute($attributeType); |
|
211 |
|
212 return $attributeType; |
|
213 } |
|
214 |
|
215 /** |
|
216 * Loads the object classes |
|
217 * |
|
218 * @return void |
|
219 */ |
|
220 protected function _loadObjectClasses() |
|
221 { |
|
222 $this->_objectClasses = array(); |
|
223 foreach ($this->getAttribute('objectClasses') as $value) { |
|
224 $val = $this->_parseObjectClass($value); |
|
225 $val = new Zend_Ldap_Node_Schema_ObjectClass_OpenLdap($val); |
|
226 $this->_objectClasses[$val->getName()] = $val; |
|
227 } |
|
228 foreach ($this->_objectClasses as $val) { |
|
229 if (count($val->sup) > 0) { |
|
230 $this->_resolveInheritance($val, $this->_objectClasses); |
|
231 } |
|
232 foreach ($val->aliases as $alias) { |
|
233 $this->_objectClasses[$alias] = $val; |
|
234 } |
|
235 } |
|
236 ksort($this->_objectClasses, SORT_STRING); |
|
237 } |
|
238 |
|
239 /** |
|
240 * Parses an objectClasses value |
|
241 * |
|
242 * @param string $value |
|
243 * @return array |
|
244 */ |
|
245 protected function _parseObjectClass($value) |
|
246 { |
|
247 $objectClass = array( |
|
248 'oid' => null, |
|
249 'name' => null, |
|
250 'desc' => null, |
|
251 'obsolete' => false, |
|
252 'sup' => array(), |
|
253 'abstract' => false, |
|
254 'structural' => false, |
|
255 'auxiliary' => false, |
|
256 'must' => array(), |
|
257 'may' => array(), |
|
258 '_string' => $value, |
|
259 '_parents' => array()); |
|
260 |
|
261 $tokens = $this->_tokenizeString($value); |
|
262 $objectClass['oid'] = array_shift($tokens); // first token is the oid |
|
263 $this->_parseLdapSchemaSyntax($objectClass, $tokens); |
|
264 |
|
265 $this->_ensureNameAttribute($objectClass); |
|
266 |
|
267 return $objectClass; |
|
268 } |
|
269 |
|
270 /** |
|
271 * Resolves inheritance in objectClasses and attributes |
|
272 * |
|
273 * @param Zend_Ldap_Node_Schema_Item $node |
|
274 * @param array $repository |
|
275 */ |
|
276 protected function _resolveInheritance(Zend_Ldap_Node_Schema_Item $node, array $repository) |
|
277 { |
|
278 $data = $node->getData(); |
|
279 $parents = $data['sup']; |
|
280 if ($parents === null || !is_array($parents) || count($parents) < 1) return; |
|
281 foreach ($parents as $parent) { |
|
282 if (!array_key_exists($parent, $repository)) continue; |
|
283 if (!array_key_exists('_parents', $data) || !is_array($data['_parents'])) { |
|
284 $data['_parents'] = array(); |
|
285 } |
|
286 $data['_parents'][] = $repository[$parent]; |
|
287 } |
|
288 $node->setData($data); |
|
289 } |
|
290 |
|
291 /** |
|
292 * Loads the LDAP syntaxes |
|
293 * |
|
294 * @return void |
|
295 */ |
|
296 protected function _loadLdapSyntaxes() |
|
297 { |
|
298 $this->_ldapSyntaxes = array(); |
|
299 foreach ($this->getAttribute('ldapSyntaxes') as $value) { |
|
300 $val = $this->_parseLdapSyntax($value); |
|
301 $this->_ldapSyntaxes[$val['oid']] = $val; |
|
302 } |
|
303 ksort($this->_ldapSyntaxes, SORT_STRING); |
|
304 } |
|
305 |
|
306 /** |
|
307 * Parses an ldapSyntaxes value |
|
308 * |
|
309 * @param string $value |
|
310 * @return array |
|
311 */ |
|
312 protected function _parseLdapSyntax($value) |
|
313 { |
|
314 $ldapSyntax = array( |
|
315 'oid' => null, |
|
316 'desc' => null, |
|
317 '_string' => $value); |
|
318 |
|
319 $tokens = $this->_tokenizeString($value); |
|
320 $ldapSyntax['oid'] = array_shift($tokens); // first token is the oid |
|
321 $this->_parseLdapSchemaSyntax($ldapSyntax, $tokens); |
|
322 |
|
323 return $ldapSyntax; |
|
324 } |
|
325 |
|
326 /** |
|
327 * Loads the matching rules |
|
328 * |
|
329 * @return void |
|
330 */ |
|
331 protected function _loadMatchingRules() |
|
332 { |
|
333 $this->_matchingRules = array(); |
|
334 foreach ($this->getAttribute('matchingRules') as $value) { |
|
335 $val = $this->_parseMatchingRule($value); |
|
336 $this->_matchingRules[$val['name']] = $val; |
|
337 } |
|
338 ksort($this->_matchingRules, SORT_STRING); |
|
339 } |
|
340 |
|
341 /** |
|
342 * Parses an matchingRules value |
|
343 * |
|
344 * @param string $value |
|
345 * @return array |
|
346 */ |
|
347 protected function _parseMatchingRule($value) |
|
348 { |
|
349 $matchingRule = array( |
|
350 'oid' => null, |
|
351 'name' => null, |
|
352 'desc' => null, |
|
353 'obsolete' => false, |
|
354 'syntax' => null, |
|
355 '_string' => $value); |
|
356 |
|
357 $tokens = $this->_tokenizeString($value); |
|
358 $matchingRule['oid'] = array_shift($tokens); // first token is the oid |
|
359 $this->_parseLdapSchemaSyntax($matchingRule, $tokens); |
|
360 |
|
361 $this->_ensureNameAttribute($matchingRule); |
|
362 |
|
363 return $matchingRule; |
|
364 } |
|
365 |
|
366 /** |
|
367 * Loads the matching rule use |
|
368 * |
|
369 * @return void |
|
370 */ |
|
371 protected function _loadMatchingRuleUse() |
|
372 { |
|
373 $this->_matchingRuleUse = array(); |
|
374 foreach ($this->getAttribute('matchingRuleUse') as $value) { |
|
375 $val = $this->_parseMatchingRuleUse($value); |
|
376 $this->_matchingRuleUse[$val['name']] = $val; |
|
377 } |
|
378 ksort($this->_matchingRuleUse, SORT_STRING); |
|
379 } |
|
380 |
|
381 /** |
|
382 * Parses an matchingRuleUse value |
|
383 * |
|
384 * @param string $value |
|
385 * @return array |
|
386 */ |
|
387 protected function _parseMatchingRuleUse($value) |
|
388 { |
|
389 $matchingRuleUse = array( |
|
390 'oid' => null, |
|
391 'name' => null, |
|
392 'desc' => null, |
|
393 'obsolete' => false, |
|
394 'applies' => array(), |
|
395 '_string' => $value); |
|
396 |
|
397 $tokens = $this->_tokenizeString($value); |
|
398 $matchingRuleUse['oid'] = array_shift($tokens); // first token is the oid |
|
399 $this->_parseLdapSchemaSyntax($matchingRuleUse, $tokens); |
|
400 |
|
401 $this->_ensureNameAttribute($matchingRuleUse); |
|
402 |
|
403 return $matchingRuleUse; |
|
404 } |
|
405 |
|
406 /** |
|
407 * Ensures that a name element is present and that it is single-values. |
|
408 * |
|
409 * @param array $data |
|
410 */ |
|
411 protected function _ensureNameAttribute(array &$data) |
|
412 { |
|
413 if (!array_key_exists('name', $data) || empty($data['name'])) { |
|
414 // force a name |
|
415 $data['name'] = $data['oid']; |
|
416 } |
|
417 if (is_array($data['name'])) { |
|
418 // make one name the default and put the other ones into aliases |
|
419 $aliases = $data['name']; |
|
420 $data['name'] = array_shift($aliases); |
|
421 $data['aliases'] = $aliases; |
|
422 } else { |
|
423 $data['aliases'] = array(); |
|
424 } |
|
425 } |
|
426 |
|
427 /** |
|
428 * Parse the given tokens into a data structure |
|
429 * |
|
430 * @param array $data |
|
431 * @param array $tokens |
|
432 * @return void |
|
433 */ |
|
434 protected function _parseLdapSchemaSyntax(array &$data, array $tokens) |
|
435 { |
|
436 // tokens that have no value associated |
|
437 $noValue = array('single-value', |
|
438 'obsolete', |
|
439 'collective', |
|
440 'no-user-modification', |
|
441 'abstract', |
|
442 'structural', |
|
443 'auxiliary'); |
|
444 // tokens that can have multiple values |
|
445 $multiValue = array('must', 'may', 'sup'); |
|
446 |
|
447 while (count($tokens) > 0) { |
|
448 $token = strtolower(array_shift($tokens)); |
|
449 if (in_array($token, $noValue)) { |
|
450 $data[$token] = true; // single value token |
|
451 } else { |
|
452 $data[$token] = array_shift($tokens); |
|
453 // this one follows a string or a list if it is multivalued |
|
454 if ($data[$token] == '(') { |
|
455 // this creates the list of values and cycles through the tokens |
|
456 // until the end of the list is reached ')' |
|
457 $data[$token] = array(); |
|
458 while ($tmp = array_shift($tokens)) { |
|
459 if ($tmp == ')') break; |
|
460 if ($tmp != '$') { |
|
461 $data[$token][] = Zend_Ldap_Attribute::convertFromLdapValue($tmp); |
|
462 } |
|
463 } |
|
464 } else { |
|
465 $data[$token] = Zend_Ldap_Attribute::convertFromLdapValue($data[$token]); |
|
466 } |
|
467 // create a array if the value should be multivalued but was not |
|
468 if (in_array($token, $multiValue) && !is_array($data[$token])) { |
|
469 $data[$token] = array($data[$token]); |
|
470 } |
|
471 } |
|
472 } |
|
473 } |
|
474 |
|
475 /** |
|
476 * Tokenizes the given value into an array |
|
477 * |
|
478 * @param string $value |
|
479 * @return array tokens |
|
480 */ |
|
481 protected function _tokenizeString($value) |
|
482 { |
|
483 $tokens = array(); |
|
484 $matches = array(); |
|
485 // this one is taken from PEAR::Net_LDAP2 |
|
486 $pattern = "/\s* (?:([()]) | ([^'\s()]+) | '((?:[^']+|'[^\s)])*)') \s*/x"; |
|
487 preg_match_all($pattern, $value, $matches); |
|
488 $cMatches = count($matches[0]); |
|
489 $cPattern = count($matches); |
|
490 for ($i = 0; $i < $cMatches; $i++) { // number of tokens (full pattern match) |
|
491 for ($j = 1; $j < $cPattern; $j++) { // each subpattern |
|
492 $tok = trim($matches[$j][$i]); |
|
493 if (!empty($tok)) { // pattern match in this subpattern |
|
494 $tokens[$i] = $tok; // this is the token |
|
495 } |
|
496 } |
|
497 } |
|
498 if ($tokens[0] == '(') array_shift($tokens); |
|
499 if ($tokens[count($tokens) - 1] == ')') array_pop($tokens); |
|
500 return $tokens; |
|
501 } |
|
502 } |