PageRenderTime 122ms CodeModel.GetById 64ms app.highlight 51ms RepoModel.GetById 0ms app.codeStats 1ms

/engine/lib/access.php

https://github.com/blacktooth/Elgg
PHP | 1001 lines | 473 code | 143 blank | 385 comment | 112 complexity | 46542fbe8bfc898b077a3ed9cc733bf2 MD5 | raw file
   1<?php
   2/**
   3 * Primary function for Elgg's entity and metadata access systems.
   4 *
   5 * Access is generally saved in the database as access_id.  This corresponds to
   6 * one of the ACCESS_* constants defined in {@link elgglib.php}, or the ID of an
   7 * access collection.
   8 *
   9 * @package Elgg.Core
  10 * @subpackage Access
  11 * @link http://docs.elgg.org/Access
  12 */
  13
  14/**
  15 * Return a string of access_ids for $user_id appropriate for inserting into an SQL IN clause.
  16 *
  17 * @uses get_access_array
  18 *
  19 * @return string A list of access collections suitable for injection in an SQL call
  20 * @link http://docs.elgg.org/Access
  21 * @see get_access_array()
  22 *
  23 * @param int  $user_id User ID; defaults to currently logged in user
  24 * @param int  $site_id Site ID; defaults to current site
  25 * @param bool $flush   If set to true, will refresh the access list from the database
  26 *
  27 * @return string
  28 */
  29function get_access_list($user_id = 0, $site_id = 0, $flush = false) {
  30	global $CONFIG, $init_finished;
  31	static $access_list;
  32
  33	if (!isset($access_list) || !$init_finished) {
  34		$access_list = array();
  35	}
  36
  37	if ($user_id == 0) {
  38		$user_id = elgg_get_logged_in_user_guid();
  39	}
  40
  41	if (($site_id == 0) && (isset($CONFIG->site_id))) {
  42		$site_id = $CONFIG->site_id;
  43	}
  44	$user_id = (int) $user_id;
  45	$site_id = (int) $site_id;
  46
  47	if (isset($access_list[$user_id]) && $flush == false) {
  48		return $access_list[$user_id];
  49	}
  50
  51	$access_list[$user_id] = "(" . implode(",", get_access_array($user_id, $site_id, $flush)) . ")";
  52
  53	return $access_list[$user_id];
  54}
  55
  56/**
  57 * Returns an array of access IDs a user is permitted to see.
  58 *
  59 * Can be overridden with the access:collections:read, user plugin hook.
  60 *
  61 * @param int     $user_id User ID; defaults to currently logged in user
  62 * @param int     $site_id Site ID; defaults to current site
  63 * @param boolean $flush   If set to true, will refresh the access list from the database
  64 *
  65 * @return array An array of access collections ids
  66 * @see get_access_list()
  67 */
  68function get_access_array($user_id = 0, $site_id = 0, $flush = false) {
  69	global $CONFIG, $init_finished;
  70
  71	// @todo everything from the db is cached.
  72	// this cache might be redundant. But cache is flushed on every db write.
  73	static $access_array;
  74
  75	if (!isset($access_array) || (!isset($init_finished)) || (!$init_finished)) {
  76		$access_array = array();
  77	}
  78
  79	if ($user_id == 0) {
  80		$user_id = elgg_get_logged_in_user_guid();
  81	}
  82
  83	if (($site_id == 0) && (isset($CONFIG->site_guid))) {
  84		$site_id = $CONFIG->site_guid;
  85	}
  86
  87	$user_id = (int) $user_id;
  88	$site_id = (int) $site_id;
  89
  90	if (empty($access_array[$user_id]) || $flush == true) {
  91		$tmp_access_array = array(ACCESS_PUBLIC);
  92
  93		// The following can only return sensible data if the user is logged in.
  94		if (elgg_is_logged_in()) {
  95			$tmp_access_array[] = ACCESS_LOGGED_IN;
  96
  97			// Get ACL memberships
  98			$query = "SELECT am.access_collection_id"
  99				. " FROM {$CONFIG->dbprefix}access_collection_membership am"
 100				. " LEFT JOIN {$CONFIG->dbprefix}access_collections ag ON ag.id = am.access_collection_id"
 101				. " WHERE am.user_guid = {$user_id} AND (ag.site_guid = {$site_id} OR ag.site_guid = 0)";
 102
 103			if ($collections = get_data($query)) {
 104				foreach ($collections as $collection) {
 105					if (!empty($collection->access_collection_id)) {
 106						$tmp_access_array[] = $collection->access_collection_id;
 107					}
 108				}
 109			}
 110
 111			// Get ACLs owned.
 112			$query = "SELECT ag.id FROM {$CONFIG->dbprefix}access_collections ag ";
 113			$query .= "WHERE ag.owner_guid = {$user_id} AND (ag.site_guid = {$site_id} OR ag.site_guid = 0)";
 114
 115			if ($collections = get_data($query)) {
 116				foreach ($collections as $collection) {
 117					if (!empty($collection->id)) {
 118						$tmp_access_array[] = $collection->id;
 119					}
 120				}
 121			}
 122
 123			$ignore_access = elgg_check_access_overrides($user_id);
 124
 125			if ($ignore_access == true) {
 126				$tmp_access_array[] = ACCESS_PRIVATE;
 127			}
 128
 129			$access_array[$user_id] = $tmp_access_array;
 130		} else {
 131			// No user id logged in so we can only access public info
 132			$tmp_return = $tmp_access_array;
 133		}
 134
 135	} else {
 136		$tmp_access_array = $access_array[$user_id];
 137	}
 138
 139	$options = array('user_id' => $user_id, 'site_id' => $site_id);
 140	return elgg_trigger_plugin_hook('access:collections:read', 'user', $options, $tmp_access_array);
 141}
 142
 143/**
 144 * Gets the default access permission.
 145 *
 146 * This returns the default access level for the site or optionally for the user.
 147 *
 148 * @param ElggUser $user Get the user's default access. Defaults to logged in user.
 149 *
 150 * @return int default access id (see ACCESS defines in elgglib.php)
 151 * @link http://docs.elgg.org/Access
 152 */
 153function get_default_access(ElggUser $user = null) {
 154	global $CONFIG;
 155
 156	if (!$CONFIG->allow_user_default_access) {
 157		return $CONFIG->default_access;
 158	}
 159
 160	if (!($user) && (!$user = elgg_get_logged_in_user_entity())) {
 161		return $CONFIG->default_access;
 162	}
 163
 164	if (false !== ($default_access = $user->getPrivateSetting('elgg_default_access'))) {
 165		return $default_access;
 166	} else {
 167		return $CONFIG->default_access;
 168	}
 169}
 170
 171/**
 172 * Allow disabled entities and metadata to be returned by getter functions
 173 *
 174 * @todo Replace this with query object!
 175 * @global bool $ENTITY_SHOW_HIDDEN_OVERRIDE
 176 * @access private
 177 */
 178$ENTITY_SHOW_HIDDEN_OVERRIDE = false;
 179
 180/**
 181 * Show or hide disabled entities.
 182 *
 183 * @access private
 184 *
 185 * @param bool $show_hidden Show disabled entities.
 186 *
 187 * @return void
 188 */
 189function access_show_hidden_entities($show_hidden) {
 190	global $ENTITY_SHOW_HIDDEN_OVERRIDE;
 191	$ENTITY_SHOW_HIDDEN_OVERRIDE = $show_hidden;
 192}
 193
 194/**
 195 * Return current status of showing disabled entities.
 196 *
 197 * @access private
 198 * @return bool
 199 */
 200function access_get_show_hidden_status() {
 201	global $ENTITY_SHOW_HIDDEN_OVERRIDE;
 202	return $ENTITY_SHOW_HIDDEN_OVERRIDE;
 203}
 204
 205/**
 206 * Add annotation restriction
 207 *
 208 * Returns an SQL fragment that is true (or optionally false) if the given user has
 209 * added an annotation with the given name to the given entity.
 210 *
 211 * @todo This is fairly generic so perhaps it could be moved to annotations.php
 212 *
 213 * @param string  $annotation_name Name of the annotation
 214 * @param string  $entity_guid     SQL GUID of entity the annotation is attached to.
 215 * @param string  $owner_guid      SQL string that evaluates to the GUID of the annotation owner
 216 * @param boolean $exists          If true, returns BOOL if the annotation exists
 217 *
 218 * @return string An SQL fragment suitable for inserting into a WHERE clause
 219 * @todo Document and maybe even remove.  At least rename to something that makes sense.
 220 */
 221function get_annotation_sql($annotation_name, $entity_guid, $owner_guid, $exists) {
 222	global $CONFIG;
 223
 224	if ($exists) {
 225		$not = '';
 226	} else {
 227		$not = 'NOT';
 228	}
 229
 230	$sql = <<<END
 231$not EXISTS (SELECT * FROM {$CONFIG->dbprefix}annotations a
 232INNER JOIN {$CONFIG->dbprefix}metastrings ms ON (a.name_id = ms.id)
 233WHERE ms.string = '$annotation_name'
 234AND a.entity_guid = $entity_guid
 235AND a.owner_guid = $owner_guid)
 236END;
 237	return $sql;
 238}
 239
 240/**
 241 * Returns the SQL where clause for a table with a access_id and enabled columns.
 242 *
 243 * This handles returning where clauses for ACCESS_FRIENDS, and the currently
 244 * unused block and filter lists.
 245 *
 246 * @warning If an admin is logged in or {@link elgg_set_ignore_access()} is true,
 247 * this will return blank.
 248 *
 249 * @param string $table_prefix Optional table. prefix for the access code.
 250 * @param int    $owner        The guid to check access for. Defaults to logged in user.
 251 *
 252 * @return string The SQL for a where clause
 253 * @access private
 254 */
 255function get_access_sql_suffix($table_prefix = '', $owner = null) {
 256	global $ENTITY_SHOW_HIDDEN_OVERRIDE, $CONFIG;
 257
 258	$sql = "";
 259	$friends_bit = "";
 260	$enemies_bit = "";
 261
 262	if ($table_prefix) {
 263			$table_prefix = sanitise_string($table_prefix) . ".";
 264	}
 265
 266	if (!isset($owner)) {
 267		$owner = elgg_get_logged_in_user_guid();
 268	}
 269
 270	if (!$owner) {
 271		$owner = -1;
 272	}
 273
 274	$ignore_access = elgg_check_access_overrides($owner);
 275	$access = get_access_list($owner);
 276
 277	if ($ignore_access) {
 278		$sql = " (1 = 1) ";
 279	} else if ($owner != -1) {
 280		$friends_bit = "{$table_prefix}access_id = " . ACCESS_FRIENDS . "
 281			AND {$table_prefix}owner_guid IN (
 282				SELECT guid_one FROM {$CONFIG->dbprefix}entity_relationships
 283				WHERE relationship='friend' AND guid_two=$owner
 284			)";
 285
 286		$friends_bit = '(' . $friends_bit . ') OR ';
 287
 288		if ((isset($CONFIG->user_block_and_filter_enabled)) && ($CONFIG->user_block_and_filter_enabled)) {
 289			// check to see if the user is in the entity owner's block list
 290			// or if the entity owner is in the user's filter list
 291			// if so, disallow access
 292			$enemies_bit = get_annotation_sql('elgg_block_list', "{$table_prefix}owner_guid", $owner, false);
 293			$enemies_bit = '('
 294				. $enemies_bit
 295				. '	AND ' . get_annotation_sql('elgg_filter_list', $owner, "{$table_prefix}owner_guid", false)
 296			. ')';
 297		}
 298	}
 299
 300	if (empty($sql)) {
 301		$sql = " $friends_bit ({$table_prefix}access_id IN {$access}
 302			OR ({$table_prefix}owner_guid = {$owner})
 303			OR (
 304				{$table_prefix}access_id = " . ACCESS_PRIVATE . "
 305				AND {$table_prefix}owner_guid = $owner
 306			)
 307		)";
 308	}
 309
 310	if ($enemies_bit) {
 311		$sql = "$enemies_bit AND ($sql)";
 312	}
 313
 314	if (!$ENTITY_SHOW_HIDDEN_OVERRIDE) {
 315		$sql .= " and {$table_prefix}enabled='yes'";
 316	}
 317
 318	return '(' . $sql . ')';
 319}
 320
 321/**
 322 * Can $user access $entity.
 323 *
 324 * @warning If a logged in user doesn't have access to an entity, the
 325 * core engine will not load that entity.
 326 *
 327 * @tip This is mostly useful for checking if a 3rd user has access
 328 * to an entity that is currently loaded.
 329 *
 330 * @param ElggEntity $entity The entity to check access for.
 331 * @param ElggUser   $user   Optionally user to check access for. Defaults to
 332 *                           logged in user (which doesn't make sense).
 333 *
 334 * @return boolean True if the user can access the entity
 335 * @link http://docs.elgg.org/Access
 336 */
 337function has_access_to_entity($entity, $user = null) {
 338	global $CONFIG;
 339
 340	if (!isset($user)) {
 341		$access_bit = get_access_sql_suffix("e");
 342	} else {
 343		$access_bit = get_access_sql_suffix("e", $user->getGUID());
 344	}
 345
 346	$query = "SELECT guid from {$CONFIG->dbprefix}entities e WHERE e.guid = " . $entity->getGUID();
 347	// Add access controls
 348	$query .= " AND " . $access_bit;
 349	if (get_data($query)) {
 350		return true;
 351	} else {
 352		return false;
 353	}
 354}
 355
 356/**
 357 * Returns an array of access permissions that the user is allowed to save objects with.
 358 * Permissions are of the form ('id' => 'Description')
 359 *
 360 * @param int  $user_id The user's GUID.
 361 * @param int  $site_id The current site.
 362 * @param bool $flush   If this is set to true, this will ignore any cached version
 363 *
 364 * @return array List of access permissions
 365 * @link http://docs.elgg.org/Access
 366 */
 367function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) {
 368	global $CONFIG;
 369	//@todo this is probably not needed since caching happens at the DB level.
 370	static $access_array;
 371
 372	if ($user_id == 0) {
 373		$user_id = elgg_get_logged_in_user_guid();
 374	}
 375
 376	if (($site_id == 0) && (isset($CONFIG->site_id))) {
 377		$site_id = $CONFIG->site_id;
 378	}
 379
 380	$user_id = (int) $user_id;
 381	$site_id = (int) $site_id;
 382
 383	if (empty($access_array[$user_id]) || $flush == true) {
 384		$query = "SELECT ag.* FROM {$CONFIG->dbprefix}access_collections ag ";
 385		$query .= " WHERE (ag.site_guid = {$site_id} OR ag.site_guid = 0)";
 386		$query .= " AND (ag.owner_guid = {$user_id})";
 387		$query .= " AND ag.id >= 3";
 388
 389		$tmp_access_array = array(
 390									ACCESS_PRIVATE => elgg_echo("PRIVATE"),
 391									ACCESS_FRIENDS => elgg_echo("access:friends:label"),
 392									ACCESS_LOGGED_IN => elgg_echo("LOGGED_IN"),
 393									ACCESS_PUBLIC => elgg_echo("PUBLIC")
 394								);
 395		if ($collections = get_data($query)) {
 396			foreach ($collections as $collection) {
 397				$tmp_access_array[$collection->id] = $collection->name;
 398			}
 399		}
 400
 401		$access_array[$user_id] = $tmp_access_array;
 402	} else {
 403		$tmp_access_array = $access_array[$user_id];
 404	}
 405
 406	$options = array('user_id' => $user_id, 'site_id' => $site_id);
 407	$tmp_access_array = elgg_trigger_plugin_hook('access:collections:write', 'user',
 408		$options, $tmp_access_array);
 409
 410	return $tmp_access_array;
 411}
 412
 413
 414/**
 415 * Can the user write to the access collection?
 416 *
 417 * Hook into the access:collections:write, user to change this.
 418 *
 419 * Respects access control disabling for admin users and {@see elgg_set_ignore_access()}
 420 *
 421 * @see get_write_access_array()
 422 *
 423 * @param int   $collection_id The collection id
 424 * @param mixed $user_guid     The user GUID to check for. Defaults to logged in user.
 425 * @return bool
 426 */
 427function can_edit_access_collection($collection_id, $user_guid = null) {
 428	if ($user_guid) {
 429		$user = get_entity((int) $user_guid);
 430	} else {
 431		$user = get_loggedin_user();
 432	}
 433
 434	$collection = get_access_collection($collection_id);
 435
 436	if (!($user instanceof ElggUser) || !$collection) {
 437		return false;
 438	}
 439
 440	$write_access = get_write_access_array($user->getGUID(), null, true);
 441
 442	// don't ignore access when checking users.
 443	if ($user_guid) {
 444		return array_key_exists($collection_id, $write_access);
 445	} else {
 446		return elgg_get_ignore_access() || array_key_exists($collection_id, $write_access);
 447	}
 448}
 449
 450/**
 451 * Creates a new access collection.
 452 *
 453 * Access colletions allow plugins and users to create granular access
 454 * for entities.
 455 *
 456 * @internal Access collections are stored in the access_collections table.
 457 * Memberships to collections are in access_collections_membership.
 458 *
 459 * @param string $name       The name of the collection.
 460 * @param int    $owner_guid The GUID of the owner (default: currently logged in user).
 461 * @param int    $site_guid  The GUID of the site (default: current site).
 462 *
 463 * @return int|false Depending on success (the collection ID if successful).
 464 * @link http://docs.elgg.org/Access/Collections
 465 * @see update_access_collection()
 466 * @see delete_access_collection()
 467 */
 468function create_access_collection($name, $owner_guid = 0, $site_guid = 0) {
 469	global $CONFIG;
 470
 471	$name = trim($name);
 472	if (empty($name)) {
 473		return false;
 474	}
 475
 476	if ($owner_guid == 0) {
 477		$owner_guid = elgg_get_logged_in_user_guid();
 478	}
 479	if (($site_guid == 0) && (isset($CONFIG->site_guid))) {
 480		$site_guid = $CONFIG->site_guid;
 481	}
 482	$name = sanitise_string($name);
 483
 484	$q = "INSERT INTO {$CONFIG->dbprefix}access_collections
 485		SET name = '{$name}',
 486			owner_guid = {$owner_guid},
 487			site_guid = {$site_guid}";
 488	if (!$id = insert_data($q)) {
 489		return false;
 490	}
 491
 492	$params = array(
 493		'collection_id' => $id
 494	);
 495
 496	if (!elgg_trigger_plugin_hook('access:collections:addcollection', 'collection', $params, true)) {
 497		return false;
 498	}
 499
 500	return $id;
 501}
 502
 503/**
 504 * Updates the membership in an access collection.
 505 *
 506 * @warning Expects a full list of all members that should
 507 * be part o the access collection
 508 *
 509 * @note This will run all hooks associated with adding or removing
 510 * members to access collections.
 511 *
 512 * @param int   $collection_id The ID of the collection.
 513 * @param array $members       Array of member GUIDs
 514 *
 515 * @return true|false Depending on success
 516 * @link http://docs.elgg.org/Access/Collections
 517 * @see add_user_to_access_collection()
 518 * @see remove_user_from_access_collection()
 519 */
 520function update_access_collection($collection_id, $members) {
 521	global $CONFIG;
 522
 523	$acl = get_access_collection($collection_id);
 524
 525	if (!$acl) {
 526		return false;
 527	}
 528	$members = (is_array($members)) ? $members : array();
 529
 530	$cur_members = get_members_of_access_collection($collection_id, true);
 531	$cur_members = (is_array($cur_members)) ? $cur_members : array();
 532
 533	$remove_members = array_diff($cur_members, $members);
 534	$add_members = array_diff($members, $cur_members);
 535
 536	$result = true;
 537
 538	foreach ($add_members as $guid) {
 539		$result = $result && add_user_to_access_collection($guid, $collection_id);
 540	}
 541
 542	foreach ($remove_members as $guid) {
 543		$result = $result && remove_user_from_access_collection($guid, $collection_id);
 544	}
 545
 546	return $result;
 547}
 548
 549/**
 550 * Deletes a specified access collection and its membership.
 551 *
 552 * @param int $collection_id The collection ID
 553 *
 554 * @return bool
 555 * @link http://docs.elgg.org/Access/Collections
 556 * @see create_access_collection()
 557 * @see update_access_collection()
 558 */
 559function delete_access_collection($collection_id) {
 560	global $CONFIG;
 561
 562	$collection_id = (int) $collection_id;
 563	$params = array('collection_id' => $collection_id);
 564
 565	if (!elgg_trigger_plugin_hook('access:collections:deletecollection', 'collection', $params, true)) {
 566		return false;
 567	}
 568
 569	// Deleting membership doesn't affect result of deleting ACL.
 570	$q = "DELETE FROM {$CONFIG->dbprefix}access_collection_membership
 571		WHERE access_collection_id = {$collection_id}";
 572	delete_data($q);
 573
 574	$q = "DELETE FROM {$CONFIG->dbprefix}access_collections
 575		WHERE id = {$collection_id}";
 576	$result = delete_data($q);
 577
 578
 579	return $result;
 580}
 581
 582/**
 583 * Get a specified access collection
 584 *
 585 * @note This doesn't return the members of an access collection,
 586 * just the database row of the actual collection.
 587 *
 588 * @param int $collection_id The collection ID
 589 *
 590 * @return object|false
 591 */
 592function get_access_collection($collection_id) {
 593	global $CONFIG;
 594	$collection_id = (int) $collection_id;
 595
 596	$query = "SELECT * FROM {$CONFIG->dbprefix}access_collections WHERE id = {$collection_id}";
 597	$get_collection = get_data_row($query);
 598
 599	return $get_collection;
 600}
 601
 602/**
 603 * Adds a user to an access collection.
 604 *
 605 * Emits the access:collections:add_user, collection plugin hook.
 606 *
 607 * @param int $user_guid     The GUID of the user to add
 608 * @param int $collection_id The ID of the collection to add them to
 609 *
 610 * @return true|false Depending on success
 611 * @link http://docs.elgg.org/Access/Collections
 612 * @see update_access_collection()
 613 * @see remove_user_from_access_collection()
 614 */
 615function add_user_to_access_collection($user_guid, $collection_id) {
 616	global $CONFIG;
 617
 618	$collection_id = (int) $collection_id;
 619	$user_guid = (int) $user_guid;
 620	$user = get_user($user_guid);
 621
 622	$collection = get_access_collection($collection_id);
 623
 624	if (!($user instanceof Elgguser) || !$collection) {
 625		return false;
 626	}
 627
 628	$params = array(
 629		'collection_id' => $collection_id,
 630		'user_guid' => $user_guid
 631	);
 632
 633	$result = elgg_trigger_plugin_hook('access:collections:add_user', 'collection', $params, true);
 634	if ($result == false) {
 635		return false;
 636	}
 637
 638	try {
 639		$q = "INSERT INTO {$CONFIG->dbprefix}access_collection_membership
 640			SET access_collection_id = {$collection_id},
 641				user_guid = {$user_guid}";
 642		insert_data($q);
 643	} catch (DatabaseException $e) {
 644		return false;
 645	}
 646
 647	return true;
 648}
 649
 650/**
 651 * Removes a user from an access collection.
 652 *
 653 * Emits the access:collections:remove_user, collection plugin hook.
 654 *
 655 * @param int $user_guid     The user GUID
 656 * @param int $collection_id The access collection ID
 657 *
 658 * @return true|false Depending on success
 659 */
 660function remove_user_from_access_collection($user_guid, $collection_id) {
 661	global $CONFIG;
 662
 663	$collection_id = (int) $collection_id;
 664	$user_guid = (int) $user_guid;
 665	$user = get_user($user_guid);
 666
 667	$collection = get_access_collection($collection_id);
 668
 669	if (!($user instanceof Elgguser) || !$collection) {
 670		return false;
 671	}
 672
 673	$params = array(
 674		'collection_id' => $collection_id,
 675		'user_guid' => $user_guid
 676	);
 677
 678	if (!elgg_trigger_plugin_hook('access:collections:remove_user', 'collection', $params, true)) {
 679		return false;
 680	}
 681
 682	$q = "DELETE FROM {$CONFIG->dbprefix}access_collection_membership
 683		WHERE access_collection_id = {$collection_id}
 684			AND user_guid = {$user_guid}";
 685
 686	return delete_data($q);
 687}
 688
 689/**
 690 * Returns an array of database row objects of the access collections owned by $owner_guid.
 691 *
 692 * @param int $owner_guid The entity guid
 693 * @param int $site_guid  The GUID of the site (default: current site).
 694 *
 695 * @return array|false
 696 * @see add_access_collection()
 697 * @see get_members_of_access_collection()
 698 * @link http://docs.elgg.org/Access/Collections
 699 */
 700function get_user_access_collections($owner_guid, $site_guid = 0) {
 701	global $CONFIG;
 702	$owner_guid = (int) $owner_guid;
 703	$site_guid = (int) $site_guid;
 704
 705	if (($site_guid == 0) && (isset($CONFIG->site_guid))) {
 706		$site_guid = $CONFIG->site_guid;
 707	}
 708
 709	$query = "SELECT * FROM {$CONFIG->dbprefix}access_collections
 710			WHERE owner_guid = {$owner_guid}
 711			AND site_guid = {$site_guid}";
 712
 713	$collections = get_data($query);
 714
 715	return $collections;
 716}
 717
 718/**
 719 * Get all of members of an access collection
 720 *
 721 * @param int  $collection The collection's ID
 722 * @param bool $idonly     If set to true, will only return the members' GUIDs (default: false)
 723 *
 724 * @return array ElggUser guids or entities if successful, false if not
 725 * @see add_user_to_access_collection()
 726 * @see http://docs.elgg.org/Access/Collections
 727 */
 728function get_members_of_access_collection($collection, $idonly = FALSE) {
 729	global $CONFIG;
 730	$collection = (int)$collection;
 731
 732	if (!$idonly) {
 733		$query = "SELECT e.* FROM {$CONFIG->dbprefix}access_collection_membership m"
 734			. " JOIN {$CONFIG->dbprefix}entities e ON e.guid = m.user_guid"
 735			. " WHERE m.access_collection_id = {$collection}";
 736		$collection_members = get_data($query, "entity_row_to_elggstar");
 737	} else {
 738		$query = "SELECT e.guid FROM {$CONFIG->dbprefix}access_collection_membership m"
 739			. " JOIN {$CONFIG->dbprefix}entities e ON e.guid = m.user_guid"
 740			. " WHERE m.access_collection_id = {$collection}";
 741		$collection_members = get_data($query);
 742		if (!$collection_members) {
 743			return FALSE;
 744		}
 745		foreach ($collection_members as $key => $val) {
 746			$collection_members[$key] = $val->guid;
 747		}
 748	}
 749
 750	return $collection_members;
 751}
 752
 753/**
 754 * Displays a user's access collections, using the core/friends/collections view
 755 *
 756 * @param int $owner_guid The GUID of the owning user
 757 *
 758 * @return string A formatted rendition of the collections
 759 * @todo Move to the friends/collection.php page.
 760 */
 761function elgg_view_access_collections($owner_guid) {
 762	if ($collections = get_user_access_collections($owner_guid)) {
 763		foreach ($collections as $key => $collection) {
 764			$collections[$key]->members = get_members_of_access_collection($collection->id, true);
 765			$collections[$key]->entities = get_user_friends($owner_guid, "", 9999);
 766		}
 767	}
 768
 769	return elgg_view('core/friends/collections', array('collections' => $collections));
 770}
 771
 772/**
 773 * Return entities based upon access id.
 774 *
 775 * @param array $options Any options accepted by {@link elgg_get_entities()} and:
 776 * 	access_id => int The access ID of the entity.
 777 *
 778 * @see elgg_get_entities()
 779 * @return array
 780 * @since 1.7.0
 781 */
 782function elgg_get_entities_from_access_id(array $options = array()) {
 783	// restrict the resultset to access collection provided
 784	if (!isset($options['access_id'])) {
 785		return FALSE;
 786	}
 787
 788	// @todo add support for an array of collection_ids
 789	$where = "e.access_id = '{$options['access_id']}'";
 790	if (isset($options['wheres'])) {
 791		if (is_array($options['wheres'])) {
 792			$options['wheres'][] = $where;
 793		} else {
 794			$options['wheres'] = array($options['wheres'], $where);
 795		}
 796	} else {
 797		$options['wheres'] = array($where);
 798	}
 799
 800	// return entities with the desired options
 801	return elgg_get_entities($options);
 802}
 803
 804/**
 805 * Lists entities from an access collection
 806 *
 807 * @param array $options See elgg_list_entities() and elgg_get_entities_from_access_id()
 808 * 
 809 * @see elgg_list_entities()
 810 * @see elgg_get_entities_from_access_id()
 811 * 
 812 * @return str
 813 */
 814function elgg_list_entities_from_access_id(array $options = array()) {
 815	return elgg_list_entities($options, 'elgg_get_entities_from_access_id');
 816}
 817
 818/**
 819 * Return the name of an ACCESS_* constant or a access collection,
 820 * but only if the user has write access on that ACL.
 821 *
 822 * @warning This function probably doesn't work how it's meant to.
 823 *
 824 * @param int $entity_accessid The entity's access id
 825 *
 826 * @return string e.g. Public, Private etc
 827 * @since 1.7.0
 828 * @todo I think this probably wants get_access_array() instead of get_write_access_array(),
 829 * but those two functions return different types of arrays.
 830 */
 831function get_readable_access_level($entity_accessid) {
 832	$access = (int) $entity_accessid;
 833
 834	//get the access level for object in readable string
 835	$options = get_write_access_array();
 836
 837	//@todo Really?  Use array_key_exists()
 838	foreach ($options as $key => $option) {
 839		if ($key == $access) {
 840			$entity_acl = htmlentities($option, ENT_QUOTES, 'UTF-8');
 841			return $entity_acl;
 842			break;
 843		}
 844	}
 845	return false;
 846}
 847
 848/**
 849 * Set if entity access system should be ignored.
 850 *
 851 * The access system will not return entities in any getter
 852 * functions if the user doesn't have access.
 853 *
 854 * @internal For performance reasons this is done at the database level.
 855 *
 856 * @tip Use this to access entities in automated scripts
 857 * when no user is logged in.
 858 *
 859 * @warning This will not show disabled entities.  Use {@link $ENTITY_SHOW_HIDDEN_OVERRIDE}
 860 * for that.
 861 *
 862 * @param bool $ignore If true, disables all access checks.
 863 *
 864 * @return bool Previous ignore_access setting.
 865 * @since 1.7.0
 866 * @see http://docs.elgg.org/Access/IgnoreAccess
 867 * @see elgg_get_ignore_access()
 868 */
 869function elgg_set_ignore_access($ignore = true) {
 870	$elgg_access = elgg_get_access_object();
 871	return $elgg_access->setIgnoreAccess($ignore);
 872}
 873
 874/**
 875 * Get current ignore access setting.
 876 *
 877 * @return bool
 878 * @since 1.7.0
 879 * @see http://docs.elgg.org/Access/IgnoreAccess
 880 * @see elgg_set_ignore_access()
 881 */
 882function elgg_get_ignore_access() {
 883	return elgg_get_access_object()->getIgnoreAccess();
 884}
 885
 886/**
 887 * Decides if the access system is being ignored.
 888 *
 889 * The access system can be ignored if 1) an admin user is logged in
 890 * or 2) {@link elgg_set_ignore_access()} was called with true.
 891 *
 892 * @param mixed $user_guid The user to check against. Defaults to logged in.
 893 *
 894 * @return bool
 895 * @since 1.7.0
 896 */
 897function elgg_check_access_overrides($user_guid = null) {
 898	if (!$user_guid || $user_guid <= 0) {
 899		$is_admin = false;
 900	} else {
 901		$is_admin = elgg_is_admin_user($user_guid);
 902	}
 903
 904	return ($is_admin || elgg_get_ignore_access());
 905}
 906
 907/**
 908 * Returns the ElggAccess object.
 909 *
 910 * This is used to
 911 *
 912 * @return ElggAccess
 913 * @since 1.7.0
 914 * @access private
 915 */
 916function elgg_get_access_object() {
 917	static $elgg_access;
 918
 919	if (!$elgg_access) {
 920		$elgg_access = new ElggAccess();
 921	}
 922
 923	return $elgg_access;
 924}
 925
 926/**
 927 * A flag to set if Elgg's access initialization is finished.
 928 *
 929 * @global bool $init_finished
 930 * @access private
 931 * @todo investigate why this is needed
 932 */
 933$init_finished = false;
 934
 935/**
 936 * A quick and dirty way to make sure the access permissions have been correctly set up
 937 *
 938 * @elgg_event_handler init system
 939 * @todo Invesigate
 940 *
 941 * @return void
 942 */
 943function access_init() {
 944	global $init_finished;
 945	$init_finished = true;
 946}
 947
 948/**
 949 * Check if the access system should be overridden.
 950 *
 951 * Allows admin users and calls after {@link elgg_set_ignore_access} to
 952 * by pass the access system.
 953 *
 954 * @return true|null
 955 * @since 1.7.0
 956 * @elgg_event_handler permissions_check all
 957 */
 958function elgg_override_permissions_hook($hook, $type, $value, $params) {
 959	$user = elgg_extract('user', $params);
 960	if (!$user) {
 961		$user = elgg_get_logged_in_user_entity();
 962	}
 963
 964	// don't do this so ignore access still works.
 965//	if (!$user instanceof ElggUser) {
 966//		return false;
 967//	}
 968
 969	$user_guid = $user->guid;
 970
 971	// check for admin
 972	if ($user_guid && elgg_is_admin_user($user_guid)) {
 973		return true;
 974	}
 975
 976	// check access overrides
 977	if ((elgg_check_access_overrides($user_guid))) {
 978		return true;
 979	}
 980
 981	// consult other hooks
 982	return NULL;
 983}
 984
 985/**
 986 * Runs unit tests for the entities object.
 987 */
 988function access_test($hook, $type, $value, $params) {
 989	global $CONFIG;
 990	$value[] = $CONFIG->path . 'engine/tests/api/access_collections.php';
 991	return $value;
 992}
 993
 994// This function will let us know when 'init' has finished
 995elgg_register_event_handler('init', 'system', 'access_init', 9999);
 996
 997// For overrided permissions
 998elgg_register_plugin_hook_handler('permissions_check', 'all', 'elgg_override_permissions_hook');
 999elgg_register_plugin_hook_handler('container_permissions_check', 'all', 'elgg_override_permissions_hook');
1000
1001elgg_register_plugin_hook_handler('unit_test', 'system', 'access_test');