00001 <?php
00026 require_once 'Zend/Acl/Resource/Interface.php';
00027
00028
00032 require_once 'Zend/Acl/Role/Registry.php';
00033
00034
00038 require_once 'Zend/Acl/Assert/Interface.php';
00039
00040
00047 class Zend_Acl
00048 {
00052 const TYPE_ALLOW = 'TYPE_ALLOW';
00053
00057 const TYPE_DENY = 'TYPE_DENY';
00058
00062 const OP_ADD = 'OP_ADD';
00063
00067 const OP_REMOVE = 'OP_REMOVE';
00068
00074 protected $_roleRegistry = null;
00075
00081 protected $_resources = array();
00082
00086 protected $_isAllowedRole = null;
00087
00091 protected $_isAllowedResource = null;
00092
00098 protected $_rules = array(
00099 'allResources' => array(
00100 'allRoles' => array(
00101 'allPrivileges' => array(
00102 'type' => self::TYPE_DENY,
00103 'assert' => null
00104 ),
00105 'byPrivilegeId' => array()
00106 ),
00107 'byRoleId' => array()
00108 ),
00109 'byResourceId' => array()
00110 );
00111
00131 public function addRole($role, $parents = null)
00132 {
00133 if (is_string($role)) {
00134 $role = new Zend_Acl_Role($role);
00135 }
00136
00137 if (!$role instanceof Zend_Acl_Role_Interface) {
00138 require_once 'Zend/Acl/Exception.php';
00139 throw new Zend_Acl_Exception('addRole() expects $role to be of type Zend_Acl_Role_Interface');
00140 }
00141
00142
00143 $this->_getRoleRegistry()->add($role, $parents);
00144
00145 return $this;
00146 }
00147
00157 public function getRole($role)
00158 {
00159 return $this->_getRoleRegistry()->get($role);
00160 }
00161
00171 public function hasRole($role)
00172 {
00173 return $this->_getRoleRegistry()->has($role);
00174 }
00175
00191 public function inheritsRole($role, $inherit, $onlyParents = false)
00192 {
00193 return $this->_getRoleRegistry()->inherits($role, $inherit, $onlyParents);
00194 }
00195
00205 public function removeRole($role)
00206 {
00207 $this->_getRoleRegistry()->remove($role);
00208
00209 if ($role instanceof Zend_Acl_Role_Interface) {
00210 $roleId = $role->getRoleId();
00211 } else {
00212 $roleId = $role;
00213 }
00214
00215 foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) {
00216 if ($roleId === $roleIdCurrent) {
00217 unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]);
00218 }
00219 }
00220 foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) {
00221 if (array_key_exists('byRoleId', $visitor)) {
00222 foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) {
00223 if ($roleId === $roleIdCurrent) {
00224 unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]);
00225 }
00226 }
00227 }
00228 }
00229
00230 return $this;
00231 }
00232
00239 public function removeRoleAll()
00240 {
00241 $this->_getRoleRegistry()->removeAll();
00242
00243 foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) {
00244 unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]);
00245 }
00246 foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) {
00247 foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) {
00248 unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]);
00249 }
00250 }
00251
00252 return $this;
00253 }
00254
00266 public function addResource($resource, $parent = null)
00267 {
00268 if (is_string($resource)) {
00269 $resource = new Zend_Acl_Resource($resource);
00270 }
00271
00272 if (!$resource instanceof Zend_Acl_Resource_Interface) {
00273 require_once 'Zend/Acl/Exception.php';
00274 throw new Zend_Acl_Exception('addResource() expects $resource to be of type Zend_Acl_Resource_Interface');
00275 }
00276
00277 $resourceId = $resource->getResourceId();
00278
00279 if ($this->has($resourceId)) {
00280 require_once 'Zend/Acl/Exception.php';
00281 throw new Zend_Acl_Exception("Resource id '$resourceId' already exists in the ACL");
00282 }
00283
00284 $resourceParent = null;
00285
00286 if (null !== $parent) {
00287 try {
00288 if ($parent instanceof Zend_Acl_Resource_Interface) {
00289 $resourceParentId = $parent->getResourceId();
00290 } else {
00291 $resourceParentId = $parent;
00292 }
00293 $resourceParent = $this->get($resourceParentId);
00294 } catch (Zend_Acl_Exception $e) {
00295 throw new Zend_Acl_Exception("Parent Resource id '$resourceParentId' does not exist");
00296 }
00297 $this->_resources[$resourceParentId]['children'][$resourceId] = $resource;
00298 }
00299
00300 $this->_resources[$resourceId] = array(
00301 'instance' => $resource,
00302 'parent' => $resourceParent,
00303 'children' => array()
00304 );
00305
00306 return $this;
00307 }
00308
00323 public function add(Zend_Acl_Resource_Interface $resource, $parent = null)
00324 {
00325 return $this->addResource($resource, $parent);
00326 }
00327
00337 public function get($resource)
00338 {
00339 if ($resource instanceof Zend_Acl_Resource_Interface) {
00340 $resourceId = $resource->getResourceId();
00341 } else {
00342 $resourceId = (string) $resource;
00343 }
00344
00345 if (!$this->has($resource)) {
00346 require_once 'Zend/Acl/Exception.php';
00347 throw new Zend_Acl_Exception("Resource '$resourceId' not found");
00348 }
00349
00350 return $this->_resources[$resourceId]['instance'];
00351 }
00352
00361 public function has($resource)
00362 {
00363 if ($resource instanceof Zend_Acl_Resource_Interface) {
00364 $resourceId = $resource->getResourceId();
00365 } else {
00366 $resourceId = (string) $resource;
00367 }
00368
00369 return isset($this->_resources[$resourceId]);
00370 }
00371
00387 public function inherits($resource, $inherit, $onlyParent = false)
00388 {
00389 try {
00390 $resourceId = $this->get($resource)->getResourceId();
00391 $inheritId = $this->get($inherit)->getResourceId();
00392 } catch (Zend_Acl_Exception $e) {
00393 throw $e;
00394 }
00395
00396 if (null !== $this->_resources[$resourceId]['parent']) {
00397 $parentId = $this->_resources[$resourceId]['parent']->getResourceId();
00398 if ($inheritId === $parentId) {
00399 return true;
00400 } else if ($onlyParent) {
00401 return false;
00402 }
00403 } else {
00404 return false;
00405 }
00406
00407 while (null !== $this->_resources[$parentId]['parent']) {
00408 $parentId = $this->_resources[$parentId]['parent']->getResourceId();
00409 if ($inheritId === $parentId) {
00410 return true;
00411 }
00412 }
00413
00414 return false;
00415 }
00416
00426 public function remove($resource)
00427 {
00428 try {
00429 $resourceId = $this->get($resource)->getResourceId();
00430 } catch (Zend_Acl_Exception $e) {
00431 throw $e;
00432 }
00433
00434 $resourcesRemoved = array($resourceId);
00435 if (null !== ($resourceParent = $this->_resources[$resourceId]['parent'])) {
00436 unset($this->_resources[$resourceParent->getResourceId()]['children'][$resourceId]);
00437 }
00438 foreach ($this->_resources[$resourceId]['children'] as $childId => $child) {
00439 $this->remove($childId);
00440 $resourcesRemoved[] = $childId;
00441 }
00442
00443 foreach ($resourcesRemoved as $resourceIdRemoved) {
00444 foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $rules) {
00445 if ($resourceIdRemoved === $resourceIdCurrent) {
00446 unset($this->_rules['byResourceId'][$resourceIdCurrent]);
00447 }
00448 }
00449 }
00450
00451 unset($this->_resources[$resourceId]);
00452
00453 return $this;
00454 }
00455
00461 public function removeAll()
00462 {
00463 foreach ($this->_resources as $resourceId => $resource) {
00464 foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $rules) {
00465 if ($resourceId === $resourceIdCurrent) {
00466 unset($this->_rules['byResourceId'][$resourceIdCurrent]);
00467 }
00468 }
00469 }
00470
00471 $this->_resources = array();
00472
00473 return $this;
00474 }
00475
00486 public function allow($roles = null, $resources = null, $privileges = null, Zend_Acl_Assert_Interface $assert = null)
00487 {
00488 return $this->setRule(self::OP_ADD, self::TYPE_ALLOW, $roles, $resources, $privileges, $assert);
00489 }
00490
00501 public function deny($roles = null, $resources = null, $privileges = null, Zend_Acl_Assert_Interface $assert = null)
00502 {
00503 return $this->setRule(self::OP_ADD, self::TYPE_DENY, $roles, $resources, $privileges, $assert);
00504 }
00505
00515 public function removeAllow($roles = null, $resources = null, $privileges = null)
00516 {
00517 return $this->setRule(self::OP_REMOVE, self::TYPE_ALLOW, $roles, $resources, $privileges);
00518 }
00519
00529 public function removeDeny($roles = null, $resources = null, $privileges = null)
00530 {
00531 return $this->setRule(self::OP_REMOVE, self::TYPE_DENY, $roles, $resources, $privileges);
00532 }
00533
00586 public function setRule($operation, $type, $roles = null, $resources = null, $privileges = null,
00587 Zend_Acl_Assert_Interface $assert = null)
00588 {
00589
00590 $type = strtoupper($type);
00591 if (self::TYPE_ALLOW !== $type && self::TYPE_DENY !== $type) {
00592 require_once 'Zend/Acl/Exception.php';
00593 throw new Zend_Acl_Exception("Unsupported rule type; must be either '" . self::TYPE_ALLOW . "' or '"
00594 . self::TYPE_DENY . "'");
00595 }
00596
00597
00598 if (!is_array($roles)) {
00599 $roles = array($roles);
00600 } else if (0 === count($roles)) {
00601 $roles = array(null);
00602 }
00603 $rolesTemp = $roles;
00604 $roles = array();
00605 foreach ($rolesTemp as $role) {
00606 if (null !== $role) {
00607 $roles[] = $this->_getRoleRegistry()->get($role);
00608 } else {
00609 $roles[] = null;
00610 }
00611 }
00612 unset($rolesTemp);
00613
00614
00615 if (!is_array($resources)) {
00616 $resources = array($resources);
00617 } else if (0 === count($resources)) {
00618 $resources = array(null);
00619 }
00620 $resourcesTemp = $resources;
00621 $resources = array();
00622 foreach ($resourcesTemp as $resource) {
00623 if (null !== $resource) {
00624 $resources[] = $this->get($resource);
00625 } else {
00626 $resources[] = null;
00627 }
00628 }
00629 unset($resourcesTemp);
00630
00631
00632 if (null === $privileges) {
00633 $privileges = array();
00634 } else if (!is_array($privileges)) {
00635 $privileges = array($privileges);
00636 }
00637
00638 switch ($operation) {
00639
00640
00641 case self::OP_ADD:
00642 foreach ($resources as $resource) {
00643 foreach ($roles as $role) {
00644 $rules =& $this->_getRules($resource, $role, true);
00645 if (0 === count($privileges)) {
00646 $rules['allPrivileges']['type'] = $type;
00647 $rules['allPrivileges']['assert'] = $assert;
00648 if (!isset($rules['byPrivilegeId'])) {
00649 $rules['byPrivilegeId'] = array();
00650 }
00651 } else {
00652 foreach ($privileges as $privilege) {
00653 $rules['byPrivilegeId'][$privilege]['type'] = $type;
00654 $rules['byPrivilegeId'][$privilege]['assert'] = $assert;
00655 }
00656 }
00657 }
00658 }
00659 break;
00660
00661
00662 case self::OP_REMOVE:
00663 foreach ($resources as $resource) {
00664 foreach ($roles as $role) {
00665 $rules =& $this->_getRules($resource, $role);
00666 if (null === $rules) {
00667 continue;
00668 }
00669 if (0 === count($privileges)) {
00670 if (null === $resource && null === $role) {
00671 if ($type === $rules['allPrivileges']['type']) {
00672 $rules = array(
00673 'allPrivileges' => array(
00674 'type' => self::TYPE_DENY,
00675 'assert' => null
00676 ),
00677 'byPrivilegeId' => array()
00678 );
00679 }
00680 continue;
00681 }
00682 if ($type === $rules['allPrivileges']['type']) {
00683 unset($rules['allPrivileges']);
00684 }
00685 } else {
00686 foreach ($privileges as $privilege) {
00687 if (isset($rules['byPrivilegeId'][$privilege]) &&
00688 $type === $rules['byPrivilegeId'][$privilege]['type']) {
00689 unset($rules['byPrivilegeId'][$privilege]);
00690 }
00691 }
00692 }
00693 }
00694 }
00695 break;
00696
00697 default:
00698 require_once 'Zend/Acl/Exception.php';
00699 throw new Zend_Acl_Exception("Unsupported operation; must be either '" . self::OP_ADD . "' or '"
00700 . self::OP_REMOVE . "'");
00701 }
00702
00703 return $this;
00704 }
00705
00734 public function isAllowed($role = null, $resource = null, $privilege = null)
00735 {
00736
00737 $this->_isAllowedRole = $this->_isAllowedResource = null;
00738
00739 if (null !== $role) {
00740
00741 $this->_isAllowedRole = $role;
00742 $role = $this->_getRoleRegistry()->get($role);
00743 if (!$this->_isAllowedRole instanceof Zend_Acl_Role_Interface) {
00744 $this->_isAllowedRole = $role;
00745 }
00746 }
00747
00748 if (null !== $resource) {
00749
00750 $this->_isAllowedResource = $resource;
00751 $resource = $this->get($resource);
00752 if (!$this->_isAllowedResource instanceof Zend_Acl_Resource_Interface) {
00753 $this->_isAllowedResource = $resource;
00754 }
00755 }
00756
00757 if (null === $privilege) {
00758
00759 do {
00760
00761 if (null !== $role && null !== ($result = $this->_roleDFSAllPrivileges($role, $resource, $privilege))) {
00762 return $result;
00763 }
00764
00765
00766 if (null !== ($rules = $this->_getRules($resource, null))) {
00767 foreach ($rules['byPrivilegeId'] as $privilege => $rule) {
00768 if (self::TYPE_DENY === ($ruleTypeOnePrivilege = $this->_getRuleType($resource, null, $privilege))) {
00769 return false;
00770 }
00771 }
00772 if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, null, null))) {
00773 return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
00774 }
00775 }
00776
00777
00778 $resource = $this->_resources[$resource->getResourceId()]['parent'];
00779
00780 } while (true);
00781 } else {
00782
00783 do {
00784
00785 if (null !== $role && null !== ($result = $this->_roleDFSOnePrivilege($role, $resource, $privilege))) {
00786 return $result;
00787 }
00788
00789
00790 if (null !== ($ruleType = $this->_getRuleType($resource, null, $privilege))) {
00791 return self::TYPE_ALLOW === $ruleType;
00792 } else if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, null, null))) {
00793 return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
00794 }
00795
00796
00797 $resource = $this->_resources[$resource->getResourceId()]['parent'];
00798
00799 } while (true);
00800 }
00801 }
00802
00811 protected function _getRoleRegistry()
00812 {
00813 if (null === $this->_roleRegistry) {
00814 $this->_roleRegistry = new Zend_Acl_Role_Registry();
00815 }
00816 return $this->_roleRegistry;
00817 }
00818
00830 protected function _roleDFSAllPrivileges(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null)
00831 {
00832 $dfs = array(
00833 'visited' => array(),
00834 'stack' => array()
00835 );
00836
00837 if (null !== ($result = $this->_roleDFSVisitAllPrivileges($role, $resource, $dfs))) {
00838 return $result;
00839 }
00840
00841 while (null !== ($role = array_pop($dfs['stack']))) {
00842 if (!isset($dfs['visited'][$role->getRoleId()])) {
00843 if (null !== ($result = $this->_roleDFSVisitAllPrivileges($role, $resource, $dfs))) {
00844 return $result;
00845 }
00846 }
00847 }
00848
00849 return null;
00850 }
00851
00866 protected function _roleDFSVisitAllPrivileges(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
00867 &$dfs = null)
00868 {
00869 if (null === $dfs) {
00873 require_once 'Zend/Acl/Exception.php';
00874 throw new Zend_Acl_Exception('$dfs parameter may not be null');
00875 }
00876
00877 if (null !== ($rules = $this->_getRules($resource, $role))) {
00878 foreach ($rules['byPrivilegeId'] as $privilege => $rule) {
00879 if (self::TYPE_DENY === ($ruleTypeOnePrivilege = $this->_getRuleType($resource, $role, $privilege))) {
00880 return false;
00881 }
00882 }
00883 if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, $role, null))) {
00884 return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
00885 }
00886 }
00887
00888 $dfs['visited'][$role->getRoleId()] = true;
00889 foreach ($this->_getRoleRegistry()->getParents($role) as $roleParentId => $roleParent) {
00890 $dfs['stack'][] = $roleParent;
00891 }
00892
00893 return null;
00894 }
00895
00909 protected function _roleDFSOnePrivilege(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
00910 $privilege = null)
00911 {
00912 if (null === $privilege) {
00916 require_once 'Zend/Acl/Exception.php';
00917 throw new Zend_Acl_Exception('$privilege parameter may not be null');
00918 }
00919
00920 $dfs = array(
00921 'visited' => array(),
00922 'stack' => array()
00923 );
00924
00925 if (null !== ($result = $this->_roleDFSVisitOnePrivilege($role, $resource, $privilege, $dfs))) {
00926 return $result;
00927 }
00928
00929 while (null !== ($role = array_pop($dfs['stack']))) {
00930 if (!isset($dfs['visited'][$role->getRoleId()])) {
00931 if (null !== ($result = $this->_roleDFSVisitOnePrivilege($role, $resource, $privilege, $dfs))) {
00932 return $result;
00933 }
00934 }
00935 }
00936
00937 return null;
00938 }
00939
00955 protected function _roleDFSVisitOnePrivilege(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null,
00956 $privilege = null, &$dfs = null)
00957 {
00958 if (null === $privilege) {
00962 require_once 'Zend/Acl/Exception.php';
00963 throw new Zend_Acl_Exception('$privilege parameter may not be null');
00964 }
00965
00966 if (null === $dfs) {
00970 require_once 'Zend/Acl/Exception.php';
00971 throw new Zend_Acl_Exception('$dfs parameter may not be null');
00972 }
00973
00974 if (null !== ($ruleTypeOnePrivilege = $this->_getRuleType($resource, $role, $privilege))) {
00975 return self::TYPE_ALLOW === $ruleTypeOnePrivilege;
00976 } else if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, $role, null))) {
00977 return self::TYPE_ALLOW === $ruleTypeAllPrivileges;
00978 }
00979
00980 $dfs['visited'][$role->getRoleId()] = true;
00981 foreach ($this->_getRoleRegistry()->getParents($role) as $roleParentId => $roleParent) {
00982 $dfs['stack'][] = $roleParent;
00983 }
00984
00985 return null;
00986 }
00987
01009 protected function _getRuleType(Zend_Acl_Resource_Interface $resource = null, Zend_Acl_Role_Interface $role = null,
01010 $privilege = null)
01011 {
01012
01013 if (null === ($rules = $this->_getRules($resource, $role))) {
01014 return null;
01015 }
01016
01017
01018 if (null === $privilege) {
01019 if (isset($rules['allPrivileges'])) {
01020 $rule = $rules['allPrivileges'];
01021 } else {
01022 return null;
01023 }
01024 } else if (!isset($rules['byPrivilegeId'][$privilege])) {
01025 return null;
01026 } else {
01027 $rule = $rules['byPrivilegeId'][$privilege];
01028 }
01029
01030
01031 if ($rule['assert']) {
01032 $assertion = $rule['assert'];
01033 $assertionValue = $assertion->assert(
01034 $this,
01035 ($this->_isAllowedRole instanceof Zend_Acl_Role_Interface) ? $this->_isAllowedRole : $role,
01036 ($this->_isAllowedResource instanceof Zend_Acl_Resource_Interface) ? $this->_isAllowedResource : $resource,
01037 $privilege
01038 );
01039 }
01040
01041 if (null === $rule['assert'] || $assertionValue) {
01042 return $rule['type'];
01043 } else if (null !== $resource || null !== $role || null !== $privilege) {
01044 return null;
01045 } else if (self::TYPE_ALLOW === $rule['type']) {
01046 return self::TYPE_DENY;
01047 } else {
01048 return self::TYPE_ALLOW;
01049 }
01050 }
01051
01065 protected function &_getRules(Zend_Acl_Resource_Interface $resource = null, Zend_Acl_Role_Interface $role = null,
01066 $create = false)
01067 {
01068
01069 $null = null;
01070 $nullRef =& $null;
01071
01072
01073 do {
01074 if (null === $resource) {
01075 $visitor =& $this->_rules['allResources'];
01076 break;
01077 }
01078 $resourceId = $resource->getResourceId();
01079 if (!isset($this->_rules['byResourceId'][$resourceId])) {
01080 if (!$create) {
01081 return $nullRef;
01082 }
01083 $this->_rules['byResourceId'][$resourceId] = array();
01084 }
01085 $visitor =& $this->_rules['byResourceId'][$resourceId];
01086 } while (false);
01087
01088
01089
01090 if (null === $role) {
01091 if (!isset($visitor['allRoles'])) {
01092 if (!$create) {
01093 return $nullRef;
01094 }
01095 $visitor['allRoles']['byPrivilegeId'] = array();
01096 }
01097 return $visitor['allRoles'];
01098 }
01099 $roleId = $role->getRoleId();
01100 if (!isset($visitor['byRoleId'][$roleId])) {
01101 if (!$create) {
01102 return $nullRef;
01103 }
01104 $visitor['byRoleId'][$roleId]['byPrivilegeId'] = array();
01105 }
01106 return $visitor['byRoleId'][$roleId];
01107 }
01108
01109
01114 public function getRegisteredRoles()
01115 {
01116 return $this->_getRoleRegistry()->getRoles();
01117 }
01118
01119 }