| [ Index ] |
PHP Cross Reference of Joomla 2.5.4 DE |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * @package Joomla.Platform 4 * @subpackage Access 5 * 6 * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved. 7 * @license GNU General Public License version 2 or later; see LICENSE 8 */ 9 10 defined('JPATH_PLATFORM') or die; 11 12 jimport('joomla.utilities.arrayhelper'); 13 14 /** 15 * Class that handles all access authorisation routines. 16 * 17 * @package Joomla.Platform 18 * @subpackage Access 19 * @since 11.1 20 */ 21 class JAccess 22 { 23 /** 24 * Array of view levels 25 * 26 * @var array 27 * @since 11.1 28 */ 29 protected static $viewLevels = array(); 30 31 /** 32 * Array of rules for the asset 33 * 34 * @var array 35 * @since 11.1 36 */ 37 protected static $assetRules = array(); 38 39 /** 40 * Array of user groups. 41 * 42 * @var array 43 * @since 11.1 44 */ 45 protected static $userGroups = array(); 46 47 /** 48 * Array of user group paths. 49 * 50 * @var array 51 * @since 11.1 52 */ 53 protected static $userGroupPaths = array(); 54 55 /** 56 * Array of cached groups by user. 57 * 58 * @var array 59 * @since 11.1 60 */ 61 protected static $groupsByUser = array(); 62 63 /** 64 * Method for clearing static caches. 65 * 66 * @return void 67 * 68 * @since 11.3 69 */ 70 public static function clearStatics() 71 { 72 self::$viewLevels = array(); 73 self::$assetRules = array(); 74 self::$userGroups = array(); 75 self::$userGroupPaths = array(); 76 self::$groupsByUser = array(); 77 } 78 79 /** 80 * Method to check if a user is authorised to perform an action, optionally on an asset. 81 * 82 * @param integer $userId Id of the user for which to check authorisation. 83 * @param string $action The name of the action to authorise. 84 * @param mixed $asset Integer asset id or the name of the asset as a string. Defaults to the global asset node. 85 * 86 * @return boolean True if authorised. 87 * 88 * @since 11.1 89 */ 90 public static function check($userId, $action, $asset = null) 91 { 92 // Sanitise inputs. 93 $userId = (int) $userId; 94 95 $action = strtolower(preg_replace('#[\s\-]+#', '.', trim($action))); 96 $asset = strtolower(preg_replace('#[\s\-]+#', '.', trim($asset))); 97 98 // Default to the root asset node. 99 if (empty($asset)) 100 { 101 $asset = 1; 102 } 103 104 // Get the rules for the asset recursively to root if not already retrieved. 105 if (empty(self::$assetRules[$asset])) 106 { 107 self::$assetRules[$asset] = self::getAssetRules($asset, true); 108 } 109 110 // Get all groups against which the user is mapped. 111 $identities = self::getGroupsByUser($userId); 112 array_unshift($identities, $userId * -1); 113 114 return self::$assetRules[$asset]->allow($action, $identities); 115 } 116 117 /** 118 * Method to check if a group is authorised to perform an action, optionally on an asset. 119 * 120 * @param integer $groupId The path to the group for which to check authorisation. 121 * @param string $action The name of the action to authorise. 122 * @param mixed $asset Integer asset id or the name of the asset as a string. Defaults to the global asset node. 123 * 124 * @return boolean True if authorised. 125 * 126 * @since 11.1 127 */ 128 public static function checkGroup($groupId, $action, $asset = null) 129 { 130 // Sanitize inputs. 131 $groupId = (int) $groupId; 132 $action = strtolower(preg_replace('#[\s\-]+#', '.', trim($action))); 133 $asset = strtolower(preg_replace('#[\s\-]+#', '.', trim($asset))); 134 135 // Get group path for group 136 $groupPath = self::getGroupPath($groupId); 137 138 // Default to the root asset node. 139 if (empty($asset)) 140 { 141 $asset = 1; 142 } 143 144 // Get the rules for the asset recursively to root if not already retrieved. 145 if (empty(self::$assetRules[$asset])) 146 { 147 self::$assetRules[$asset] = self::getAssetRules($asset, true); 148 } 149 150 return self::$assetRules[$asset]->allow($action, $groupPath); 151 } 152 153 /** 154 * Gets the parent groups that a leaf group belongs to in its branch back to the root of the tree 155 * (including the leaf group id). 156 * 157 * @param mixed $groupId An integer or array of integers representing the identities to check. 158 * 159 * @return mixed True if allowed, false for an explicit deny, null for an implicit deny. 160 * 161 * @since 11.1 162 */ 163 protected static function getGroupPath($groupId) 164 { 165 // Preload all groups 166 if (empty(self::$userGroups)) 167 { 168 $db = JFactory::getDbo(); 169 $query = $db->getQuery(true) 170 ->select('parent.id, parent.lft, parent.rgt') 171 ->from('#__usergroups AS parent') 172 ->order('parent.lft'); 173 $db->setQuery($query); 174 self::$userGroups = $db->loadObjectList('id'); 175 } 176 177 // Make sure groupId is valid 178 if (!array_key_exists($groupId, self::$userGroups)) 179 { 180 return array(); 181 } 182 183 // Get parent groups and leaf group 184 if (!isset(self::$userGroupPaths[$groupId])) 185 { 186 self::$userGroupPaths[$groupId] = array(); 187 188 foreach (self::$userGroups as $group) 189 { 190 if ($group->lft <= self::$userGroups[$groupId]->lft && $group->rgt >= self::$userGroups[$groupId]->rgt) 191 { 192 self::$userGroupPaths[$groupId][] = $group->id; 193 } 194 } 195 } 196 197 return self::$userGroupPaths[$groupId]; 198 } 199 200 /** 201 * Method to return the JAccessRules object for an asset. The returned object can optionally hold 202 * only the rules explicitly set for the asset or the summation of all inherited rules from 203 * parent assets and explicit rules. 204 * 205 * @param mixed $asset Integer asset id or the name of the asset as a string. 206 * @param boolean $recursive True to return the rules object with inherited rules. 207 * 208 * @return JAccessRules JAccessRules object for the asset. 209 * 210 * @since 11.1 211 */ 212 public static function getAssetRules($asset, $recursive = false) 213 { 214 // Get the database connection object. 215 $db = JFactory::getDbo(); 216 217 // Build the database query to get the rules for the asset. 218 $query = $db->getQuery(true); 219 $query->select($recursive ? 'b.rules' : 'a.rules'); 220 $query->from('#__assets AS a'); 221 //sqlsrv change 222 $query->group($recursive ? 'b.id, b.rules, b.lft' : 'a.id, a.rules, a.lft'); 223 224 // If the asset identifier is numeric assume it is a primary key, else lookup by name. 225 if (is_numeric($asset)) 226 { 227 // Get the root even if the asset is not found 228 $query->where('(a.id = ' . (int) $asset . ($recursive ? ' OR a.parent_id=0' : '') . ')'); 229 } 230 else 231 { 232 // Get the root even if the asset is not found 233 $query->where('(a.name = ' . $db->quote($asset) . ($recursive ? ' OR a.parent_id=0' : '') . ')'); 234 } 235 236 // If we want the rules cascading up to the global asset node we need a self-join. 237 if ($recursive) 238 { 239 $query->leftJoin('#__assets AS b ON b.lft <= a.lft AND b.rgt >= a.rgt'); 240 $query->order('b.lft'); 241 } 242 243 // Execute the query and load the rules from the result. 244 $db->setQuery($query); 245 $result = $db->loadColumn(); 246 247 // Get the root even if the asset is not found and in recursive mode 248 if ($recursive && empty($result)) 249 { 250 $query = $db->getQuery(true); 251 $query->select('rules'); 252 $query->from('#__assets'); 253 $query->where('parent_id = 0'); 254 $db->setQuery($query); 255 $result = $db->loadColumn(); 256 } 257 258 // Instantiate and return the JAccessRules object for the asset rules. 259 $rules = new JAccessRules; 260 $rules->mergeCollection($result); 261 262 return $rules; 263 } 264 265 /** 266 * Method to return a list of user groups mapped to a user. The returned list can optionally hold 267 * only the groups explicitly mapped to the user or all groups both explicitly mapped and inherited 268 * by the user. 269 * 270 * @param integer $userId Id of the user for which to get the list of groups. 271 * @param boolean $recursive True to include inherited user groups. 272 * 273 * @return array List of user group ids to which the user is mapped. 274 * 275 * @since 11.1 276 */ 277 public static function getGroupsByUser($userId, $recursive = true) 278 { 279 // Creates a simple unique string for each parameter combination: 280 $storeId = $userId . ':' . (int) $recursive; 281 282 if (!isset(self::$groupsByUser[$storeId])) 283 { 284 // Guest user (if only the actually assigned group is requested) 285 if (empty($userId) && !$recursive) 286 { 287 $result = array(JComponentHelper::getParams('com_users')->get('guest_usergroup', 1)); 288 } 289 // Registered user and guest if all groups are requested 290 else 291 { 292 $db = JFactory::getDbo(); 293 294 // Build the database query to get the rules for the asset. 295 $query = $db->getQuery(true); 296 $query->select($recursive ? 'b.id' : 'a.id'); 297 if (empty($userId)) 298 { 299 $query->from('#__usergroups AS a'); 300 $query->where('a.id = ' . (int) JComponentHelper::getParams('com_users')->get('guest_usergroup', 1)); 301 } 302 else 303 { 304 $query->from('#__user_usergroup_map AS map'); 305 $query->where('map.user_id = ' . (int) $userId); 306 $query->leftJoin('#__usergroups AS a ON a.id = map.group_id'); 307 } 308 309 // If we want the rules cascading up to the global asset node we need a self-join. 310 if ($recursive) 311 { 312 $query->leftJoin('#__usergroups AS b ON b.lft <= a.lft AND b.rgt >= a.rgt'); 313 } 314 315 // Execute the query and load the rules from the result. 316 $db->setQuery($query); 317 $result = $db->loadColumn(); 318 319 // Clean up any NULL or duplicate values, just in case 320 JArrayHelper::toInteger($result); 321 322 if (empty($result)) 323 { 324 $result = array('1'); 325 } 326 else 327 { 328 $result = array_unique($result); 329 } 330 } 331 332 self::$groupsByUser[$storeId] = $result; 333 } 334 335 return self::$groupsByUser[$storeId]; 336 } 337 338 /** 339 * Method to return a list of user Ids contained in a Group 340 * 341 * @param integer $groupId The group Id 342 * @param boolean $recursive Recursively include all child groups (optional) 343 * 344 * @return array 345 * 346 * @since 11.1 347 * @todo This method should move somewhere else 348 */ 349 public static function getUsersByGroup($groupId, $recursive = false) 350 { 351 // Get a database object. 352 $db = JFactory::getDbo(); 353 354 $test = $recursive ? '>=' : '='; 355 356 // First find the users contained in the group 357 $query = $db->getQuery(true); 358 $query->select('DISTINCT(user_id)'); 359 $query->from('#__usergroups as ug1'); 360 $query->join('INNER', '#__usergroups AS ug2 ON ug2.lft' . $test . 'ug1.lft AND ug1.rgt' . $test . 'ug2.rgt'); 361 $query->join('INNER', '#__user_usergroup_map AS m ON ug2.id=m.group_id'); 362 $query->where('ug1.id=' . $db->Quote($groupId)); 363 364 $db->setQuery($query); 365 366 $result = $db->loadColumn(); 367 368 // Clean up any NULL values, just in case 369 JArrayHelper::toInteger($result); 370 371 return $result; 372 } 373 374 /** 375 * Method to return a list of view levels for which the user is authorised. 376 * 377 * @param integer $userId Id of the user for which to get the list of authorised view levels. 378 * 379 * @return array List of view levels for which the user is authorised. 380 * 381 * @since 11.1 382 */ 383 public static function getAuthorisedViewLevels($userId) 384 { 385 // Get all groups that the user is mapped to recursively. 386 $groups = self::getGroupsByUser($userId); 387 388 // Only load the view levels once. 389 if (empty(self::$viewLevels)) 390 { 391 // Get a database object. 392 $db = JFactory::getDBO(); 393 394 // Build the base query. 395 $query = $db->getQuery(true); 396 $query->select('id, rules'); 397 $query->from($query->qn('#__viewlevels')); 398 399 // Set the query for execution. 400 $db->setQuery((string) $query); 401 402 // Build the view levels array. 403 foreach ($db->loadAssocList() as $level) 404 { 405 self::$viewLevels[$level['id']] = (array) json_decode($level['rules']); 406 } 407 } 408 409 // Initialise the authorised array. 410 $authorised = array(1); 411 412 // Find the authorised levels. 413 foreach (self::$viewLevels as $level => $rule) 414 { 415 foreach ($rule as $id) 416 { 417 if (($id < 0) && (($id * -1) == $userId)) 418 { 419 $authorised[] = $level; 420 break; 421 } 422 // Check to see if the group is mapped to the level. 423 elseif (($id >= 0) && in_array($id, $groups)) 424 { 425 $authorised[] = $level; 426 break; 427 } 428 } 429 } 430 431 return $authorised; 432 } 433 434 /** 435 * Method to return a list of actions for which permissions can be set given a component and section. 436 * 437 * @param string $component The component from which to retrieve the actions. 438 * @param string $section The name of the section within the component from which to retrieve the actions. 439 * 440 * @return array List of actions available for the given component and section. 441 * 442 * @since 11.1 443 * 444 * @todo Need to decouple this method from the CMS. Maybe check if $component is a 445 * valid file (or create a getActionsFromFile method). 446 */ 447 public static function getActions($component, $section = 'component') 448 { 449 $actions = array(); 450 451 if (defined('JPATH_ADMINISTRATOR') && is_file(JPATH_ADMINISTRATOR . '/components/' . $component . '/access.xml')) 452 { 453 $xml = simplexml_load_file(JPATH_ADMINISTRATOR . '/components/' . $component . '/access.xml'); 454 455 foreach ($xml->children() as $child) 456 { 457 if ($section == (string) $child['name']) 458 { 459 foreach ($child->children() as $action) 460 { 461 $actions[] = (object) array( 462 'name' => (string) $action['name'], 463 'title' => (string) $action['title'], 464 'description' => (string) $action['description']); 465 } 466 467 break; 468 } 469 } 470 } 471 472 return $actions; 473 } 474 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Tue Apr 3 11:40:28 2012 | Cross-referenced by PHPXref 0.7.1 |