File indexing completed on 2024-06-23 05:55:26

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 }