| 1 |
lars |
1 |
<?php
|
|
|
2 |
/* vim: set expandtab tabstop=4 shiftwidth=4: */
|
|
|
3 |
/**
|
|
|
4 |
* File containing the Net_LDAP2_Schema interface class.
|
|
|
5 |
*
|
|
|
6 |
* PHP version 5
|
|
|
7 |
*
|
|
|
8 |
* @category Net
|
|
|
9 |
* @package Net_LDAP2
|
|
|
10 |
* @author Jan Wagner <wagner@netsols.de>
|
|
|
11 |
* @author Benedikt Hallinger <beni@php.net>
|
|
|
12 |
* @copyright 2009 Jan Wagner, Benedikt Hallinger
|
|
|
13 |
* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3
|
|
|
14 |
* @version SVN: $Id: Schema.php 296515 2010-03-22 14:46:41Z beni $
|
|
|
15 |
* @link http://pear.php.net/package/Net_LDAP2/
|
|
|
16 |
* @todo see the comment at the end of the file
|
|
|
17 |
*/
|
|
|
18 |
|
|
|
19 |
/**
|
|
|
20 |
* Includes
|
|
|
21 |
*/
|
|
|
22 |
require_once 'PEAR.php';
|
|
|
23 |
|
|
|
24 |
/**
|
|
|
25 |
* Syntax definitions
|
|
|
26 |
*
|
|
|
27 |
* Please don't forget to add binary attributes to isBinary() below
|
|
|
28 |
* to support proper value fetching from Net_LDAP2_Entry
|
|
|
29 |
*/
|
|
|
30 |
define('NET_LDAP2_SYNTAX_BOOLEAN', '1.3.6.1.4.1.1466.115.121.1.7');
|
|
|
31 |
define('NET_LDAP2_SYNTAX_DIRECTORY_STRING', '1.3.6.1.4.1.1466.115.121.1.15');
|
|
|
32 |
define('NET_LDAP2_SYNTAX_DISTINGUISHED_NAME', '1.3.6.1.4.1.1466.115.121.1.12');
|
|
|
33 |
define('NET_LDAP2_SYNTAX_INTEGER', '1.3.6.1.4.1.1466.115.121.1.27');
|
|
|
34 |
define('NET_LDAP2_SYNTAX_JPEG', '1.3.6.1.4.1.1466.115.121.1.28');
|
|
|
35 |
define('NET_LDAP2_SYNTAX_NUMERIC_STRING', '1.3.6.1.4.1.1466.115.121.1.36');
|
|
|
36 |
define('NET_LDAP2_SYNTAX_OID', '1.3.6.1.4.1.1466.115.121.1.38');
|
|
|
37 |
define('NET_LDAP2_SYNTAX_OCTET_STRING', '1.3.6.1.4.1.1466.115.121.1.40');
|
|
|
38 |
|
|
|
39 |
/**
|
|
|
40 |
* Load an LDAP Schema and provide information
|
|
|
41 |
*
|
|
|
42 |
* This class takes a Subschema entry, parses this information
|
|
|
43 |
* and makes it available in an array. Most of the code has been
|
|
|
44 |
* inspired by perl-ldap( http://perl-ldap.sourceforge.net).
|
|
|
45 |
* You will find portions of their implementation in here.
|
|
|
46 |
*
|
|
|
47 |
* @category Net
|
|
|
48 |
* @package Net_LDAP2
|
|
|
49 |
* @author Jan Wagner <wagner@netsols.de>
|
|
|
50 |
* @author Benedikt Hallinger <beni@php.net>
|
|
|
51 |
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
|
52 |
* @link http://pear.php.net/package/Net_LDAP22/
|
|
|
53 |
*/
|
|
|
54 |
class Net_LDAP2_Schema extends PEAR
|
|
|
55 |
{
|
|
|
56 |
/**
|
|
|
57 |
* Map of entry types to ldap attributes of subschema entry
|
|
|
58 |
*
|
|
|
59 |
* @access public
|
|
|
60 |
* @var array
|
|
|
61 |
*/
|
|
|
62 |
public $types = array(
|
|
|
63 |
'attribute' => 'attributeTypes',
|
|
|
64 |
'ditcontentrule' => 'dITContentRules',
|
|
|
65 |
'ditstructurerule' => 'dITStructureRules',
|
|
|
66 |
'matchingrule' => 'matchingRules',
|
|
|
67 |
'matchingruleuse' => 'matchingRuleUse',
|
|
|
68 |
'nameform' => 'nameForms',
|
|
|
69 |
'objectclass' => 'objectClasses',
|
|
|
70 |
'syntax' => 'ldapSyntaxes'
|
|
|
71 |
);
|
|
|
72 |
|
|
|
73 |
/**
|
|
|
74 |
* Array of entries belonging to this type
|
|
|
75 |
*
|
|
|
76 |
* @access protected
|
|
|
77 |
* @var array
|
|
|
78 |
*/
|
|
|
79 |
protected $_attributeTypes = array();
|
|
|
80 |
protected $_matchingRules = array();
|
|
|
81 |
protected $_matchingRuleUse = array();
|
|
|
82 |
protected $_ldapSyntaxes = array();
|
|
|
83 |
protected $_objectClasses = array();
|
|
|
84 |
protected $_dITContentRules = array();
|
|
|
85 |
protected $_dITStructureRules = array();
|
|
|
86 |
protected $_nameForms = array();
|
|
|
87 |
|
|
|
88 |
|
|
|
89 |
/**
|
|
|
90 |
* hash of all fetched oids
|
|
|
91 |
*
|
|
|
92 |
* @access protected
|
|
|
93 |
* @var array
|
|
|
94 |
*/
|
|
|
95 |
protected $_oids = array();
|
|
|
96 |
|
|
|
97 |
/**
|
|
|
98 |
* Tells if the schema is initialized
|
|
|
99 |
*
|
|
|
100 |
* @access protected
|
|
|
101 |
* @var boolean
|
|
|
102 |
* @see parse(), get()
|
|
|
103 |
*/
|
|
|
104 |
protected $_initialized = false;
|
|
|
105 |
|
|
|
106 |
|
|
|
107 |
/**
|
|
|
108 |
* Constructor of the class
|
|
|
109 |
*
|
|
|
110 |
* @access protected
|
|
|
111 |
*/
|
|
|
112 |
protected function __construct()
|
|
|
113 |
{
|
|
|
114 |
$this->PEAR('Net_LDAP2_Error'); // default error class
|
|
|
115 |
}
|
|
|
116 |
|
|
|
117 |
/**
|
|
|
118 |
* Fetch the Schema from an LDAP connection
|
|
|
119 |
*
|
|
|
120 |
* @param Net_LDAP2 $ldap LDAP connection
|
|
|
121 |
* @param string $dn (optional) Subschema entry dn
|
|
|
122 |
*
|
|
|
123 |
* @access public
|
|
|
124 |
* @return Net_LDAP2_Schema|NET_LDAP2_Error
|
|
|
125 |
*/
|
|
|
126 |
public function fetch($ldap, $dn = null)
|
|
|
127 |
{
|
|
|
128 |
if (!$ldap instanceof Net_LDAP2) {
|
|
|
129 |
return PEAR::raiseError("Unable to fetch Schema: Parameter \$ldap must be a Net_LDAP2 object!");
|
|
|
130 |
}
|
|
|
131 |
|
|
|
132 |
$schema_o = new Net_LDAP2_Schema();
|
|
|
133 |
|
|
|
134 |
if (is_null($dn)) {
|
|
|
135 |
// get the subschema entry via root dse
|
|
|
136 |
$dse = $ldap->rootDSE(array('subschemaSubentry'));
|
|
|
137 |
if (false == Net_LDAP2::isError($dse)) {
|
|
|
138 |
$base = $dse->getValue('subschemaSubentry', 'single');
|
|
|
139 |
if (!Net_LDAP2::isError($base)) {
|
|
|
140 |
$dn = $base;
|
|
|
141 |
}
|
|
|
142 |
}
|
|
|
143 |
}
|
|
|
144 |
|
|
|
145 |
// Support for buggy LDAP servers (e.g. Siemens DirX 6.x) that incorrectly
|
|
|
146 |
// call this entry subSchemaSubentry instead of subschemaSubentry.
|
|
|
147 |
// Note the correct case/spelling as per RFC 2251.
|
|
|
148 |
if (is_null($dn)) {
|
|
|
149 |
// get the subschema entry via root dse
|
|
|
150 |
$dse = $ldap->rootDSE(array('subSchemaSubentry'));
|
|
|
151 |
if (false == Net_LDAP2::isError($dse)) {
|
|
|
152 |
$base = $dse->getValue('subSchemaSubentry', 'single');
|
|
|
153 |
if (!Net_LDAP2::isError($base)) {
|
|
|
154 |
$dn = $base;
|
|
|
155 |
}
|
|
|
156 |
}
|
|
|
157 |
}
|
|
|
158 |
|
|
|
159 |
// Final fallback case where there is no subschemaSubentry attribute
|
|
|
160 |
// in the root DSE (this is a bug for an LDAP v3 server so report this
|
|
|
161 |
// to your LDAP vendor if you get this far).
|
|
|
162 |
if (is_null($dn)) {
|
|
|
163 |
$dn = 'cn=Subschema';
|
|
|
164 |
}
|
|
|
165 |
|
|
|
166 |
// fetch the subschema entry
|
|
|
167 |
$result = $ldap->search($dn, '(objectClass=*)',
|
|
|
168 |
array('attributes' => array_values($schema_o->types),
|
|
|
169 |
'scope' => 'base'));
|
|
|
170 |
if (Net_LDAP2::isError($result)) {
|
|
|
171 |
return PEAR::raiseError('Could not fetch Subschema entry: '.$result->getMessage());
|
|
|
172 |
}
|
|
|
173 |
|
|
|
174 |
$entry = $result->shiftEntry();
|
|
|
175 |
if (!$entry instanceof Net_LDAP2_Entry) {
|
|
|
176 |
if ($entry instanceof Net_LDAP2_Error) {
|
|
|
177 |
return PEAR::raiseError('Could not fetch Subschema entry: '.$entry->getMessage());
|
|
|
178 |
} else {
|
|
|
179 |
return PEAR::raiseError('Could not fetch Subschema entry (search returned '.$result->count().' entries. Check parameter \'basedn\')');
|
|
|
180 |
}
|
|
|
181 |
}
|
|
|
182 |
|
|
|
183 |
$schema_o->parse($entry);
|
|
|
184 |
return $schema_o;
|
|
|
185 |
}
|
|
|
186 |
|
|
|
187 |
/**
|
|
|
188 |
* Return a hash of entries for the given type
|
|
|
189 |
*
|
|
|
190 |
* Returns a hash of entry for the givene type. Types may be:
|
|
|
191 |
* objectclasses, attributes, ditcontentrules, ditstructurerules, matchingrules,
|
|
|
192 |
* matchingruleuses, nameforms, syntaxes
|
|
|
193 |
*
|
|
|
194 |
* @param string $type Type to fetch
|
|
|
195 |
*
|
|
|
196 |
* @access public
|
|
|
197 |
* @return array|Net_LDAP2_Error Array or Net_LDAP2_Error
|
|
|
198 |
*/
|
|
|
199 |
public function &getAll($type)
|
|
|
200 |
{
|
|
|
201 |
$map = array('objectclasses' => &$this->_objectClasses,
|
|
|
202 |
'attributes' => &$this->_attributeTypes,
|
|
|
203 |
'ditcontentrules' => &$this->_dITContentRules,
|
|
|
204 |
'ditstructurerules' => &$this->_dITStructureRules,
|
|
|
205 |
'matchingrules' => &$this->_matchingRules,
|
|
|
206 |
'matchingruleuses' => &$this->_matchingRuleUse,
|
|
|
207 |
'nameforms' => &$this->_nameForms,
|
|
|
208 |
'syntaxes' => &$this->_ldapSyntaxes );
|
|
|
209 |
|
|
|
210 |
$key = strtolower($type);
|
|
|
211 |
$ret = ((key_exists($key, $map)) ? $map[$key] : PEAR::raiseError("Unknown type $type"));
|
|
|
212 |
return $ret;
|
|
|
213 |
}
|
|
|
214 |
|
|
|
215 |
/**
|
|
|
216 |
* Return a specific entry
|
|
|
217 |
*
|
|
|
218 |
* @param string $type Type of name
|
|
|
219 |
* @param string $name Name or OID to fetch
|
|
|
220 |
*
|
|
|
221 |
* @access public
|
|
|
222 |
* @return mixed Entry or Net_LDAP2_Error
|
|
|
223 |
*/
|
|
|
224 |
public function &get($type, $name)
|
|
|
225 |
{
|
|
|
226 |
if ($this->_initialized) {
|
|
|
227 |
$type = strtolower($type);
|
|
|
228 |
if (false == key_exists($type, $this->types)) {
|
|
|
229 |
return PEAR::raiseError("No such type $type");
|
|
|
230 |
}
|
|
|
231 |
|
|
|
232 |
$name = strtolower($name);
|
|
|
233 |
$type_var = &$this->{'_' . $this->types[$type]};
|
|
|
234 |
|
|
|
235 |
if (key_exists($name, $type_var)) {
|
|
|
236 |
return $type_var[$name];
|
|
|
237 |
} elseif (key_exists($name, $this->_oids) && $this->_oids[$name]['type'] == $type) {
|
|
|
238 |
return $this->_oids[$name];
|
|
|
239 |
} else {
|
|
|
240 |
return PEAR::raiseError("Could not find $type $name");
|
|
|
241 |
}
|
|
|
242 |
} else {
|
|
|
243 |
$return = null;
|
|
|
244 |
return $return;
|
|
|
245 |
}
|
|
|
246 |
}
|
|
|
247 |
|
|
|
248 |
|
|
|
249 |
/**
|
|
|
250 |
* Fetches attributes that MAY be present in the given objectclass
|
|
|
251 |
*
|
|
|
252 |
* @param string $oc Name or OID of objectclass
|
|
|
253 |
*
|
|
|
254 |
* @access public
|
|
|
255 |
* @return array|Net_LDAP2_Error Array with attributes or Net_LDAP2_Error
|
|
|
256 |
*/
|
|
|
257 |
public function may($oc)
|
|
|
258 |
{
|
|
|
259 |
return $this->_getAttr($oc, 'may');
|
|
|
260 |
}
|
|
|
261 |
|
|
|
262 |
/**
|
|
|
263 |
* Fetches attributes that MUST be present in the given objectclass
|
|
|
264 |
*
|
|
|
265 |
* @param string $oc Name or OID of objectclass
|
|
|
266 |
*
|
|
|
267 |
* @access public
|
|
|
268 |
* @return array|Net_LDAP2_Error Array with attributes or Net_LDAP2_Error
|
|
|
269 |
*/
|
|
|
270 |
public function must($oc)
|
|
|
271 |
{
|
|
|
272 |
return $this->_getAttr($oc, 'must');
|
|
|
273 |
}
|
|
|
274 |
|
|
|
275 |
/**
|
|
|
276 |
* Fetches the given attribute from the given objectclass
|
|
|
277 |
*
|
|
|
278 |
* @param string $oc Name or OID of objectclass
|
|
|
279 |
* @param string $attr Name of attribute to fetch
|
|
|
280 |
*
|
|
|
281 |
* @access protected
|
|
|
282 |
* @return array|Net_LDAP2_Error The attribute or Net_LDAP2_Error
|
|
|
283 |
*/
|
|
|
284 |
protected function _getAttr($oc, $attr)
|
|
|
285 |
{
|
|
|
286 |
$oc = strtolower($oc);
|
|
|
287 |
if (key_exists($oc, $this->_objectClasses) && key_exists($attr, $this->_objectClasses[$oc])) {
|
|
|
288 |
return $this->_objectClasses[$oc][$attr];
|
|
|
289 |
} elseif (key_exists($oc, $this->_oids) &&
|
|
|
290 |
$this->_oids[$oc]['type'] == 'objectclass' &&
|
|
|
291 |
key_exists($attr, $this->_oids[$oc])) {
|
|
|
292 |
return $this->_oids[$oc][$attr];
|
|
|
293 |
} else {
|
|
|
294 |
return PEAR::raiseError("Could not find $attr attributes for $oc ");
|
|
|
295 |
}
|
|
|
296 |
}
|
|
|
297 |
|
|
|
298 |
/**
|
|
|
299 |
* Returns the name(s) of the immediate superclass(es)
|
|
|
300 |
*
|
|
|
301 |
* @param string $oc Name or OID of objectclass
|
|
|
302 |
*
|
|
|
303 |
* @access public
|
|
|
304 |
* @return array|Net_LDAP2_Error Array of names or Net_LDAP2_Error
|
|
|
305 |
*/
|
|
|
306 |
public function superclass($oc)
|
|
|
307 |
{
|
|
|
308 |
$o = $this->get('objectclass', $oc);
|
|
|
309 |
if (Net_LDAP2::isError($o)) {
|
|
|
310 |
return $o;
|
|
|
311 |
}
|
|
|
312 |
return (key_exists('sup', $o) ? $o['sup'] : array());
|
|
|
313 |
}
|
|
|
314 |
|
|
|
315 |
/**
|
|
|
316 |
* Parses the schema of the given Subschema entry
|
|
|
317 |
*
|
|
|
318 |
* @param Net_LDAP2_Entry &$entry Subschema entry
|
|
|
319 |
*
|
|
|
320 |
* @access public
|
|
|
321 |
* @return void
|
|
|
322 |
*/
|
|
|
323 |
public function parse(&$entry)
|
|
|
324 |
{
|
|
|
325 |
foreach ($this->types as $type => $attr) {
|
|
|
326 |
// initialize map type to entry
|
|
|
327 |
$type_var = '_' . $attr;
|
|
|
328 |
$this->{$type_var} = array();
|
|
|
329 |
|
|
|
330 |
// get values for this type
|
|
|
331 |
if ($entry->exists($attr)) {
|
|
|
332 |
$values = $entry->getValue($attr);
|
|
|
333 |
if (is_array($values)) {
|
|
|
334 |
foreach ($values as $value) {
|
|
|
335 |
|
|
|
336 |
unset($schema_entry); // this was a real mess without it
|
|
|
337 |
|
|
|
338 |
// get the schema entry
|
|
|
339 |
$schema_entry = $this->_parse_entry($value);
|
|
|
340 |
|
|
|
341 |
// set the type
|
|
|
342 |
$schema_entry['type'] = $type;
|
|
|
343 |
|
|
|
344 |
// save a ref in $_oids
|
|
|
345 |
$this->_oids[$schema_entry['oid']] = &$schema_entry;
|
|
|
346 |
|
|
|
347 |
// save refs for all names in type map
|
|
|
348 |
$names = $schema_entry['aliases'];
|
|
|
349 |
array_push($names, $schema_entry['name']);
|
|
|
350 |
foreach ($names as $name) {
|
|
|
351 |
$this->{$type_var}[strtolower($name)] = &$schema_entry;
|
|
|
352 |
}
|
|
|
353 |
}
|
|
|
354 |
}
|
|
|
355 |
}
|
|
|
356 |
}
|
|
|
357 |
$this->_initialized = true;
|
|
|
358 |
}
|
|
|
359 |
|
|
|
360 |
/**
|
|
|
361 |
* Parses an attribute value into a schema entry
|
|
|
362 |
*
|
|
|
363 |
* @param string $value Attribute value
|
|
|
364 |
*
|
|
|
365 |
* @access protected
|
|
|
366 |
* @return array|false Schema entry array or false
|
|
|
367 |
*/
|
|
|
368 |
protected function &_parse_entry($value)
|
|
|
369 |
{
|
|
|
370 |
// tokens that have no value associated
|
|
|
371 |
$noValue = array('single-value',
|
|
|
372 |
'obsolete',
|
|
|
373 |
'collective',
|
|
|
374 |
'no-user-modification',
|
|
|
375 |
'abstract',
|
|
|
376 |
'structural',
|
|
|
377 |
'auxiliary');
|
|
|
378 |
|
|
|
379 |
// tokens that can have multiple values
|
|
|
380 |
$multiValue = array('must', 'may', 'sup');
|
|
|
381 |
|
|
|
382 |
$schema_entry = array('aliases' => array()); // initilization
|
|
|
383 |
|
|
|
384 |
$tokens = $this->_tokenize($value); // get an array of tokens
|
|
|
385 |
|
|
|
386 |
// remove surrounding brackets
|
|
|
387 |
if ($tokens[0] == '(') array_shift($tokens);
|
|
|
388 |
if ($tokens[count($tokens) - 1] == ')') array_pop($tokens); // -1 doesnt work on arrays :-(
|
|
|
389 |
|
|
|
390 |
$schema_entry['oid'] = array_shift($tokens); // first token is the oid
|
|
|
391 |
|
|
|
392 |
// cycle over the tokens until none are left
|
|
|
393 |
while (count($tokens) > 0) {
|
|
|
394 |
$token = strtolower(array_shift($tokens));
|
|
|
395 |
if (in_array($token, $noValue)) {
|
|
|
396 |
$schema_entry[$token] = 1; // single value token
|
|
|
397 |
} else {
|
|
|
398 |
// this one follows a string or a list if it is multivalued
|
|
|
399 |
if (($schema_entry[$token] = array_shift($tokens)) == '(') {
|
|
|
400 |
// this creates the list of values and cycles through the tokens
|
|
|
401 |
// until the end of the list is reached ')'
|
|
|
402 |
$schema_entry[$token] = array();
|
|
|
403 |
while ($tmp = array_shift($tokens)) {
|
|
|
404 |
if ($tmp == ')') break;
|
|
|
405 |
if ($tmp != '$') array_push($schema_entry[$token], $tmp);
|
|
|
406 |
}
|
|
|
407 |
}
|
|
|
408 |
// create a array if the value should be multivalued but was not
|
|
|
409 |
if (in_array($token, $multiValue) && !is_array($schema_entry[$token])) {
|
|
|
410 |
$schema_entry[$token] = array($schema_entry[$token]);
|
|
|
411 |
}
|
|
|
412 |
}
|
|
|
413 |
}
|
|
|
414 |
// get max length from syntax
|
|
|
415 |
if (key_exists('syntax', $schema_entry)) {
|
|
|
416 |
if (preg_match('/{(\d+)}/', $schema_entry['syntax'], $matches)) {
|
|
|
417 |
$schema_entry['max_length'] = $matches[1];
|
|
|
418 |
}
|
|
|
419 |
}
|
|
|
420 |
// force a name
|
|
|
421 |
if (empty($schema_entry['name'])) {
|
|
|
422 |
$schema_entry['name'] = $schema_entry['oid'];
|
|
|
423 |
}
|
|
|
424 |
// make one name the default and put the other ones into aliases
|
|
|
425 |
if (is_array($schema_entry['name'])) {
|
|
|
426 |
$aliases = $schema_entry['name'];
|
|
|
427 |
$schema_entry['name'] = array_shift($aliases);
|
|
|
428 |
$schema_entry['aliases'] = $aliases;
|
|
|
429 |
}
|
|
|
430 |
return $schema_entry;
|
|
|
431 |
}
|
|
|
432 |
|
|
|
433 |
/**
|
|
|
434 |
* Tokenizes the given value into an array of tokens
|
|
|
435 |
*
|
|
|
436 |
* @param string $value String to parse
|
|
|
437 |
*
|
|
|
438 |
* @access protected
|
|
|
439 |
* @return array Array of tokens
|
|
|
440 |
*/
|
|
|
441 |
protected function _tokenize($value)
|
|
|
442 |
{
|
|
|
443 |
$tokens = array(); // array of tokens
|
|
|
444 |
$matches = array(); // matches[0] full pattern match, [1,2,3] subpatterns
|
|
|
445 |
|
|
|
446 |
// this one is taken from perl-ldap, modified for php
|
|
|
447 |
$pattern = "/\s* (?:([()]) | ([^'\s()]+) | '((?:[^']+|'[^\s)])*)') \s*/x";
|
|
|
448 |
|
|
|
449 |
/**
|
|
|
450 |
* This one matches one big pattern wherin only one of the three subpatterns matched
|
|
|
451 |
* We are interested in the subpatterns that matched. If it matched its value will be
|
|
|
452 |
* non-empty and so it is a token. Tokens may be round brackets, a string, or a string
|
|
|
453 |
* enclosed by '
|
|
|
454 |
*/
|
|
|
455 |
preg_match_all($pattern, $value, $matches);
|
|
|
456 |
|
|
|
457 |
for ($i = 0; $i < count($matches[0]); $i++) { // number of tokens (full pattern match)
|
|
|
458 |
for ($j = 1; $j < 4; $j++) { // each subpattern
|
|
|
459 |
if (null != trim($matches[$j][$i])) { // pattern match in this subpattern
|
|
|
460 |
$tokens[$i] = trim($matches[$j][$i]); // this is the token
|
|
|
461 |
}
|
|
|
462 |
}
|
|
|
463 |
}
|
|
|
464 |
return $tokens;
|
|
|
465 |
}
|
|
|
466 |
|
|
|
467 |
/**
|
|
|
468 |
* Returns wether a attribute syntax is binary or not
|
|
|
469 |
*
|
|
|
470 |
* This method gets used by Net_LDAP2_Entry to decide which
|
|
|
471 |
* PHP function needs to be used to fetch the value in the
|
|
|
472 |
* proper format (e.g. binary or string)
|
|
|
473 |
*
|
|
|
474 |
* @param string $attribute The name of the attribute (eg.: 'sn')
|
|
|
475 |
*
|
|
|
476 |
* @access public
|
|
|
477 |
* @return boolean
|
|
|
478 |
*/
|
|
|
479 |
public function isBinary($attribute)
|
|
|
480 |
{
|
|
|
481 |
$return = false; // default to false
|
|
|
482 |
|
|
|
483 |
// This list contains all syntax that should be treaten as
|
|
|
484 |
// containing binary values
|
|
|
485 |
// The Syntax Definitons go into constants at the top of this page
|
|
|
486 |
$syntax_binary = array(
|
|
|
487 |
NET_LDAP2_SYNTAX_OCTET_STRING,
|
|
|
488 |
NET_LDAP2_SYNTAX_JPEG
|
|
|
489 |
);
|
|
|
490 |
|
|
|
491 |
// Check Syntax
|
|
|
492 |
$attr_s = $this->get('attribute', $attribute);
|
|
|
493 |
if (Net_LDAP2::isError($attr_s)) {
|
|
|
494 |
// Attribute not found in schema
|
|
|
495 |
$return = false; // consider attr not binary
|
|
|
496 |
} elseif (isset($attr_s['syntax']) && in_array($attr_s['syntax'], $syntax_binary)) {
|
|
|
497 |
// Syntax is defined as binary in schema
|
|
|
498 |
$return = true;
|
|
|
499 |
} else {
|
|
|
500 |
// Syntax not defined as binary, or not found
|
|
|
501 |
// if attribute is a subtype, check superior attribute syntaxes
|
|
|
502 |
if (isset($attr_s['sup'])) {
|
|
|
503 |
foreach ($attr_s['sup'] as $superattr) {
|
|
|
504 |
$return = $this->isBinary($superattr);
|
|
|
505 |
if ($return) {
|
|
|
506 |
break; // stop checking parents since we are binary
|
|
|
507 |
}
|
|
|
508 |
}
|
|
|
509 |
}
|
|
|
510 |
}
|
|
|
511 |
|
|
|
512 |
return $return;
|
|
|
513 |
}
|
|
|
514 |
|
|
|
515 |
/**
|
|
|
516 |
* See if an schema element exists
|
|
|
517 |
*
|
|
|
518 |
* @param string $type Type of name, see get()
|
|
|
519 |
* @param string $name Name or OID
|
|
|
520 |
*
|
|
|
521 |
* @return boolean
|
|
|
522 |
*/
|
|
|
523 |
public function exists($type, $name)
|
|
|
524 |
{
|
|
|
525 |
$entry = $this->get($type, $name);
|
|
|
526 |
if ($entry instanceof Net_LDAP2_ERROR) {
|
|
|
527 |
return false;
|
|
|
528 |
} else {
|
|
|
529 |
return true;
|
|
|
530 |
}
|
|
|
531 |
}
|
|
|
532 |
|
|
|
533 |
/**
|
|
|
534 |
* See if an attribute is defined in the schema
|
|
|
535 |
*
|
|
|
536 |
* @param string $attribute Name or OID of the attribute
|
|
|
537 |
* @return boolean
|
|
|
538 |
*/
|
|
|
539 |
public function attributeExists($attribute)
|
|
|
540 |
{
|
|
|
541 |
return $this->exists('attribute', $attribute);
|
|
|
542 |
}
|
|
|
543 |
|
|
|
544 |
/**
|
|
|
545 |
* See if an objectClass is defined in the schema
|
|
|
546 |
*
|
|
|
547 |
* @param string $ocl Name or OID of the objectClass
|
|
|
548 |
* @return boolean
|
|
|
549 |
*/
|
|
|
550 |
public function objectClassExists($ocl)
|
|
|
551 |
{
|
|
|
552 |
return $this->exists('objectclass', $ocl);
|
|
|
553 |
}
|
|
|
554 |
|
|
|
555 |
|
|
|
556 |
/**
|
|
|
557 |
* See to which ObjectClasses an attribute is assigned
|
|
|
558 |
*
|
|
|
559 |
* The objectclasses are sorted into the keys 'may' and 'must'.
|
|
|
560 |
*
|
|
|
561 |
* @param string $attribute Name or OID of the attribute
|
|
|
562 |
*
|
|
|
563 |
* @return array|Net_LDAP2_Error Associative array with OCL names or Error
|
|
|
564 |
*/
|
|
|
565 |
public function getAssignedOCLs($attribute)
|
|
|
566 |
{
|
|
|
567 |
$may = array();
|
|
|
568 |
$must = array();
|
|
|
569 |
|
|
|
570 |
// Test if the attribute type is defined in the schema,
|
|
|
571 |
// if so, retrieve real name for lookups
|
|
|
572 |
$attr_entry = $this->get('attribute', $attribute);
|
|
|
573 |
if ($attr_entry instanceof Net_LDAP2_ERROR) {
|
|
|
574 |
return PEAR::raiseError("Attribute $attribute not defined in schema: ".$attr_entry->getMessage());
|
|
|
575 |
} else {
|
|
|
576 |
$attribute = $attr_entry['name'];
|
|
|
577 |
}
|
|
|
578 |
|
|
|
579 |
|
|
|
580 |
// We need to get all defined OCLs for this.
|
|
|
581 |
$ocls = $this->getAll('objectclasses');
|
|
|
582 |
foreach ($ocls as $ocl => $ocl_data) {
|
|
|
583 |
// Fetch the may and must attrs and see if our searched attr is contained.
|
|
|
584 |
// If so, record it in the corresponding array.
|
|
|
585 |
$ocl_may_attrs = $this->may($ocl);
|
|
|
586 |
$ocl_must_attrs = $this->must($ocl);
|
|
|
587 |
if (is_array($ocl_may_attrs) && in_array($attribute, $ocl_may_attrs)) {
|
|
|
588 |
array_push($may, $ocl_data['name']);
|
|
|
589 |
}
|
|
|
590 |
if (is_array($ocl_must_attrs) && in_array($attribute, $ocl_must_attrs)) {
|
|
|
591 |
array_push($must, $ocl_data['name']);
|
|
|
592 |
}
|
|
|
593 |
}
|
|
|
594 |
|
|
|
595 |
return array('may' => $may, 'must' => $must);
|
|
|
596 |
}
|
|
|
597 |
|
|
|
598 |
/**
|
|
|
599 |
* See if an attribute is available in a set of objectClasses
|
|
|
600 |
*
|
|
|
601 |
* @param string $attribute Attribute name or OID
|
|
|
602 |
* @param array $ocls Names of OCLs to check for
|
|
|
603 |
*
|
|
|
604 |
* @return boolean TRUE, if the attribute is defined for at least one of the OCLs
|
|
|
605 |
*/
|
|
|
606 |
public function checkAttribute($attribute, $ocls)
|
|
|
607 |
{
|
|
|
608 |
foreach ($ocls as $ocl) {
|
|
|
609 |
$ocl_entry = $this->get('objectclass', $ocl);
|
|
|
610 |
$ocl_may_attrs = $this->may($ocl);
|
|
|
611 |
$ocl_must_attrs = $this->must($ocl);
|
|
|
612 |
if (is_array($ocl_may_attrs) && in_array($attribute, $ocl_may_attrs)) {
|
|
|
613 |
return true;
|
|
|
614 |
}
|
|
|
615 |
if (is_array($ocl_must_attrs) && in_array($attribute, $ocl_must_attrs)) {
|
|
|
616 |
return true;
|
|
|
617 |
}
|
|
|
618 |
}
|
|
|
619 |
return false; // no ocl for the ocls found.
|
|
|
620 |
}
|
|
|
621 |
}
|
|
|
622 |
?>
|