PageRenderTime 79ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/joomla/access/access.php

https://github.com/rietn/minima
PHP | 383 lines | 190 code | 58 blank | 135 comment | 27 complexity | daeccc90298424a425309b52d16e4d11 MD5 | raw file
  1. <?php
  2. /**
  3. * @version $Id: access.php 21147 2011-04-14 16:49:40Z dextercowley $
  4. * @package Joomla.Framework
  5. * @subpackage Access
  6. * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE.txt
  8. */
  9. defined('JPATH_BASE') or die;
  10. jimport('joomla.access.rules');
  11. /**
  12. * Class that handles all access authorization routines.
  13. *
  14. * @package Joomla.Framework
  15. * @subpackage User
  16. * @since 1.6
  17. */
  18. class JAccess
  19. {
  20. /**
  21. * @since 1.6
  22. */
  23. protected static $viewLevels = array();
  24. /**
  25. * @since 1.6
  26. */
  27. protected static $assetRules = array();
  28. /**
  29. * Method to check if a user is authorised to perform an action, optionally on an asset.
  30. *
  31. * @param integer $userId Id of the user for which to check authorisation.
  32. * @param string $action The name of the action to authorise.
  33. * @param mixed $asset Integer asset id or the name of the asset as a string. Defaults to the global asset node.
  34. *
  35. * @return boolean True if authorised.
  36. * @since 1.6
  37. */
  38. public static function check($userId, $action, $asset = null)
  39. {
  40. // Sanitize inputs.
  41. $userId = (int) $userId;
  42. $action = strtolower(preg_replace('#[\s\-]+#', '.', trim($action)));
  43. $asset = strtolower(preg_replace('#[\s\-]+#', '.', trim($asset)));
  44. // Default to the root asset node.
  45. if (empty($asset)) {
  46. $asset = 1;
  47. }
  48. // Get the rules for the asset recursively to root if not already retrieved.
  49. if (empty(self::$assetRules[$asset])) {
  50. self::$assetRules[$asset] = self::getAssetRules($asset, true);
  51. }
  52. // Get all groups against which the user is mapped.
  53. $identities = self::getGroupsByUser($userId);
  54. array_unshift($identities, $userId * -1);
  55. return self::$assetRules[$asset]->allow($action, $identities);
  56. }
  57. /**
  58. * Method to check if a group is authorised to perform an action, optionally on an asset.
  59. *
  60. * @param integer $groupId The path to the group for which to check authorisation.
  61. * @param string $action The name of the action to authorise.
  62. * @param mixed $asset Integer asset id or the name of the asset as a string. Defaults to the global asset node.
  63. *
  64. * @return boolean True if authorised.
  65. * @since 1.6
  66. */
  67. public static function checkGroup($groupId, $action, $asset = null)
  68. {
  69. // Sanitize inputs.
  70. $groupId = (int) $groupId;
  71. $action = strtolower(preg_replace('#[\s\-]+#', '.', trim($action)));
  72. $asset = strtolower(preg_replace('#[\s\-]+#', '.', trim($asset)));
  73. // Get group path for group
  74. $groupPath = self::getGroupPath($groupId);
  75. // Default to the root asset node.
  76. if (empty($asset)) {
  77. $asset = 1;
  78. }
  79. // Get the rules for the asset recursively to root if not already retrieved.
  80. if (empty(self::$assetRules[$asset])) {
  81. self::$assetRules[$asset] = self::getAssetRules($asset, true);
  82. }
  83. return self::$assetRules[$asset]->allow($action, $groupPath);
  84. }
  85. /**
  86. * Gets the parent groups that a leaf group belongs to in it's branch back to the root of the tree
  87. * (including the leaf group id).
  88. *
  89. * @param mixed $groupId An integer or array of integers representing the identities to check.
  90. *
  91. * @return mixed True if allowed, false for an explicit deny, null for an implicit deny.
  92. * @since 1.6
  93. */
  94. protected static function getGroupPath($groupId)
  95. {
  96. static $groups, $paths;
  97. // Preload all groups
  98. if (empty($groups)) {
  99. $db = JFactory::getDbo();
  100. $query = $db->getQuery(true)
  101. ->select('parent.id, parent.lft, parent.rgt')
  102. ->from('#__usergroups AS parent')
  103. ->order('parent.lft');
  104. $db->setQuery($query);
  105. $groups = $db->loadObjectList('id');
  106. }
  107. // Make sure groupId is valid
  108. if (!array_key_exists($groupId, $groups))
  109. {
  110. return array();
  111. }
  112. // Get parent groups and leaf group
  113. if (!isset($paths[$groupId])) {
  114. $paths[$groupId] = array();
  115. foreach($groups as $group) {
  116. if ($group->lft <= $groups[$groupId]->lft && $group->rgt >= $groups[$groupId]->rgt) {
  117. $paths[$groupId][] = $group->id;
  118. }
  119. }
  120. }
  121. return $paths[$groupId];
  122. }
  123. /**
  124. * Method to return the JRules object for an asset. The returned object can optionally hold
  125. * only the rules explicitly set for the asset or the summation of all inherited rules from
  126. * parent assets and explicit rules.
  127. *
  128. * @param mixed $asset Integer asset id or the name of the asset as a string.
  129. * @param boolean $recursive True to return the rules object with inherited rules.
  130. *
  131. * @return object JRules object for the asset.
  132. * @since 1.6
  133. */
  134. public static function getAssetRules($asset, $recursive = false)
  135. {
  136. // Get the database connection object.
  137. $db = JFactory::getDbo();
  138. // Build the database query to get the rules for the asset.
  139. $query = $db->getQuery(true);
  140. $query->select($recursive ? 'b.rules' : 'a.rules');
  141. $query->from('#__assets AS a');
  142. // If the asset identifier is numeric assume it is a primary key, else lookup by name.
  143. if (is_numeric($asset)) {
  144. $query->where('a.id = '.(int) $asset);
  145. }
  146. else {
  147. $query->where('a.name = '.$db->quote($asset));
  148. }
  149. // If we want the rules cascading up to the global asset node we need a self-join.
  150. if ($recursive) {
  151. $query->leftJoin('#__assets AS b ON b.lft <= a.lft AND b.rgt >= a.rgt');
  152. $query->order('b.lft');
  153. }
  154. // Execute the query and load the rules from the result.
  155. $db->setQuery($query);
  156. $result = $db->loadResultArray();
  157. // Get the root even if the asset is not found and in recursive mode
  158. if ($recursive && empty($result)) {
  159. $query = $db->getQuery(true);
  160. $query->select('rules');
  161. $query->from('#__assets');
  162. $query->where('parent_id=0');
  163. $db->setQuery($query);
  164. $result = $db->loadResultArray();
  165. }
  166. // Instantiate and return the JRules object for the asset rules.
  167. $rules = new JRules;
  168. $rules->mergeCollection($result);
  169. return $rules;
  170. }
  171. /**
  172. * Method to return a list of user groups mapped to a user. The returned list can optionally hold
  173. * only the groups explicitly mapped to the user or all groups both explicitly mapped and inherited
  174. * by the user.
  175. *
  176. * @param integer $userId Id of the user for which to get the list of groups.
  177. * @param boolean $recursive True to include inherited user groups.
  178. *
  179. * @return array List of user group ids to which the user is mapped.
  180. * @since 1.6
  181. */
  182. public static function getGroupsByUser($userId, $recursive = true)
  183. {
  184. static $results = array();
  185. // Creates a simple unique string for each parameter combination:
  186. $storeId = $userId.':'.(int) $recursive;
  187. if (!isset($results[$storeId]))
  188. {
  189. // Guest user
  190. if (empty($userId))
  191. {
  192. $result = array(JComponentHelper::getParams('com_users')->get('guest_usergroup', 1));
  193. }
  194. // Registered user
  195. else
  196. {
  197. $db = JFactory::getDbo();
  198. // Build the database query to get the rules for the asset.
  199. $query = $db->getQuery(true);
  200. $query->select($recursive ? 'b.id' : 'a.id');
  201. $query->from('#__user_usergroup_map AS map');
  202. $query->where('map.user_id = '.(int) $userId);
  203. $query->leftJoin('#__usergroups AS a ON a.id = map.group_id');
  204. // If we want the rules cascading up to the global asset node we need a self-join.
  205. if ($recursive) {
  206. $query->leftJoin('#__usergroups AS b ON b.lft <= a.lft AND b.rgt >= a.rgt');
  207. }
  208. // Execute the query and load the rules from the result.
  209. $db->setQuery($query);
  210. $result = $db->loadResultArray();
  211. // Clean up any NULL or duplicate values, just in case
  212. JArrayHelper::toInteger($result);
  213. if (empty($result)) {
  214. $result = array('1');
  215. }
  216. else {
  217. $result = array_unique($result);
  218. }
  219. }
  220. $results[$storeId] = $result;
  221. }
  222. return $results[$storeId];
  223. }
  224. /**
  225. * Method to return a list of user Ids contained in a Group
  226. *
  227. * @param int $groupId The group Id
  228. * @param boolean $recursive Recursively include all child groups (optional)
  229. *
  230. * @return array
  231. * @since 1.6
  232. * @todo This method should move somewhere else?
  233. */
  234. public static function getUsersByGroup($groupId, $recursive = false)
  235. {
  236. // Get a database object.
  237. $db = JFactory::getDbo();
  238. $test = $recursive ? '>=' : '=';
  239. // First find the users contained in the group
  240. $query = $db->getQuery(true);
  241. $query->select('DISTINCT(user_id)');
  242. $query->from('#__usergroups as ug1');
  243. $query->join('INNER','#__usergroups AS ug2 ON ug2.lft'.$test.'ug1.lft AND ug1.rgt'.$test.'ug2.rgt');
  244. $query->join('INNER','#__user_usergroup_map AS m ON ug2.id=m.group_id');
  245. $query->where('ug1.id='.$db->Quote($groupId));
  246. $db->setQuery($query);
  247. $result = $db->loadResultArray();
  248. // Clean up any NULL values, just in case
  249. JArrayHelper::toInteger($result);
  250. return $result;
  251. }
  252. /**
  253. * Method to return a list of view levels for which the user is authorised.
  254. *
  255. * @param integer $userId Id of the user for which to get the list of authorised view levels.
  256. *
  257. * @return array List of view levels for which the user is authorised.
  258. * @since 1.6
  259. */
  260. public static function getAuthorisedViewLevels($userId)
  261. {
  262. // Get all groups that the user is mapped to recursively.
  263. $groups = self::getGroupsByUser($userId);
  264. // Only load the view levels once.
  265. if (empty(self::$viewLevels)) {
  266. // Get a database object.
  267. $db = JFactory::getDBO();
  268. // Build the base query.
  269. $query = $db->getQuery(true);
  270. $query->select('id, rules');
  271. $query->from('`#__viewlevels`');
  272. // Set the query for execution.
  273. $db->setQuery((string) $query);
  274. // Build the view levels array.
  275. foreach ($db->loadAssocList() as $level) {
  276. self::$viewLevels[$level['id']] = (array) json_decode($level['rules']);
  277. }
  278. }
  279. // Initialise the authorised array.
  280. $authorised = array(1);
  281. // Find the authorized levels.
  282. foreach (self::$viewLevels as $level => $rule)
  283. {
  284. foreach ($rule as $id)
  285. {
  286. if (($id < 0) && (($id * -1) == $userId)) {
  287. $authorised[] = $level;
  288. break;
  289. }
  290. // Check to see if the group is mapped to the level.
  291. elseif (($id >= 0) && in_array($id, $groups)) {
  292. $authorised[] = $level;
  293. break;
  294. }
  295. }
  296. }
  297. return $authorised;
  298. }
  299. /**
  300. * Method to return a list of actions for which permissions can be set given a component and section.
  301. *
  302. * @param string $component The component from which to retrieve the actions.
  303. * @param string $section The name of the section within the component from which to retrieve the actions.
  304. *
  305. * @return array List of actions available for the given component and section.
  306. * @since 1.6
  307. */
  308. public static function getActions($component, $section = 'component')
  309. {
  310. $actions = array();
  311. if (is_file(JPATH_ADMINISTRATOR.'/components/'.$component.'/access.xml')) {
  312. $xml = simplexml_load_file(JPATH_ADMINISTRATOR.'/components/'.$component.'/access.xml');
  313. foreach ($xml->children() as $child)
  314. {
  315. if ($section == (string) $child['name']) {
  316. foreach ($child->children() as $action) {
  317. $actions[] = (object) array('name' => (string) $action['name'], 'title' => (string) $action['title'], 'description' => (string) $action['description']);
  318. }
  319. break;
  320. }
  321. }
  322. }
  323. return $actions;
  324. }
  325. }