File indexing completed on 2024-12-29 05:27:47
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Ldap 0017 * @subpackage Schema 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** 0024 * @see Zend_Ldap_Node_Schema 0025 */ 0026 // require_once 'Zend/Ldap/Node/Schema.php'; 0027 /** 0028 * @see Zend_Ldap_Node_Schema_AttributeType_OpenLdap 0029 */ 0030 // require_once 'Zend/Ldap/Node/Schema/AttributeType/OpenLdap.php'; 0031 /** 0032 * @see Zend_Ldap_Node_Schema_ObjectClass_OpenLdap 0033 */ 0034 // require_once 'Zend/Ldap/Node/Schema/ObjectClass/OpenLdap.php'; 0035 0036 /** 0037 * Zend_Ldap_Node_Schema_OpenLdap provides a simple data-container for the Schema node of 0038 * an OpenLDAP server. 0039 * 0040 * @category Zend 0041 * @package Zend_Ldap 0042 * @subpackage Schema 0043 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0044 * @license http://framework.zend.com/license/new-bsd New BSD License 0045 */ 0046 class Zend_Ldap_Node_Schema_OpenLdap extends Zend_Ldap_Node_Schema 0047 { 0048 /** 0049 * The attribute Types 0050 * 0051 * @var array 0052 */ 0053 protected $_attributeTypes = null; 0054 /** 0055 * The object classes 0056 * 0057 * @var array 0058 */ 0059 protected $_objectClasses = null; 0060 /** 0061 * The LDAP syntaxes 0062 * 0063 * @var array 0064 */ 0065 protected $_ldapSyntaxes = null; 0066 /** 0067 * The matching rules 0068 * 0069 * @var array 0070 */ 0071 protected $_matchingRules = null; 0072 /** 0073 * The matching rule use 0074 * 0075 * @var array 0076 */ 0077 protected $_matchingRuleUse = null; 0078 0079 /** 0080 * Parses the schema 0081 * 0082 * @param Zend_Ldap_Dn $dn 0083 * @param Zend_Ldap $ldap 0084 * @return Zend_Ldap_Node_Schema Provides a fluent interface 0085 */ 0086 protected function _parseSchema(Zend_Ldap_Dn $dn, Zend_Ldap $ldap) 0087 { 0088 parent::_parseSchema($dn, $ldap); 0089 $this->_loadAttributeTypes(); 0090 $this->_loadLdapSyntaxes(); 0091 $this->_loadMatchingRules(); 0092 $this->_loadMatchingRuleUse(); 0093 $this->_loadObjectClasses(); 0094 return $this; 0095 } 0096 0097 /** 0098 * Gets the attribute Types 0099 * 0100 * @return array 0101 */ 0102 public function getAttributeTypes() 0103 { 0104 return $this->_attributeTypes; 0105 } 0106 0107 /** 0108 * Gets the object classes 0109 * 0110 * @return array 0111 */ 0112 public function getObjectClasses() 0113 { 0114 return $this->_objectClasses; 0115 } 0116 0117 /** 0118 * Gets the LDAP syntaxes 0119 * 0120 * @return array 0121 */ 0122 public function getLdapSyntaxes() 0123 { 0124 return $this->_ldapSyntaxes; 0125 } 0126 0127 /** 0128 * Gets the matching rules 0129 * 0130 * @return array 0131 */ 0132 public function getMatchingRules() 0133 { 0134 return $this->_matchingRules; 0135 } 0136 0137 /** 0138 * Gets the matching rule use 0139 * 0140 * @return array 0141 */ 0142 public function getMatchingRuleUse() 0143 { 0144 return $this->_matchingRuleUse; 0145 } 0146 0147 /** 0148 * Loads the attribute Types 0149 * 0150 * @return void 0151 */ 0152 protected function _loadAttributeTypes() 0153 { 0154 $this->_attributeTypes = array(); 0155 foreach ($this->getAttribute('attributeTypes') as $value) { 0156 $val = $this->_parseAttributeType($value); 0157 $val = new Zend_Ldap_Node_Schema_AttributeType_OpenLdap($val); 0158 $this->_attributeTypes[$val->getName()] = $val; 0159 0160 } 0161 foreach ($this->_attributeTypes as $val) { 0162 if (count($val->sup) > 0) { 0163 $this->_resolveInheritance($val, $this->_attributeTypes); 0164 } 0165 foreach ($val->aliases as $alias) { 0166 $this->_attributeTypes[$alias] = $val; 0167 } 0168 } 0169 ksort($this->_attributeTypes, SORT_STRING); 0170 } 0171 0172 /** 0173 * Parses an attributeType value 0174 * 0175 * @param string $value 0176 * @return array 0177 */ 0178 protected function _parseAttributeType($value) 0179 { 0180 $attributeType = array( 0181 'oid' => null, 0182 'name' => null, 0183 'desc' => null, 0184 'obsolete' => false, 0185 'sup' => null, 0186 'equality' => null, 0187 'ordering' => null, 0188 'substr' => null, 0189 'syntax' => null, 0190 'max-length' => null, 0191 'single-value' => false, 0192 'collective' => false, 0193 'no-user-modification' => false, 0194 'usage' => 'userApplications', 0195 '_string' => $value, 0196 '_parents' => array()); 0197 0198 $tokens = $this->_tokenizeString($value); 0199 $attributeType['oid'] = array_shift($tokens); // first token is the oid 0200 $this->_parseLdapSchemaSyntax($attributeType, $tokens); 0201 0202 if (array_key_exists('syntax', $attributeType)) { 0203 // get max length from syntax 0204 if (preg_match('/^(.+){(\d+)}$/', $attributeType['syntax'], $matches)) { 0205 $attributeType['syntax'] = $matches[1]; 0206 $attributeType['max-length'] = $matches[2]; 0207 } 0208 } 0209 0210 $this->_ensureNameAttribute($attributeType); 0211 0212 return $attributeType; 0213 } 0214 0215 /** 0216 * Loads the object classes 0217 * 0218 * @return void 0219 */ 0220 protected function _loadObjectClasses() 0221 { 0222 $this->_objectClasses = array(); 0223 foreach ($this->getAttribute('objectClasses') as $value) { 0224 $val = $this->_parseObjectClass($value); 0225 $val = new Zend_Ldap_Node_Schema_ObjectClass_OpenLdap($val); 0226 $this->_objectClasses[$val->getName()] = $val; 0227 } 0228 foreach ($this->_objectClasses as $val) { 0229 if (count($val->sup) > 0) { 0230 $this->_resolveInheritance($val, $this->_objectClasses); 0231 } 0232 foreach ($val->aliases as $alias) { 0233 $this->_objectClasses[$alias] = $val; 0234 } 0235 } 0236 ksort($this->_objectClasses, SORT_STRING); 0237 } 0238 0239 /** 0240 * Parses an objectClasses value 0241 * 0242 * @param string $value 0243 * @return array 0244 */ 0245 protected function _parseObjectClass($value) 0246 { 0247 $objectClass = array( 0248 'oid' => null, 0249 'name' => null, 0250 'desc' => null, 0251 'obsolete' => false, 0252 'sup' => array(), 0253 'abstract' => false, 0254 'structural' => false, 0255 'auxiliary' => false, 0256 'must' => array(), 0257 'may' => array(), 0258 '_string' => $value, 0259 '_parents' => array()); 0260 0261 $tokens = $this->_tokenizeString($value); 0262 $objectClass['oid'] = array_shift($tokens); // first token is the oid 0263 $this->_parseLdapSchemaSyntax($objectClass, $tokens); 0264 0265 $this->_ensureNameAttribute($objectClass); 0266 0267 return $objectClass; 0268 } 0269 0270 /** 0271 * Resolves inheritance in objectClasses and attributes 0272 * 0273 * @param Zend_Ldap_Node_Schema_Item $node 0274 * @param array $repository 0275 */ 0276 protected function _resolveInheritance(Zend_Ldap_Node_Schema_Item $node, array $repository) 0277 { 0278 $data = $node->getData(); 0279 $parents = $data['sup']; 0280 if ($parents === null || !is_array($parents) || count($parents) < 1) return; 0281 foreach ($parents as $parent) { 0282 if (!array_key_exists($parent, $repository)) continue; 0283 if (!array_key_exists('_parents', $data) || !is_array($data['_parents'])) { 0284 $data['_parents'] = array(); 0285 } 0286 $data['_parents'][] = $repository[$parent]; 0287 } 0288 $node->setData($data); 0289 } 0290 0291 /** 0292 * Loads the LDAP syntaxes 0293 * 0294 * @return void 0295 */ 0296 protected function _loadLdapSyntaxes() 0297 { 0298 $this->_ldapSyntaxes = array(); 0299 foreach ($this->getAttribute('ldapSyntaxes') as $value) { 0300 $val = $this->_parseLdapSyntax($value); 0301 $this->_ldapSyntaxes[$val['oid']] = $val; 0302 } 0303 ksort($this->_ldapSyntaxes, SORT_STRING); 0304 } 0305 0306 /** 0307 * Parses an ldapSyntaxes value 0308 * 0309 * @param string $value 0310 * @return array 0311 */ 0312 protected function _parseLdapSyntax($value) 0313 { 0314 $ldapSyntax = array( 0315 'oid' => null, 0316 'desc' => null, 0317 '_string' => $value); 0318 0319 $tokens = $this->_tokenizeString($value); 0320 $ldapSyntax['oid'] = array_shift($tokens); // first token is the oid 0321 $this->_parseLdapSchemaSyntax($ldapSyntax, $tokens); 0322 0323 return $ldapSyntax; 0324 } 0325 0326 /** 0327 * Loads the matching rules 0328 * 0329 * @return void 0330 */ 0331 protected function _loadMatchingRules() 0332 { 0333 $this->_matchingRules = array(); 0334 foreach ($this->getAttribute('matchingRules') as $value) { 0335 $val = $this->_parseMatchingRule($value); 0336 $this->_matchingRules[$val['name']] = $val; 0337 } 0338 ksort($this->_matchingRules, SORT_STRING); 0339 } 0340 0341 /** 0342 * Parses an matchingRules value 0343 * 0344 * @param string $value 0345 * @return array 0346 */ 0347 protected function _parseMatchingRule($value) 0348 { 0349 $matchingRule = array( 0350 'oid' => null, 0351 'name' => null, 0352 'desc' => null, 0353 'obsolete' => false, 0354 'syntax' => null, 0355 '_string' => $value); 0356 0357 $tokens = $this->_tokenizeString($value); 0358 $matchingRule['oid'] = array_shift($tokens); // first token is the oid 0359 $this->_parseLdapSchemaSyntax($matchingRule, $tokens); 0360 0361 $this->_ensureNameAttribute($matchingRule); 0362 0363 return $matchingRule; 0364 } 0365 0366 /** 0367 * Loads the matching rule use 0368 * 0369 * @return void 0370 */ 0371 protected function _loadMatchingRuleUse() 0372 { 0373 $this->_matchingRuleUse = array(); 0374 foreach ($this->getAttribute('matchingRuleUse') as $value) { 0375 $val = $this->_parseMatchingRuleUse($value); 0376 $this->_matchingRuleUse[$val['name']] = $val; 0377 } 0378 ksort($this->_matchingRuleUse, SORT_STRING); 0379 } 0380 0381 /** 0382 * Parses an matchingRuleUse value 0383 * 0384 * @param string $value 0385 * @return array 0386 */ 0387 protected function _parseMatchingRuleUse($value) 0388 { 0389 $matchingRuleUse = array( 0390 'oid' => null, 0391 'name' => null, 0392 'desc' => null, 0393 'obsolete' => false, 0394 'applies' => array(), 0395 '_string' => $value); 0396 0397 $tokens = $this->_tokenizeString($value); 0398 $matchingRuleUse['oid'] = array_shift($tokens); // first token is the oid 0399 $this->_parseLdapSchemaSyntax($matchingRuleUse, $tokens); 0400 0401 $this->_ensureNameAttribute($matchingRuleUse); 0402 0403 return $matchingRuleUse; 0404 } 0405 0406 /** 0407 * Ensures that a name element is present and that it is single-values. 0408 * 0409 * @param array $data 0410 */ 0411 protected function _ensureNameAttribute(array &$data) 0412 { 0413 if (!array_key_exists('name', $data) || empty($data['name'])) { 0414 // force a name 0415 $data['name'] = $data['oid']; 0416 } 0417 if (is_array($data['name'])) { 0418 // make one name the default and put the other ones into aliases 0419 $aliases = $data['name']; 0420 $data['name'] = array_shift($aliases); 0421 $data['aliases'] = $aliases; 0422 } else { 0423 $data['aliases'] = array(); 0424 } 0425 } 0426 0427 /** 0428 * Parse the given tokens into a data structure 0429 * 0430 * @param array $data 0431 * @param array $tokens 0432 * @return void 0433 */ 0434 protected function _parseLdapSchemaSyntax(array &$data, array $tokens) 0435 { 0436 // tokens that have no value associated 0437 $noValue = array('single-value', 0438 'obsolete', 0439 'collective', 0440 'no-user-modification', 0441 'abstract', 0442 'structural', 0443 'auxiliary'); 0444 // tokens that can have multiple values 0445 $multiValue = array('must', 'may', 'sup'); 0446 0447 while (count($tokens) > 0) { 0448 $token = strtolower(array_shift($tokens)); 0449 if (in_array($token, $noValue)) { 0450 $data[$token] = true; // single value token 0451 } else { 0452 $data[$token] = array_shift($tokens); 0453 // this one follows a string or a list if it is multivalued 0454 if ($data[$token] == '(') { 0455 // this creates the list of values and cycles through the tokens 0456 // until the end of the list is reached ')' 0457 $data[$token] = array(); 0458 while ($tmp = array_shift($tokens)) { 0459 if ($tmp == ')') break; 0460 if ($tmp != '$') { 0461 $data[$token][] = Zend_Ldap_Attribute::convertFromLdapValue($tmp); 0462 } 0463 } 0464 } else { 0465 $data[$token] = Zend_Ldap_Attribute::convertFromLdapValue($data[$token]); 0466 } 0467 // create a array if the value should be multivalued but was not 0468 if (in_array($token, $multiValue) && !is_array($data[$token])) { 0469 $data[$token] = array($data[$token]); 0470 } 0471 } 0472 } 0473 } 0474 0475 /** 0476 * Tokenizes the given value into an array 0477 * 0478 * @param string $value 0479 * @return array tokens 0480 */ 0481 protected function _tokenizeString($value) 0482 { 0483 $tokens = array(); 0484 $matches = array(); 0485 // this one is taken from PEAR::Net_LDAP2 0486 $pattern = "/\s* (?:([()]) | ([^'\s()]+) | '((?:[^']+|'[^\s)])*)') \s*/x"; 0487 preg_match_all($pattern, $value, $matches); 0488 $cMatches = count($matches[0]); 0489 $cPattern = count($matches); 0490 for ($i = 0; $i < $cMatches; $i++) { // number of tokens (full pattern match) 0491 for ($j = 1; $j < $cPattern; $j++) { // each subpattern 0492 $tok = trim($matches[$j][$i]); 0493 if (!empty($tok)) { // pattern match in this subpattern 0494 $tokens[$i] = $tok; // this is the token 0495 } 0496 } 0497 } 0498 if ($tokens[0] == '(') array_shift($tokens); 0499 if ($tokens[count($tokens) - 1] == ')') array_pop($tokens); 0500 return $tokens; 0501 } 0502 }