PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Ldap/Node/Schema/OpenLdap.php

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