* @copyright 2008-2010 Alexander Schneider * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 * @version SVN: $Id$ * @link http://wordpress.org/extend/plugins/user-access-manager/ */ /** * The access handler class. * * @category UserAccessManager * @package UserAccessManager * @author Alexander Schneider * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 * @link http://wordpress.org/extend/plugins/user-access-manager/ */ class UamAccessHandler { protected $userAccessManager = null; protected $objectUserGroups = array(); protected $objectAccess = array(); protected $userGroups = array( 'filtered' => array(), 'noneFiltered' => array(), ); protected $plObjects = array(); protected $objectTypes = array( 'post', 'page', 'attachment', 'category', 'user', 'role' ); protected $allObjectTypes = null; protected $sqlResults = array(); /** * The consturctor * * @param object &$userAccessManager The user access manager object. * * @return null */ public function __construct(&$userAccessManager) { $this->userAccessManager = $userAccessManager; } /** * Returns the user access manager object. * * @return object */ public function &getUserAccessManager() { return $this->userAccessManager; } /** * Returns the predfined object types. * * @return array(); */ public function getObjectTypes() { return $this->objectTypes; } /** * Returns all objects types. * * @return array */ public function getAllObjectTypes() { if (isset($this->allObjectTypes)) { return $this->allObjectTypes; } $plObjects = $this->getPlObjects(); $this->allObjectTypes = array_merge( $this->objectTypes, array_keys($plObjects) ); return $this->allObjectTypes; } /** * Magic method getter. * * @param string $name The name of the function * @param array $arguments The arguments for the function * * @return mixed */ public function __call($name, $arguments) { echo $name; exit; $uam = $this->getUserAccessManager(); $action = ''; if ($uam->startsWith($name, 'getUserGroupsFor')) { $prefix = 'getUserGroupsFor'; } elseif ($uam->startsWith($name, 'checkAccessFor')) { $prefix = 'checkAccessFor'; } $objectType = str_replace($prefix, '', $name); $objectType = strtolower($objectType); $objectId = $arguments[0]; if ($prefix == 'getUserGroupsFor') { return $this->getUserGroupsForObject( $objectType, $objectId ); } elseif ($prefix == 'checkAccessFor') { return $this->checkObjectAccess( $objectType, $objectId ); } } /** * Filter the user groups of an object if authors_can_add_posts_to_groups * option is enabled * * @param array $userGroups The user groups. * * @return array */ private function _filterUserGroups($userGroups) { $uamOptions = $this->getUserAccessManager()->getAdminOptions(); if ($uamOptions['authors_can_add_posts_to_groups'] == 'true' && !$this->checkUserAccess() && $this->getUserAccessManager()->atAdminPanel() ) { global $current_user; //Force user infos wp_get_current_user(); $userGroupsForUser = $this->getUserGroupsForObject('user', $current_user->ID); foreach ($userGroups as $key => $uamUserGroup) { if (!array_key_exists($uamUserGroup->getId(), $userGroupsForUser)) { unset($userGroups[$key]); } } } return $userGroups; } /** * Returns all user groups or one requested by the user group id. * * @param integer $userGroupId The id of the single user group * which should be returned. * @param boolean $filter Filter the groups. * * @return array|object */ public function getUserGroups($userGroupId = null, $filter = true) { if ($filter) { $filterAttr = 'filtered'; } else { $filterAttr = 'noneFiltered'; } if ($userGroupId === null && $this->userGroups[$filterAttr] != array() ) { return $this->userGroups[$filterAttr]; } elseif ($userGroupId !== null && $this->userGroups[$filterAttr] != array() ) { if (isset($this->userGroups[$filterAttr][$userGroupId])) { return $this->userGroups[$filterAttr][$userGroupId]; } else { return null; } } $this->userGroups[$filterAttr] = array(); global $wpdb; $userGroupsDb = $wpdb->get_results( "SELECT ID FROM " . DB_ACCESSGROUP . " ORDER BY ID", ARRAY_A ); if (isset($userGroupsDb)) { foreach ($userGroupsDb as $userGroupDb) { $this->userGroups[$filterAttr][$userGroupDb['ID']] = new UamUserGroup(&$this, $userGroupDb['ID']); } } //Filter the user groups if ($filter) { $this->userGroups[$filterAttr] = $this->_filterUserGroups($this->userGroups[$filterAttr]); } if ($userGroupId == null) { return $this->userGroups[$filterAttr]; } elseif ($userGroupId != null) { if (isset($this->userGroups[$filterAttr][$userGroupId])) { return $this->userGroups[$filterAttr][$userGroupId]; } else { return null; } } } /** * Adds a user group. * * @param object $userGroup The user group which we want to add. * * @return null */ public function addUserGroup($userGroup) { $this->getUserGroups(); $this->userGroups['noneFiltered'][$userGroup->getId()] = $userGroup; $this->userGroups['filtered'] = array(); } /** * Deletes a user group. * * @param integer $userGroupId The user group id which we want to delete. * * @return null */ public function deleteUserGroup($userGroupId) { if ($this->getUserGroups($userGroupId) != null) { $this->getUserGroups($userGroupId)->delete(); unset($this->userGroups['noneFiltered'][$userGroupId]); $this->userGroups['filtered'] = array(); } } /** * Returns the user groups for the given object. * * @param string $objectType The object type. * @param integer $objectId The id of the object. * @param boolean $filter Filter the groups. * * @return array */ public function getUserGroupsForObject($objectType, $objectId, $filter = true) { if (!in_array($objectType, $this->getAllObjectTypes())) { return; } if ($objectType == 'user') { $filter = false; } if ($filter) { $filterAttr = 'filtered'; } else { $filterAttr = 'noneFiltered'; } if (isset($this->objectUserGroups[$objectType][$filterAttr][$objectId])) { return $this->objectUserGroups[$objectType][$filterAttr][$objectId]; } $objectUserGroups = array(); $userGroups = $this->getUserGroups(null, $filter); $plObject = false; if ($objectType != 'user' && $objectType != 'post' && $objectType != 'category' ) { $plObject = true; } $curIp = explode(".", $_SERVER['REMOTE_ADDR']); if (isset($userGroups)) { foreach ($userGroups as $userGroup) { $objectMembership = $userGroup->objectIsMember( $objectType, $objectId, true ); if ($objectMembership !== false || $objectType == 'user' && $this->checkUserIp($curIp, $userGroup->getIpRange()) ) { if (is_array($objectMembership)) { $userGroup->setRecursive[$objectType][$objectId] = $objectMembership; } $objectUserGroups[$userGroup->getId()] = $userGroup; } } } //Filter the user groups if ($filter) { $objectUserGroups = $this->_filterUserGroups($objectUserGroups); } $this->objectUserGroups[$objectType][$filterAttr][$objectId] = $objectUserGroups; return $this->objectUserGroups[$objectType][$filterAttr][$objectId]; } /** * Unsets the usergroups for objects. * * @return null */ public function unsetUserGroupsForObject() { $this->objectUserGroups = array(); } /** * Checks if the current_user has access to the given post. * * @param string $objectType The object type which should be checked. * @param integer $objectId The id of the object. * * @return boolean */ public function checkObjectAccess($objectType, $objectId) { if (!in_array($objectType, $this->getAllObjectTypes())) { return; } if (isset($this->objectAccess[$objectType][$objectId])) { return $this->objectAccess[$objectType][$objectId]; } global $current_user; //Force user infos wp_get_current_user(); if ($objectType == 'post') { $post = get_post($objectId); $authorId = $post->post_author; } else { $authorId = -1; } $uamOptions = $this->getUserAccessManager()->getAdminOptions(); $membership = $this->getUserGroupsForObject($objectType, $objectId, false); if ($membership == array() || $this->checkUserAccess() || $current_user->ID == $authorId && $uamOptions['authors_has_access_to_own'] == 'true' ) { return $this->objectAccess[$objectType][$objectId] = true; } $curIp = explode(".", $_SERVER['REMOTE_ADDR']); foreach ($membership as $key => $userGroup) { if ($this->checkUserIp($curIp, $userGroup->getIpRange()) || $userGroup->objectIsMember('user', $current_user->ID) ) { return $this->objectAccess[$objectType][$objectId] = true; break; } if ($this->getUserAccessManager()->atAdminPanel() && $userGroup->getWriteAccess() == 'all' || !$this->getUserAccessManager()->atAdminPanel() && $userGroup->getReadAccess() == 'all' ) { unset($membership[$key]); } } if ($membership == array()) { return $this->objectAccess[$objectType][$objectId] = true; } return $this->objectAccess[$objectType][$objectId] = false; } /* * SQL functions. */ /** * Returns the usergroups for the current user as sql string. * * @return string */ private function _getUserGroupsForUserAsSqlString() { if (isset($this->sqlResults['groupsForUser'])) { return $this->sqlResults['groupsForUser']; } global $current_user; //Force user infos wp_get_current_user(); $userUserGroups = $this->getUserGroupsForObject( 'user', $current_user->ID, false ); $userUserGroupArray = array(); foreach ($userUserGroups as $userUserGroup) { $userUserGroupArray[] = $userUserGroup->getId(); } if ($userUserGroupArray !== array()) { $userUserGroupString = implode(', ', $userUserGroupArray); } else { $userUserGroupString = "''"; } $this->sqlResults['groupsForUser'] = $userUserGroupString; return $this->sqlResults['groupsForUser']; } /** * Returns the categories assigned to the user. * * @return array */ public function getCategoriesForUser() { global $wpdb; if (isset($this->sqlResults['categoriesAssignedToUser'])) { return $this->sqlResults['categoriesAssignedToUser']; } $userUserGroupString = $this->_getUserGroupsForUserAsSqlString(); $categoriesAssignedToUserSql = " SELECT igc.object_id FROM ".DB_ACCESSGROUP_TO_OBJECT." AS igc WHERE igc.object_type = 'category' AND igc.group_id IN (".$userUserGroupString.")"; $this->sqlResults['categoriesAssignedToUser'] = $wpdb->get_col($categoriesAssignedToUserSql); return $this->sqlResults['categoriesAssignedToUser']; } /** * Returns the posts assigned to the user. * * @return array */ public function getPostsForUser() { global $wpdb; if (isset($this->sqlResults['postsAssignedToUser'])) { return $this->sqlResults['postsAssignedToUser']; } $userUserGroupString = $this->_getUserGroupsForUserAsSqlString(); $postAssignedToUserSql = " SELECT igp.object_id FROM ".DB_ACCESSGROUP_TO_OBJECT." AS igp WHERE igp.object_type = 'post' AND igp.group_id IN (".$userUserGroupString.")"; $this->sqlResults['postsAssignedToUser'] = $wpdb->get_col($postAssignedToUserSql); return $this->sqlResults['postsAssignedToUser']; } /** * Returns the excluded posts. * * @return array */ public function getExcludedPosts() { global $wpdb; if ($this->checkUserAccess()) { $this->sqlResults['excludedPosts'] = array(); } if (isset($this->sqlResults['excludedPosts'])) { return $this->sqlResults['excludedPosts']; } if ($this->getUserAccessManager()->atAdminPanel()) { $accessType = "write"; } else { $accessType = "read"; } $categoriesAssignedToUser = $this->getCategoriesForUser(); if ($categoriesAssignedToUser !== array()) { $categoriesAssignedToUserString = implode(', ', $categoriesAssignedToUser); } else { $categoriesAssignedToUserString = "''"; } $postAssignedToUser = $this->getPostsForUser(); if ($postAssignedToUser !== array()) { $postAssignedToUserString = implode(', ', $postAssignedToUser); } else { $postAssignedToUserString = "''"; } $postSql = "SELECT DISTINCT p.ID FROM $wpdb->posts AS p INNER JOIN $wpdb->term_relationships AS tr ON p.ID = tr.object_id INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy = 'category' AND tt.term_id IN ( SELECT gc.object_id FROM ".DB_ACCESSGROUP." iag INNER JOIN ".DB_ACCESSGROUP_TO_OBJECT." AS gc ON iag.id = gc.group_id WHERE gc.object_type = 'category' AND iag.".$accessType."_access != 'all' AND gc.object_id NOT IN (".$categoriesAssignedToUserString.") ) AND p.ID NOT IN (".$postAssignedToUserString.") UNION SELECT DISTINCT gp.object_id FROM ".DB_ACCESSGROUP." AS ag INNER JOIN ".DB_ACCESSGROUP_TO_OBJECT." AS gp ON ag.id = gp.group_id INNER JOIN $wpdb->term_relationships AS tr ON gp.object_id = tr.object_id INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE gp.object_type = 'post' AND ag.".$accessType."_access != 'all' AND gp.object_id NOT IN (".$postAssignedToUserString.") AND tt.term_id NOT IN (".$categoriesAssignedToUserString.")"; $this->sqlResults['excludedPosts'] = $wpdb->get_col($postSql); return $this->sqlResults['excludedPosts']; } /* * Other functions */ /** * Checks if the given ip matches with the range. * * @param string $curIp The ip of the current user. * @param array $ipRanges The ip ranges. * * @return boolean */ public function checkUserIp($curIp, $ipRanges) { if (isset($ipRanges)) { foreach ($ipRanges as $ipRange) { $ipRange = explode("-", $ipRange); $rangeBegin = explode(".", $ipRange[0]); if (isset($ipRange[1])) { $rangeEnd = explode(".", $ipRange[1]); } else { $rangeEnd = explode(".", $ipRange[0]); } if ($rangeBegin[0] <= $curIp[0] && $curIp[0] <= $rangeEnd[0] && $rangeBegin[1] <= $curIp[1] && $curIp[1] <= $rangeEnd[1] && $rangeBegin[2] <= $curIp[2] && $curIp[2] <= $rangeEnd[2] && $rangeBegin[3] <= $curIp[3] && $curIp[3] <= $rangeEnd[3] ) { return true; } } } return false; } /** * Return the role of the user. * * @param integer $userId The user id. * * @return string|null */ private function _getUserRole($userId) { global $wpdb; $curUserdata = get_userdata($userId); if (!isset($curUserdata->user_level)) { $curUserdata->user_level = null; } if (isset($curUserdata->{$wpdb->prefix . "capabilities"})) { $capabilities = $curUserdata->{$wpdb->prefix . "capabilities"}; } else { $capabilities = null; } $role = is_array($capabilities) ? array_keys($capabilities) : array('norole'); return trim($role[0]); } /** * Checks if the user is an admin user * * @param integer $userId The user id. * * @return boolean */ public function userIsAdmin($userId) { $role = $this->_getUserRole($userId); if ($role == 'administrator' || is_super_admin($userId) ) { return true; } return false; } /** * Checks the user access by user level. * * @return boolean */ public function checkUserAccess() { global $current_user; //Force user infos wp_get_current_user(); $uamOptions = $this->getUserAccessManager()->getAdminOptions(); $role = $this->_getUserRole($current_user->ID); $orderedRoles = $this->getRolesOrdered(); if ($orderedRoles[$role] >= $orderedRoles[$uamOptions['full_access_role']] || $role == 'administrator' || is_super_admin($current_user->ID) ) { return true; } return false; } /** * Returns the roles as assoziative array. * * @return array */ public function getRolesOrdered() { $orderedRoles = array( 'norole' => 0, 'subscriber' => 1, 'contributor' => 2, 'author' => 3, 'editor' => 4, 'administrator' => 5 ); return $orderedRoles; } /** * Registers object that should be handelt by the user access manager. * * @param array $object The object which you want to register. * * @return boolean */ public function registerPlObject($object) { if (!isset($object['name']) || !isset($object['reference']) || !isset($object['getFull']) || !isset($object['getFullObjects']) ) { return false; } $this->plObjects[$object['name']] = $object; return true; } /** * Returns a registerd pluggable object. * * @param string $objectName The name of the object which should be returned. * * @return array */ public function getPlObject($objectName) { if (isset($this->plObjects[$objectName])) { return $this->plObjects[$objectName]; } return array(); } /** * Returns all registerd pluggable objects. * * @return array */ public function getPlObjects() { return $this->plObjects; } }