PageRenderTime 74ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/src/application/libraries/Zend/Ldap/Node.php

https://bitbucket.org/masnug/grc276-blog-laravel
PHP | 1106 lines | 462 code | 67 blank | 577 comment | 77 complexity | 2594244b626cac6d9165a269cfdbcdf0 MD5 | raw file
  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 Node
  18. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Node.php 24352 2011-08-04 20:53:04Z sgehrig $
  21. */
  22. /**
  23. * @see Zend_Ldap
  24. */
  25. require_once 'Zend/Ldap.php';
  26. /**
  27. * @see Zend_Ldap_Node_Abstract
  28. */
  29. require_once 'Zend/Ldap/Node/Abstract.php';
  30. /**
  31. * Zend_Ldap_Node provides an object oriented view into a LDAP node.
  32. *
  33. * @category Zend
  34. * @package Zend_Ldap
  35. * @subpackage Node
  36. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  37. * @license http://framework.zend.com/license/new-bsd New BSD License
  38. */
  39. class Zend_Ldap_Node extends Zend_Ldap_Node_Abstract implements Iterator, RecursiveIterator
  40. {
  41. /**
  42. * Holds the node's new DN if node is renamed.
  43. *
  44. * @var Zend_Ldap_Dn
  45. */
  46. protected $_newDn;
  47. /**
  48. * Holds the node's orginal attributes (as loaded).
  49. *
  50. * @var array
  51. */
  52. protected $_originalData;
  53. /**
  54. * This node will be added
  55. *
  56. * @var boolean
  57. */
  58. protected $_new;
  59. /**
  60. * This node will be deleted
  61. *
  62. * @var boolean
  63. */
  64. protected $_delete;
  65. /**
  66. * Holds the connection to the LDAP server if in connected mode.
  67. *
  68. * @var Zend_Ldap
  69. */
  70. protected $_ldap;
  71. /**
  72. * Holds an array of the current node's children.
  73. *
  74. * @var array
  75. */
  76. protected $_children;
  77. /**
  78. * Controls iteration status
  79. *
  80. * @var boolean
  81. */
  82. private $_iteratorRewind = false;
  83. /**
  84. * Constructor.
  85. *
  86. * Constructor is protected to enforce the use of factory methods.
  87. *
  88. * @param Zend_Ldap_Dn $dn
  89. * @param array $data
  90. * @param boolean $fromDataSource
  91. * @param Zend_Ldap $ldap
  92. * @throws Zend_Ldap_Exception
  93. */
  94. protected function __construct(Zend_Ldap_Dn $dn, array $data, $fromDataSource, Zend_Ldap $ldap = null)
  95. {
  96. parent::__construct($dn, $data, $fromDataSource);
  97. if ($ldap !== null) $this->attachLdap($ldap);
  98. else $this->detachLdap();
  99. }
  100. /**
  101. * Serialization callback
  102. *
  103. * Only DN and attributes will be serialized.
  104. *
  105. * @return array
  106. */
  107. public function __sleep()
  108. {
  109. return array('_dn', '_currentData', '_newDn', '_originalData',
  110. '_new', '_delete', '_children');
  111. }
  112. /**
  113. * Deserialization callback
  114. *
  115. * Enforces a detached node.
  116. *
  117. * @return null
  118. */
  119. public function __wakeup()
  120. {
  121. $this->detachLdap();
  122. }
  123. /**
  124. * Gets the current LDAP connection.
  125. *
  126. * @return Zend_Ldap
  127. * @throws Zend_Ldap_Exception
  128. */
  129. public function getLdap()
  130. {
  131. if ($this->_ldap === null) {
  132. /**
  133. * @see Zend_Ldap_Exception
  134. */
  135. require_once 'Zend/Ldap/Exception.php';
  136. throw new Zend_Ldap_Exception(null, 'No LDAP connection specified.', Zend_Ldap_Exception::LDAP_OTHER);
  137. }
  138. else return $this->_ldap;
  139. }
  140. /**
  141. * Attach node to an LDAP connection
  142. *
  143. * This is an offline method.
  144. *
  145. * @uses Zend_Ldap_Dn::isChildOf()
  146. * @param Zend_Ldap $ldap
  147. * @return Zend_Ldap_Node Provides a fluid interface
  148. * @throws Zend_Ldap_Exception
  149. */
  150. public function attachLdap(Zend_Ldap $ldap)
  151. {
  152. if (!Zend_Ldap_Dn::isChildOf($this->_getDn(), $ldap->getBaseDn())) {
  153. /**
  154. * @see Zend_Ldap_Exception
  155. */
  156. require_once 'Zend/Ldap/Exception.php';
  157. throw new Zend_Ldap_Exception(null, 'LDAP connection is not responsible for given node.',
  158. Zend_Ldap_Exception::LDAP_OTHER);
  159. }
  160. if ($ldap !== $this->_ldap) {
  161. $this->_ldap = $ldap;
  162. if (is_array($this->_children)) {
  163. foreach ($this->_children as $child) {
  164. $child->attachLdap($ldap);
  165. }
  166. }
  167. }
  168. return $this;
  169. }
  170. /**
  171. * Detach node from LDAP connection
  172. *
  173. * This is an offline method.
  174. *
  175. * @return Zend_Ldap_Node Provides a fluid interface
  176. */
  177. public function detachLdap()
  178. {
  179. $this->_ldap = null;
  180. if (is_array($this->_children)) {
  181. foreach ($this->_children as $child) {
  182. $child->detachLdap();
  183. }
  184. }
  185. return $this;
  186. }
  187. /**
  188. * Checks if the current node is attached to a LDAP server.
  189. *
  190. * This is an offline method.
  191. *
  192. * @return boolean
  193. */
  194. public function isAttached()
  195. {
  196. return ($this->_ldap !== null);
  197. }
  198. /**
  199. * @param array $data
  200. * @param boolean $fromDataSource
  201. * @throws Zend_Ldap_Exception
  202. */
  203. protected function _loadData(array $data, $fromDataSource)
  204. {
  205. parent::_loadData($data, $fromDataSource);
  206. if ($fromDataSource === true) {
  207. $this->_originalData = $data;
  208. } else {
  209. $this->_originalData = array();
  210. }
  211. $this->_children = null;
  212. $this->_markAsNew(($fromDataSource === true) ? false : true);
  213. $this->_markAsToBeDeleted(false);
  214. }
  215. /**
  216. * Factory method to create a new detached Zend_Ldap_Node for a given DN.
  217. *
  218. * @param string|array|Zend_Ldap_Dn $dn
  219. * @param array $objectClass
  220. * @return Zend_Ldap_Node
  221. * @throws Zend_Ldap_Exception
  222. */
  223. public static function create($dn, array $objectClass = array())
  224. {
  225. if (is_string($dn) || is_array($dn)) {
  226. $dn = Zend_Ldap_Dn::factory($dn);
  227. } else if ($dn instanceof Zend_Ldap_Dn) {
  228. $dn = clone $dn;
  229. } else {
  230. /**
  231. * @see Zend_Ldap_Exception
  232. */
  233. require_once 'Zend/Ldap/Exception.php';
  234. throw new Zend_Ldap_Exception(null, '$dn is of a wrong data type.');
  235. }
  236. $new = new self($dn, array(), false, null);
  237. $new->_ensureRdnAttributeValues();
  238. $new->setAttribute('objectClass', $objectClass);
  239. return $new;
  240. }
  241. /**
  242. * Factory method to create an attached Zend_Ldap_Node for a given DN.
  243. *
  244. * @param string|array|Zend_Ldap_Dn $dn
  245. * @param Zend_Ldap $ldap
  246. * @return Zend_Ldap_Node|null
  247. * @throws Zend_Ldap_Exception
  248. */
  249. public static function fromLdap($dn, Zend_Ldap $ldap)
  250. {
  251. if (is_string($dn) || is_array($dn)) {
  252. $dn = Zend_Ldap_Dn::factory($dn);
  253. } else if ($dn instanceof Zend_Ldap_Dn) {
  254. $dn = clone $dn;
  255. } else {
  256. /**
  257. * @see Zend_Ldap_Exception
  258. */
  259. require_once 'Zend/Ldap/Exception.php';
  260. throw new Zend_Ldap_Exception(null, '$dn is of a wrong data type.');
  261. }
  262. $data = $ldap->getEntry($dn, array('*', '+'), true);
  263. if ($data === null) {
  264. return null;
  265. }
  266. $entry = new self($dn, $data, true, $ldap);
  267. return $entry;
  268. }
  269. /**
  270. * Factory method to create a detached Zend_Ldap_Node from array data.
  271. *
  272. * @param array $data
  273. * @param boolean $fromDataSource
  274. * @return Zend_Ldap_Node
  275. * @throws Zend_Ldap_Exception
  276. */
  277. public static function fromArray(array $data, $fromDataSource = false)
  278. {
  279. if (!array_key_exists('dn', $data)) {
  280. /**
  281. * @see Zend_Ldap_Exception
  282. */
  283. require_once 'Zend/Ldap/Exception.php';
  284. throw new Zend_Ldap_Exception(null, '\'dn\' key is missing in array.');
  285. }
  286. if (is_string($data['dn']) || is_array($data['dn'])) {
  287. $dn = Zend_Ldap_Dn::factory($data['dn']);
  288. } else if ($data['dn'] instanceof Zend_Ldap_Dn) {
  289. $dn = clone $data['dn'];
  290. } else {
  291. /**
  292. * @see Zend_Ldap_Exception
  293. */
  294. require_once 'Zend/Ldap/Exception.php';
  295. throw new Zend_Ldap_Exception(null, '\'dn\' key is of a wrong data type.');
  296. }
  297. $fromDataSource = ($fromDataSource === true) ? true : false;
  298. $new = new self($dn, $data, $fromDataSource, null);
  299. $new->_ensureRdnAttributeValues();
  300. return $new;
  301. }
  302. /**
  303. * Ensures that teh RDN attributes are correctly set.
  304. *
  305. * @param boolean $overwrite True to overwrite the RDN attributes
  306. * @return void
  307. */
  308. protected function _ensureRdnAttributeValues($overwrite = false)
  309. {
  310. foreach ($this->getRdnArray() as $key => $value) {
  311. if (!array_key_exists($key, $this->_currentData) || $overwrite) {
  312. Zend_Ldap_Attribute::setAttribute($this->_currentData, $key, $value, false);
  313. } else if (!in_array($value, $this->_currentData[$key])) {
  314. Zend_Ldap_Attribute::setAttribute($this->_currentData, $key, $value, true);
  315. }
  316. }
  317. }
  318. /**
  319. * Marks this node as new.
  320. *
  321. * Node will be added (instead of updated) on calling update() if $new is true.
  322. *
  323. * @param boolean $new
  324. */
  325. protected function _markAsNew($new)
  326. {
  327. $this->_new = ($new === false) ? false : true;
  328. }
  329. /**
  330. * Tells if the node is consiedered as new (not present on the server)
  331. *
  332. * Please note, that this doesn't tell you if the node is present on the server.
  333. * Use {@link exits()} to see if a node is already there.
  334. *
  335. * @return boolean
  336. */
  337. public function isNew()
  338. {
  339. return $this->_new;
  340. }
  341. /**
  342. * Marks this node as to be deleted.
  343. *
  344. * Node will be deleted on calling update() if $delete is true.
  345. *
  346. * @param boolean $delete
  347. */
  348. protected function _markAsToBeDeleted($delete)
  349. {
  350. $this->_delete = ($delete === true) ? true : false;
  351. }
  352. /**
  353. * Is this node going to be deleted once update() is called?
  354. *
  355. * @return boolean
  356. */
  357. public function willBeDeleted()
  358. {
  359. return $this->_delete;
  360. }
  361. /**
  362. * Marks this node as to be deleted
  363. *
  364. * Node will be deleted on calling update() if $delete is true.
  365. *
  366. * @return Zend_Ldap_Node Provides a fluid interface
  367. */
  368. public function delete()
  369. {
  370. $this->_markAsToBeDeleted(true);
  371. return $this;
  372. }
  373. /**
  374. * Is this node going to be moved once update() is called?
  375. *
  376. * @return boolean
  377. */
  378. public function willBeMoved()
  379. {
  380. if ($this->isNew() || $this->willBeDeleted()) {
  381. return false;
  382. } else if ($this->_newDn !== null) {
  383. return ($this->_dn != $this->_newDn);
  384. } else {
  385. return false;
  386. }
  387. }
  388. /**
  389. * Sends all pending changes to the LDAP server
  390. *
  391. * @param Zend_Ldap $ldap
  392. * @return Zend_Ldap_Node Provides a fluid interface
  393. * @throws Zend_Ldap_Exception
  394. */
  395. public function update(Zend_Ldap $ldap = null)
  396. {
  397. if ($ldap !== null) {
  398. $this->attachLdap($ldap);
  399. }
  400. $ldap = $this->getLdap();
  401. if (!($ldap instanceof Zend_Ldap)) {
  402. /**
  403. * @see Zend_Ldap_Exception
  404. */
  405. require_once 'Zend/Ldap/Exception.php';
  406. throw new Zend_Ldap_Exception(null, 'No LDAP connection available');
  407. }
  408. if ($this->willBeDeleted()) {
  409. if ($ldap->exists($this->_dn)) {
  410. $ldap->delete($this->_dn);
  411. }
  412. return $this;
  413. }
  414. if ($this->isNew()) {
  415. $data = $this->getData();
  416. $ldap->add($this->_getDn(), $data);
  417. $this->_loadData($data, true);
  418. return $this;
  419. }
  420. $changedData = $this->getChangedData();
  421. if ($this->willBeMoved()) {
  422. $recursive = $this->hasChildren();
  423. $ldap->rename($this->_dn, $this->_newDn, $recursive, false);
  424. foreach ($this->_newDn->getRdn() as $key => $value) {
  425. if (array_key_exists($key, $changedData)) {
  426. unset($changedData[$key]);
  427. }
  428. }
  429. $this->_dn = $this->_newDn;
  430. $this->_newDn = null;
  431. }
  432. if (count($changedData) > 0) {
  433. $ldap->update($this->_getDn(), $changedData);
  434. }
  435. $this->_originalData = $this->_currentData;
  436. return $this;
  437. }
  438. /**
  439. * Gets the DN of the current node as a Zend_Ldap_Dn.
  440. *
  441. * This is an offline method.
  442. *
  443. * @return Zend_Ldap_Dn
  444. */
  445. protected function _getDn()
  446. {
  447. return ($this->_newDn === null) ? parent::_getDn() : $this->_newDn;
  448. }
  449. /**
  450. * Gets the current DN of the current node as a Zend_Ldap_Dn.
  451. * The method returns a clone of the node's DN to prohibit modification.
  452. *
  453. * This is an offline method.
  454. *
  455. * @return Zend_Ldap_Dn
  456. */
  457. public function getCurrentDn()
  458. {
  459. $dn = clone parent::_getDn();
  460. return $dn;
  461. }
  462. /**
  463. * Sets the new DN for this node
  464. *
  465. * This is an offline method.
  466. *
  467. * @param Zend_Ldap_Dn|string|array $newDn
  468. * @throws Zend_Ldap_Exception
  469. * @return Zend_Ldap_Node Provides a fluid interface
  470. */
  471. public function setDn($newDn)
  472. {
  473. if ($newDn instanceof Zend_Ldap_Dn) {
  474. $this->_newDn = clone $newDn;
  475. } else {
  476. $this->_newDn = Zend_Ldap_Dn::factory($newDn);
  477. }
  478. $this->_ensureRdnAttributeValues(true);
  479. return $this;
  480. }
  481. /**
  482. * {@see setDn()}
  483. *
  484. * This is an offline method.
  485. *
  486. * @param Zend_Ldap_Dn|string|array $newDn
  487. * @throws Zend_Ldap_Exception
  488. * @return Zend_Ldap_Node Provides a fluid interface
  489. */
  490. public function move($newDn)
  491. {
  492. return $this->setDn($newDn);
  493. }
  494. /**
  495. * {@see setDn()}
  496. *
  497. * This is an offline method.
  498. *
  499. * @param Zend_Ldap_Dn|string|array $newDn
  500. * @throws Zend_Ldap_Exception
  501. * @return Zend_Ldap_Node Provides a fluid interface
  502. */
  503. public function rename($newDn)
  504. {
  505. return $this->setDn($newDn);
  506. }
  507. /**
  508. * Sets the objectClass.
  509. *
  510. * This is an offline method.
  511. *
  512. * @param array|string $value
  513. * @return Zend_Ldap_Node Provides a fluid interface
  514. * @throws Zend_Ldap_Exception
  515. */
  516. public function setObjectClass($value)
  517. {
  518. $this->setAttribute('objectClass', $value);
  519. return $this;
  520. }
  521. /**
  522. * Appends to the objectClass.
  523. *
  524. * This is an offline method.
  525. *
  526. * @param array|string $value
  527. * @return Zend_Ldap_Node Provides a fluid interface
  528. * @throws Zend_Ldap_Exception
  529. */
  530. public function appendObjectClass($value)
  531. {
  532. $this->appendToAttribute('objectClass', $value);
  533. return $this;
  534. }
  535. /**
  536. * Returns a LDIF representation of the current node
  537. *
  538. * @param array $options Additional options used during encoding
  539. * @return string
  540. */
  541. public function toLdif(array $options = array())
  542. {
  543. $attributes = array_merge(array('dn' => $this->getDnString()), $this->getData(false));
  544. /**
  545. * Zend_Ldap_Ldif_Encoder
  546. */
  547. require_once 'Zend/Ldap/Ldif/Encoder.php';
  548. return Zend_Ldap_Ldif_Encoder::encode($attributes, $options);
  549. }
  550. /**
  551. * Gets changed node data.
  552. *
  553. * The array contains all changed attributes.
  554. * This format can be used in {@link Zend_Ldap::add()} and {@link Zend_Ldap::update()}.
  555. *
  556. * This is an offline method.
  557. *
  558. * @return array
  559. */
  560. public function getChangedData()
  561. {
  562. $changed = array();
  563. foreach ($this->_currentData as $key => $value) {
  564. if (!array_key_exists($key, $this->_originalData) && !empty($value)) {
  565. $changed[$key] = $value;
  566. } else if ($this->_originalData[$key] !== $this->_currentData[$key]) {
  567. $changed[$key] = $value;
  568. }
  569. }
  570. return $changed;
  571. }
  572. /**
  573. * Returns all changes made.
  574. *
  575. * This is an offline method.
  576. *
  577. * @return array
  578. */
  579. public function getChanges()
  580. {
  581. $changes = array(
  582. 'add' => array(),
  583. 'delete' => array(),
  584. 'replace' => array());
  585. foreach ($this->_currentData as $key => $value) {
  586. if (!array_key_exists($key, $this->_originalData) && !empty($value)) {
  587. $changes['add'][$key] = $value;
  588. } else if (count($this->_originalData[$key]) === 0 && !empty($value)) {
  589. $changes['add'][$key] = $value;
  590. } else if ($this->_originalData[$key] !== $this->_currentData[$key]) {
  591. if (empty($value)) {
  592. $changes['delete'][$key] = $value;
  593. } else {
  594. $changes['replace'][$key] = $value;
  595. }
  596. }
  597. }
  598. return $changes;
  599. }
  600. /**
  601. * Sets a LDAP attribute.
  602. *
  603. * This is an offline method.
  604. *
  605. * @param string $name
  606. * @param mixed $value
  607. * @return Zend_Ldap_Node Provides a fluid interface
  608. * @throws Zend_Ldap_Exception
  609. */
  610. public function setAttribute($name, $value)
  611. {
  612. $this->_setAttribute($name, $value, false);
  613. return $this;
  614. }
  615. /**
  616. * Appends to a LDAP attribute.
  617. *
  618. * This is an offline method.
  619. *
  620. * @param string $name
  621. * @param mixed $value
  622. * @return Zend_Ldap_Node Provides a fluid interface
  623. * @throws Zend_Ldap_Exception
  624. */
  625. public function appendToAttribute($name, $value)
  626. {
  627. $this->_setAttribute($name, $value, true);
  628. return $this;
  629. }
  630. /**
  631. * Checks if the attribute can be set and sets it accordingly.
  632. *
  633. * @param string $name
  634. * @param mixed $value
  635. * @param boolean $append
  636. * @throws Zend_Ldap_Exception
  637. */
  638. protected function _setAttribute($name, $value, $append)
  639. {
  640. $this->_assertChangeableAttribute($name);
  641. Zend_Ldap_Attribute::setAttribute($this->_currentData, $name, $value, $append);
  642. }
  643. /**
  644. * Sets a LDAP date/time attribute.
  645. *
  646. * This is an offline method.
  647. *
  648. * @param string $name
  649. * @param integer|array $value
  650. * @param boolean $utc
  651. * @return Zend_Ldap_Node Provides a fluid interface
  652. * @throws Zend_Ldap_Exception
  653. */
  654. public function setDateTimeAttribute($name, $value, $utc = false)
  655. {
  656. $this->_setDateTimeAttribute($name, $value, $utc, false);
  657. return $this;
  658. }
  659. /**
  660. * Appends to a LDAP date/time attribute.
  661. *
  662. * This is an offline method.
  663. *
  664. * @param string $name
  665. * @param integer|array $value
  666. * @param boolean $utc
  667. * @return Zend_Ldap_Node Provides a fluid interface
  668. * @throws Zend_Ldap_Exception
  669. */
  670. public function appendToDateTimeAttribute($name, $value, $utc = false)
  671. {
  672. $this->_setDateTimeAttribute($name, $value, $utc, true);
  673. return $this;
  674. }
  675. /**
  676. * Checks if the attribute can be set and sets it accordingly.
  677. *
  678. * @param string $name
  679. * @param integer|array $value
  680. * @param boolean $utc
  681. * @param boolean $append
  682. * @throws Zend_Ldap_Exception
  683. */
  684. protected function _setDateTimeAttribute($name, $value, $utc, $append)
  685. {
  686. $this->_assertChangeableAttribute($name);
  687. Zend_Ldap_Attribute::setDateTimeAttribute($this->_currentData, $name, $value, $utc, $append);
  688. }
  689. /**
  690. * Sets a LDAP password.
  691. *
  692. * @param string $password
  693. * @param string $hashType
  694. * @param string $attribName
  695. * @return Zend_Ldap_Node Provides a fluid interface
  696. * @throws Zend_Ldap_Exception
  697. */
  698. public function setPasswordAttribute($password, $hashType = Zend_Ldap_Attribute::PASSWORD_HASH_MD5,
  699. $attribName = 'userPassword')
  700. {
  701. $this->_assertChangeableAttribute($attribName);
  702. Zend_Ldap_Attribute::setPassword($this->_currentData, $password, $hashType, $attribName);
  703. return $this;
  704. }
  705. /**
  706. * Deletes a LDAP attribute.
  707. *
  708. * This method deletes the attribute.
  709. *
  710. * This is an offline method.
  711. *
  712. * @param string $name
  713. * @return Zend_Ldap_Node Provides a fluid interface
  714. * @throws Zend_Ldap_Exception
  715. */
  716. public function deleteAttribute($name)
  717. {
  718. if ($this->existsAttribute($name, true)) {
  719. $this->_setAttribute($name, null, false);
  720. }
  721. return $this;
  722. }
  723. /**
  724. * Removes duplicate values from a LDAP attribute
  725. *
  726. * @param string $attribName
  727. * @return void
  728. */
  729. public function removeDuplicatesFromAttribute($attribName)
  730. {
  731. Zend_Ldap_Attribute::removeDuplicatesFromAttribute($this->_currentData, $attribName);
  732. }
  733. /**
  734. * Remove given values from a LDAP attribute
  735. *
  736. * @param string $attribName
  737. * @param mixed|array $value
  738. * @return void
  739. */
  740. public function removeFromAttribute($attribName, $value)
  741. {
  742. Zend_Ldap_Attribute::removeFromAttribute($this->_currentData, $attribName, $value);
  743. }
  744. /**
  745. * @param string $name
  746. * @return boolean
  747. * @throws Zend_Ldap_Exception
  748. */
  749. protected function _assertChangeableAttribute($name)
  750. {
  751. $name = strtolower($name);
  752. $rdn = $this->getRdnArray(Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER);
  753. if ($name == 'dn') {
  754. /**
  755. * @see Zend_Ldap_Exception
  756. */
  757. require_once 'Zend/Ldap/Exception.php';
  758. throw new Zend_Ldap_Exception(null, 'DN cannot be changed.');
  759. }
  760. else if (array_key_exists($name, $rdn)) {
  761. /**
  762. * @see Zend_Ldap_Exception
  763. */
  764. require_once 'Zend/Ldap/Exception.php';
  765. throw new Zend_Ldap_Exception(null, 'Cannot change attribute because it\'s part of the RDN');
  766. } else if (in_array($name, self::$_systemAttributes)) {
  767. /**
  768. * @see Zend_Ldap_Exception
  769. */
  770. require_once 'Zend/Ldap/Exception.php';
  771. throw new Zend_Ldap_Exception(null, 'Cannot change attribute because it\'s read-only');
  772. }
  773. else return true;
  774. }
  775. /**
  776. * Sets a LDAP attribute.
  777. *
  778. * This is an offline method.
  779. *
  780. * @param string $name
  781. * @param mixed $value
  782. * @return null
  783. * @throws Zend_Ldap_Exception
  784. */
  785. public function __set($name, $value)
  786. {
  787. $this->setAttribute($name, $value);
  788. }
  789. /**
  790. * Deletes a LDAP attribute.
  791. *
  792. * This method deletes the attribute.
  793. *
  794. * This is an offline method.
  795. *
  796. * @param string $name
  797. * @return null
  798. * @throws Zend_Ldap_Exception
  799. */
  800. public function __unset($name)
  801. {
  802. $this->deleteAttribute($name);
  803. }
  804. /**
  805. * Sets a LDAP attribute.
  806. * Implements ArrayAccess.
  807. *
  808. * This is an offline method.
  809. *
  810. * @param string $name
  811. * @param mixed $value
  812. * @return null
  813. * @throws Zend_Ldap_Exception
  814. */
  815. public function offsetSet($name, $value)
  816. {
  817. $this->setAttribute($name, $value);
  818. }
  819. /**
  820. * Deletes a LDAP attribute.
  821. * Implements ArrayAccess.
  822. *
  823. * This method deletes the attribute.
  824. *
  825. * This is an offline method.
  826. *
  827. * @param string $name
  828. * @return null
  829. * @throws Zend_Ldap_Exception
  830. */
  831. public function offsetUnset($name)
  832. {
  833. $this->deleteAttribute($name);
  834. }
  835. /**
  836. * Check if node exists on LDAP.
  837. *
  838. * This is an online method.
  839. *
  840. * @param Zend_Ldap $ldap
  841. * @return boolean
  842. * @throws Zend_Ldap_Exception
  843. */
  844. public function exists(Zend_Ldap $ldap = null)
  845. {
  846. if ($ldap !== null) {
  847. $this->attachLdap($ldap);
  848. }
  849. $ldap = $this->getLdap();
  850. return $ldap->exists($this->_getDn());
  851. }
  852. /**
  853. * Reload node attributes from LDAP.
  854. *
  855. * This is an online method.
  856. *
  857. * @param Zend_Ldap $ldap
  858. * @return Zend_Ldap_Node Provides a fluid interface
  859. * @throws Zend_Ldap_Exception
  860. */
  861. public function reload(Zend_Ldap $ldap = null)
  862. {
  863. if ($ldap !== null) {
  864. $this->attachLdap($ldap);
  865. }
  866. $ldap = $this->getLdap();
  867. parent::reload($ldap);
  868. return $this;
  869. }
  870. /**
  871. * Search current subtree with given options.
  872. *
  873. * This is an online method.
  874. *
  875. * @param string|Zend_Ldap_Filter_Abstract $filter
  876. * @param integer $scope
  877. * @param string $sort
  878. * @return Zend_Ldap_Node_Collection
  879. * @throws Zend_Ldap_Exception
  880. */
  881. public function searchSubtree($filter, $scope = Zend_Ldap::SEARCH_SCOPE_SUB, $sort = null)
  882. {
  883. /**
  884. * @see Zend_Ldap_Node_Collection
  885. */
  886. require_once 'Zend/Ldap/Node/Collection.php';
  887. return $this->getLdap()->search($filter, $this->_getDn(), $scope, array('*', '+'), $sort,
  888. 'Zend_Ldap_Node_Collection');
  889. }
  890. /**
  891. * Count items in current subtree found by given filter.
  892. *
  893. * This is an online method.
  894. *
  895. * @param string|Zend_Ldap_Filter_Abstract $filter
  896. * @param integer $scope
  897. * @return integer
  898. * @throws Zend_Ldap_Exception
  899. */
  900. public function countSubtree($filter, $scope = Zend_Ldap::SEARCH_SCOPE_SUB)
  901. {
  902. return $this->getLdap()->count($filter, $this->_getDn(), $scope);
  903. }
  904. /**
  905. * Count children of current node.
  906. *
  907. * This is an online method.
  908. *
  909. * @return integer
  910. * @throws Zend_Ldap_Exception
  911. */
  912. public function countChildren()
  913. {
  914. return $this->countSubtree('(objectClass=*)', Zend_Ldap::SEARCH_SCOPE_ONE);
  915. }
  916. /**
  917. * Gets children of current node.
  918. *
  919. * This is an online method.
  920. *
  921. * @param string|Zend_Ldap_Filter_Abstract $filter
  922. * @param string $sort
  923. * @return Zend_Ldap_Node_Collection
  924. * @throws Zend_Ldap_Exception
  925. */
  926. public function searchChildren($filter, $sort = null)
  927. {
  928. return $this->searchSubtree($filter, Zend_Ldap::SEARCH_SCOPE_ONE, $sort);
  929. }
  930. /**
  931. * Checks if current node has children.
  932. * Returns whether the current element has children.
  933. *
  934. * Can be used offline but returns false if children have not been retrieved yet.
  935. *
  936. * @return boolean
  937. * @throws Zend_Ldap_Exception
  938. */
  939. public function hasChildren()
  940. {
  941. if (!is_array($this->_children)) {
  942. if ($this->isAttached()) {
  943. return ($this->countChildren() > 0);
  944. } else {
  945. return false;
  946. }
  947. } else {
  948. return (count($this->_children) > 0);
  949. }
  950. }
  951. /**
  952. * Returns the children for the current node.
  953. *
  954. * Can be used offline but returns an empty array if children have not been retrieved yet.
  955. *
  956. * @return Zend_Ldap_Node_ChildrenIterator
  957. * @throws Zend_Ldap_Exception
  958. */
  959. public function getChildren()
  960. {
  961. if (!is_array($this->_children)) {
  962. $this->_children = array();
  963. if ($this->isAttached()) {
  964. $children = $this->searchChildren('(objectClass=*)', null);
  965. foreach ($children as $child) {
  966. $this->_children[$child->getRdnString(Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER)] = $child;
  967. }
  968. }
  969. }
  970. /**
  971. * @see Zend_Ldap_Node_ChildrenIterator
  972. */
  973. require_once 'Zend/Ldap/Node/ChildrenIterator.php';
  974. return new Zend_Ldap_Node_ChildrenIterator($this->_children);
  975. }
  976. /**
  977. * Returns the parent of the current node.
  978. *
  979. * @param Zend_Ldap $ldap
  980. * @return Zend_Ldap_Node
  981. * @throws Zend_Ldap_Exception
  982. */
  983. public function getParent(Zend_Ldap $ldap = null)
  984. {
  985. if ($ldap !== null) {
  986. $this->attachLdap($ldap);
  987. }
  988. $ldap = $this->getLdap();
  989. $parentDn = $this->_getDn()->getParentDn(1);
  990. return self::fromLdap($parentDn, $ldap);
  991. }
  992. /**
  993. * Return the current attribute.
  994. * Implements Iterator
  995. *
  996. * @return array
  997. */
  998. public function current()
  999. {
  1000. return $this;
  1001. }
  1002. /**
  1003. * Return the attribute name.
  1004. * Implements Iterator
  1005. *
  1006. * @return string
  1007. */
  1008. public function key()
  1009. {
  1010. return $this->getRdnString();
  1011. }
  1012. /**
  1013. * Move forward to next attribute.
  1014. * Implements Iterator
  1015. */
  1016. public function next()
  1017. {
  1018. $this->_iteratorRewind = false;
  1019. }
  1020. /**
  1021. * Rewind the Iterator to the first attribute.
  1022. * Implements Iterator
  1023. */
  1024. public function rewind()
  1025. {
  1026. $this->_iteratorRewind = true;
  1027. }
  1028. /**
  1029. * Check if there is a current attribute
  1030. * after calls to rewind() or next().
  1031. * Implements Iterator
  1032. *
  1033. * @return boolean
  1034. */
  1035. public function valid()
  1036. {
  1037. return $this->_iteratorRewind;
  1038. }
  1039. }