aboutsummaryrefslogtreecommitdiff
path: root/engine/lib
diff options
context:
space:
mode:
Diffstat (limited to 'engine/lib')
-rw-r--r--engine/lib/access.php640
-rw-r--r--engine/lib/actions.php368
-rw-r--r--engine/lib/admin.php228
-rw-r--r--engine/lib/annotations.php261
-rw-r--r--engine/lib/cache.php233
-rw-r--r--engine/lib/calendar.php12
-rw-r--r--engine/lib/configuration.php188
-rw-r--r--engine/lib/cron.php14
-rw-r--r--engine/lib/database.php228
-rw-r--r--engine/lib/deprecated-1.7.php2
-rw-r--r--engine/lib/deprecated-1.8.php631
-rw-r--r--engine/lib/deprecated-1.9.php582
-rw-r--r--engine/lib/elgglib.php607
-rw-r--r--engine/lib/entities.php863
-rw-r--r--engine/lib/export.php34
-rw-r--r--engine/lib/extender.php45
-rw-r--r--engine/lib/filestore.php25
-rw-r--r--engine/lib/group.php59
-rw-r--r--engine/lib/input.php197
-rw-r--r--engine/lib/languages.php156
-rw-r--r--engine/lib/location.php6
-rw-r--r--engine/lib/mb_wrapper.php2
-rw-r--r--engine/lib/memcache.php20
-rw-r--r--engine/lib/metadata.php273
-rw-r--r--engine/lib/metastrings.php159
-rw-r--r--engine/lib/navigation.php216
-rw-r--r--engine/lib/notification.php66
-rw-r--r--engine/lib/objects.php16
-rw-r--r--engine/lib/opendd.php7
-rw-r--r--engine/lib/output.php233
-rw-r--r--engine/lib/pagehandler.php108
-rw-r--r--engine/lib/pageowner.php43
-rw-r--r--engine/lib/pam.php8
-rw-r--r--engine/lib/plugins.php278
-rw-r--r--engine/lib/private_settings.php28
-rw-r--r--engine/lib/relationships.php105
-rw-r--r--engine/lib/river.php342
-rw-r--r--engine/lib/sessions.php53
-rw-r--r--engine/lib/sites.php66
-rw-r--r--engine/lib/statistics.php16
-rw-r--r--engine/lib/system_log.php49
-rw-r--r--engine/lib/tags.php48
-rw-r--r--engine/lib/upgrade.php189
-rw-r--r--engine/lib/upgrades/2009102801.php5
-rw-r--r--engine/lib/upgrades/2010033101.php2
-rw-r--r--engine/lib/upgrades/2010052601.php12
-rw-r--r--engine/lib/upgrades/2010061501.php6
-rw-r--r--engine/lib/upgrades/2010071001.php5
-rw-r--r--engine/lib/upgrades/2010071002.php5
-rw-r--r--engine/lib/upgrades/2010121602.php2
-rw-r--r--engine/lib/upgrades/2011010101.php9
-rw-r--r--engine/lib/upgrades/2011030700-1.8_svn-blog_status_metadata-4645225d7b440876.php3
-rw-r--r--engine/lib/upgrades/2011052801.php46
-rw-r--r--engine/lib/upgrades/2011061200-1.8b1-sites_need_a_site_guid-6d9dcbf46c0826cc.php31
-rw-r--r--engine/lib/upgrades/2011092500-1.8.0.1-forum_reply_river_view-5758ce8d86ac56ce.php12
-rw-r--r--engine/lib/upgrades/2011123100-1.8.2-fix_friend_river-b17e7ff8345c2269.php12
-rw-r--r--engine/lib/upgrades/2011123101-1.8.2-fix_blog_status-b14c2a0e7b9e7d55.php25
-rw-r--r--engine/lib/upgrades/2012012000-1.8.3-ip_in_syslog-87fe0f068cf62428.php12
-rw-r--r--engine/lib/upgrades/2012012100-1.8.3-system_cache-93100e7d55a24a11.php13
-rw-r--r--engine/lib/upgrades/2012041800-1.8.3-dont_filter_passwords-c0ca4a18b38ae2bc.php11
-rw-r--r--engine/lib/upgrades/2012041801-1.8.3-multiple_user_tokens-852225f7fd89f6c5.php13
-rw-r--r--engine/lib/upgrades/2013030600-1.8.13-update_user_location-8999eb8bf1bdd9a3.php24
-rw-r--r--engine/lib/upgrades/2013051700-1.8.15-add_missing_group_index-52a63a3a3ffaced2.php28
-rw-r--r--engine/lib/upgrades/2013052900-1.8.15-ipv6_in_syslog-f5c2cc0196e9e731.php12
-rw-r--r--engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php16
-rw-r--r--engine/lib/upgrades/create_upgrade.php5
-rw-r--r--engine/lib/user_settings.php64
-rw-r--r--engine/lib/users.php479
-rw-r--r--engine/lib/views.php478
-rw-r--r--engine/lib/web_services.php96
-rw-r--r--engine/lib/widgets.php136
-rw-r--r--engine/lib/xml-rpc.php5
-rw-r--r--engine/lib/xml.php40
73 files changed, 6484 insertions, 2827 deletions
diff --git a/engine/lib/access.php b/engine/lib/access.php
index cde3d256f..de0693ea8 100644
--- a/engine/lib/access.php
+++ b/engine/lib/access.php
@@ -1,9 +1,9 @@
<?php
/**
- * Primary function for Elgg's entity and metadata access systems.
+ * Functions for Elgg's access system for entities, metadata, and annotations.
*
* Access is generally saved in the database as access_id. This corresponds to
- * one of the ACCESS_* constants defined in {@link elgglib.php}, or the ID of an
+ * one of the ACCESS_* constants defined in {@link elgglib.php} or the ID of an
* access collection.
*
* @package Elgg.Core
@@ -12,26 +12,47 @@
*/
/**
+ * Return an ElggCache static variable cache for the access caches
+ *
+ * @staticvar ElggStaticVariableCache $access_cache
+ * @return \ElggStaticVariableCache
+ * @access private
+ */
+function _elgg_get_access_cache() {
+ /**
+ * A default filestore cache using the dataroot.
+ */
+ static $access_cache;
+
+ if (!$access_cache) {
+ $access_cache = new ElggStaticVariableCache('access');
+ }
+
+ return $access_cache;
+}
+
+/**
* Return a string of access_ids for $user_id appropriate for inserting into an SQL IN clause.
*
* @uses get_access_array
*
- * @return string A list of access collections suitable for injection in an SQL call
* @link http://docs.elgg.org/Access
* @see get_access_array()
*
* @param int $user_id User ID; defaults to currently logged in user
* @param int $site_id Site ID; defaults to current site
- * @param bool $flush If set to true, will refresh the access list from the database
+ * @param bool $flush If set to true, will refresh the access list from the
+ * database rather than using this function's cache.
*
- * @return string
+ * @return string A list of access collections suitable for using in an SQL call
+ * @access private
*/
function get_access_list($user_id = 0, $site_id = 0, $flush = false) {
global $CONFIG, $init_finished;
- static $access_list;
-
- if (!isset($access_list) || !$init_finished) {
- $access_list = array();
+ $cache = _elgg_get_access_cache();
+
+ if ($flush) {
+ $cache->clear();
}
if ($user_id == 0) {
@@ -44,36 +65,51 @@ function get_access_list($user_id = 0, $site_id = 0, $flush = false) {
$user_id = (int) $user_id;
$site_id = (int) $site_id;
- if (isset($access_list[$user_id]) && $flush == false) {
- return $access_list[$user_id];
- }
+ $hash = $user_id . $site_id . 'get_access_list';
- $access_list[$user_id] = "(" . implode(",", get_access_array($user_id, $site_id, $flush)) . ")";
+ if ($cache[$hash]) {
+ return $cache[$hash];
+ }
+
+ $access_array = get_access_array($user_id, $site_id, $flush);
+ $access = "(" . implode(",", $access_array) . ")";
- return $access_list[$user_id];
+ if ($init_finished) {
+ $cache[$hash] = $access;
+ }
+
+ return $access;
}
/**
* Returns an array of access IDs a user is permitted to see.
*
- * Can be overridden with the access:collections:read, user plugin hook.
+ * Can be overridden with the 'access:collections:read', 'user' plugin hook.
+ *
+ * This returns a list of all the collection ids a user owns or belongs
+ * to plus public and logged in access levels. If the user is an admin, it includes
+ * the private access level.
*
- * @param int $user_id User ID; defaults to currently logged in user
- * @param int $site_id Site ID; defaults to current site
- * @param boolean $flush If set to true, will refresh the access list from the database
+ * @internal this is only used in core for creating the SQL where clause when
+ * retrieving content from the database. The friends access level is handled by
+ * get_access_sql_suffix().
+ *
+ * @see get_write_access_array() for the access levels that a user can write to.
+ *
+ * @param int $user_id User ID; defaults to currently logged in user
+ * @param int $site_id Site ID; defaults to current site
+ * @param bool $flush If set to true, will refresh the access ids from the
+ * database rather than using this function's cache.
*
* @return array An array of access collections ids
- * @see get_access_list()
*/
function get_access_array($user_id = 0, $site_id = 0, $flush = false) {
global $CONFIG, $init_finished;
- // @todo everything from the db is cached.
- // this cache might be redundant. But cache is flushed on every db write.
- static $access_array;
+ $cache = _elgg_get_access_cache();
- if (!isset($access_array) || (!isset($init_finished)) || (!$init_finished)) {
- $access_array = array();
+ if ($flush) {
+ $cache->clear();
}
if ($user_id == 0) {
@@ -87,35 +123,41 @@ function get_access_array($user_id = 0, $site_id = 0, $flush = false) {
$user_id = (int) $user_id;
$site_id = (int) $site_id;
- if (empty($access_array[$user_id]) || $flush == true) {
- $tmp_access_array = array(ACCESS_PUBLIC);
+ $hash = $user_id . $site_id . 'get_access_array';
+
+ if ($cache[$hash]) {
+ $access_array = $cache[$hash];
+ } else {
+ $access_array = array(ACCESS_PUBLIC);
// The following can only return sensible data if the user is logged in.
if (elgg_is_logged_in()) {
- $tmp_access_array[] = ACCESS_LOGGED_IN;
+ $access_array[] = ACCESS_LOGGED_IN;
// Get ACL memberships
$query = "SELECT am.access_collection_id"
. " FROM {$CONFIG->dbprefix}access_collection_membership am"
. " LEFT JOIN {$CONFIG->dbprefix}access_collections ag ON ag.id = am.access_collection_id"
- . " WHERE am.user_guid = {$user_id} AND (ag.site_guid = {$site_id} OR ag.site_guid = 0)";
+ . " WHERE am.user_guid = $user_id AND (ag.site_guid = $site_id OR ag.site_guid = 0)";
- if ($collections = get_data($query)) {
+ $collections = get_data($query);
+ if ($collections) {
foreach ($collections as $collection) {
if (!empty($collection->access_collection_id)) {
- $tmp_access_array[] = $collection->access_collection_id;
+ $access_array[] = (int)$collection->access_collection_id;
}
}
}
// Get ACLs owned.
$query = "SELECT ag.id FROM {$CONFIG->dbprefix}access_collections ag ";
- $query .= "WHERE ag.owner_guid = {$user_id} AND (ag.site_guid = {$site_id} OR ag.site_guid = 0)";
+ $query .= "WHERE ag.owner_guid = $user_id AND (ag.site_guid = $site_id OR ag.site_guid = 0)";
- if ($collections = get_data($query)) {
+ $collections = get_data($query);
+ if ($collections) {
foreach ($collections as $collection) {
if (!empty($collection->id)) {
- $tmp_access_array[] = $collection->id;
+ $access_array[] = (int)$collection->id;
}
}
}
@@ -123,21 +165,21 @@ function get_access_array($user_id = 0, $site_id = 0, $flush = false) {
$ignore_access = elgg_check_access_overrides($user_id);
if ($ignore_access == true) {
- $tmp_access_array[] = ACCESS_PRIVATE;
+ $access_array[] = ACCESS_PRIVATE;
}
-
- $access_array[$user_id] = $tmp_access_array;
- } else {
- // No user id logged in so we can only access public info
- $tmp_return = $tmp_access_array;
}
- } else {
- $tmp_access_array = $access_array[$user_id];
+ if ($init_finished) {
+ $cache[$hash] = $access_array;
+ }
}
- $options = array('user_id' => $user_id, 'site_id' => $site_id);
- return elgg_trigger_plugin_hook('access:collections:read', 'user', $options, $tmp_access_array);
+ $options = array(
+ 'user_id' => $user_id,
+ 'site_id' => $site_id
+ );
+
+ return elgg_trigger_plugin_hook('access:collections:read', 'user', $options, $access_array);
}
/**
@@ -180,11 +222,9 @@ $ENTITY_SHOW_HIDDEN_OVERRIDE = false;
/**
* Show or hide disabled entities.
*
- * @access private
- *
* @param bool $show_hidden Show disabled entities.
- *
* @return void
+ * @access private
*/
function access_show_hidden_entities($show_hidden) {
global $ENTITY_SHOW_HIDDEN_OVERRIDE;
@@ -194,8 +234,8 @@ function access_show_hidden_entities($show_hidden) {
/**
* Return current status of showing disabled entities.
*
- * @access private
* @return bool
+ * @access private
*/
function access_get_show_hidden_status() {
global $ENTITY_SHOW_HIDDEN_OVERRIDE;
@@ -203,48 +243,11 @@ function access_get_show_hidden_status() {
}
/**
- * Add annotation restriction
- *
- * Returns an SQL fragment that is true (or optionally false) if the given user has
- * added an annotation with the given name to the given entity.
- *
- * @todo This is fairly generic so perhaps it could be moved to annotations.php
- *
- * @param string $annotation_name Name of the annotation
- * @param string $entity_guid SQL GUID of entity the annotation is attached to.
- * @param string $owner_guid SQL string that evaluates to the GUID of the annotation owner
- * @param boolean $exists If true, returns BOOL if the annotation exists
- *
- * @return string An SQL fragment suitable for inserting into a WHERE clause
- * @todo Document and maybe even remove. At least rename to something that makes sense.
- */
-function get_annotation_sql($annotation_name, $entity_guid, $owner_guid, $exists) {
- global $CONFIG;
-
- if ($exists) {
- $not = '';
- } else {
- $not = 'NOT';
- }
-
- $sql = <<<END
-$not EXISTS (SELECT * FROM {$CONFIG->dbprefix}annotations a
-INNER JOIN {$CONFIG->dbprefix}metastrings ms ON (a.name_id = ms.id)
-WHERE ms.string = '$annotation_name'
-AND a.entity_guid = $entity_guid
-AND a.owner_guid = $owner_guid)
-END;
- return $sql;
-}
-
-/**
* Returns the SQL where clause for a table with a access_id and enabled columns.
*
- * This handles returning where clauses for ACCESS_FRIENDS, and the currently
- * unused block and filter lists.
- *
- * @warning If an admin is logged in or {@link elgg_set_ignore_access()} is true,
- * this will return blank.
+ * This handles returning where clauses for ACCESS_FRIENDS and the currently
+ * unused block and filter lists in addition to using get_access_list() for
+ * access collections and the standard access levels.
*
* @param string $table_prefix Optional table. prefix for the access code.
* @param int $owner The guid to check access for. Defaults to logged in user.
@@ -260,7 +263,7 @@ function get_access_sql_suffix($table_prefix = '', $owner = null) {
$enemies_bit = "";
if ($table_prefix) {
- $table_prefix = sanitise_string($table_prefix) . ".";
+ $table_prefix = sanitise_string($table_prefix) . ".";
}
if (!isset($owner)) {
@@ -277,6 +280,7 @@ function get_access_sql_suffix($table_prefix = '', $owner = null) {
if ($ignore_access) {
$sql = " (1 = 1) ";
} else if ($owner != -1) {
+ // we have an entity's guid and auto check for friend relationships
$friends_bit = "{$table_prefix}access_id = " . ACCESS_FRIENDS . "
AND {$table_prefix}owner_guid IN (
SELECT guid_one FROM {$CONFIG->dbprefix}entity_relationships
@@ -285,14 +289,15 @@ function get_access_sql_suffix($table_prefix = '', $owner = null) {
$friends_bit = '(' . $friends_bit . ') OR ';
+ // @todo untested and unsupported at present
if ((isset($CONFIG->user_block_and_filter_enabled)) && ($CONFIG->user_block_and_filter_enabled)) {
// check to see if the user is in the entity owner's block list
// or if the entity owner is in the user's filter list
// if so, disallow access
- $enemies_bit = get_annotation_sql('elgg_block_list', "{$table_prefix}owner_guid", $owner, false);
+ $enemies_bit = get_access_restriction_sql('elgg_block_list', "{$table_prefix}owner_guid", $owner, false);
$enemies_bit = '('
. $enemies_bit
- . ' AND ' . get_annotation_sql('elgg_filter_list', $owner, "{$table_prefix}owner_guid", false)
+ . ' AND ' . get_access_restriction_sql('elgg_filter_list', $owner, "{$table_prefix}owner_guid", false)
. ')';
}
}
@@ -319,19 +324,59 @@ function get_access_sql_suffix($table_prefix = '', $owner = null) {
}
/**
- * Can $user access $entity.
+ * Get the where clause for an access restriction based on annotations
+ *
+ * Returns an SQL fragment that is true (or optionally false) if the given user has
+ * added an annotation with the given name to the given entity.
+ *
+ * @warning this is a private function for an untested capability and will likely
+ * be removed from a future version of Elgg.
+ *
+ * @param string $annotation_name Name of the annotation
+ * @param string $entity_guid SQL GUID of entity the annotation is attached to.
+ * @param string $owner_guid SQL string that evaluates to the GUID of the annotation owner
+ * @param boolean $exists If true, returns BOOL if the annotation exists
+ *
+ * @return string An SQL fragment suitable for inserting into a WHERE clause
+ * @access private
+ */
+function get_access_restriction_sql($annotation_name, $entity_guid, $owner_guid, $exists) {
+ global $CONFIG;
+
+ if ($exists) {
+ $not = '';
+ } else {
+ $not = 'NOT';
+ }
+
+ $sql = <<<END
+$not EXISTS (SELECT * FROM {$CONFIG->dbprefix}annotations a
+INNER JOIN {$CONFIG->dbprefix}metastrings ms ON (a.name_id = ms.id)
+WHERE ms.string = '$annotation_name'
+AND a.entity_guid = $entity_guid
+AND a.owner_guid = $owner_guid)
+END;
+ return $sql;
+}
+
+/**
+ * Can a user access an entity.
*
* @warning If a logged in user doesn't have access to an entity, the
* core engine will not load that entity.
*
- * @tip This is mostly useful for checking if a 3rd user has access
- * to an entity that is currently loaded.
+ * @tip This is mostly useful for checking if a user other than the logged in
+ * user has access to an entity that is currently loaded.
+ *
+ * @todo This function would be much more useful if we could pass the guid of the
+ * entity to test access for. We need to be able to tell whether the entity exists
+ * and whether the user has access to the entity.
*
* @param ElggEntity $entity The entity to check access for.
* @param ElggUser $user Optionally user to check access for. Defaults to
- * logged in user (which doesn't make sense).
+ * logged in user (which is a useless default).
*
- * @return boolean True if the user can access the entity
+ * @return bool
* @link http://docs.elgg.org/Access
*/
function has_access_to_entity($entity, $user = null) {
@@ -354,20 +399,38 @@ function has_access_to_entity($entity, $user = null) {
}
/**
- * Returns an array of access permissions that the user is allowed to save objects with.
- * Permissions are of the form ('id' => 'Description')
+ * Returns an array of access permissions that the user is allowed to save content with.
+ * Permissions returned are of the form (id => 'name').
+ *
+ * Example return value in English:
+ * array(
+ * 0 => 'Private',
+ * -2 => 'Friends',
+ * 1 => 'Logged in users',
+ * 2 => 'Public',
+ * 34 => 'My favorite friends',
+ * );
+ *
+ * Plugin hook of 'access:collections:write', 'user'
+ *
+ * @warning this only returns access collections that the user owns plus the
+ * standard access levels. It does not return access collections that the user
+ * belongs to such as the access collection for a group.
*
* @param int $user_id The user's GUID.
* @param int $site_id The current site.
- * @param bool $flush If this is set to true, this will ignore any cached version
+ * @param bool $flush If this is set to true, this will ignore a cached access array
*
* @return array List of access permissions
* @link http://docs.elgg.org/Access
*/
function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) {
- global $CONFIG;
- //@todo this is probably not needed since caching happens at the DB level.
- static $access_array;
+ global $CONFIG, $init_finished;
+ $cache = _elgg_get_access_cache();
+
+ if ($flush) {
+ $cache->clear();
+ }
if ($user_id == 0) {
$user_id = elgg_get_logged_in_user_guid();
@@ -380,34 +443,78 @@ function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) {
$user_id = (int) $user_id;
$site_id = (int) $site_id;
- if (empty($access_array[$user_id]) || $flush == true) {
+ $hash = $user_id . $site_id . 'get_write_access_array';
+
+ if ($cache[$hash]) {
+ $access_array = $cache[$hash];
+ } else {
+ // @todo is there such a thing as public write access?
+ $access_array = array(
+ ACCESS_PRIVATE => elgg_echo("PRIVATE"),
+ ACCESS_FRIENDS => elgg_echo("access:friends:label"),
+ ACCESS_LOGGED_IN => elgg_echo("LOGGED_IN"),
+ ACCESS_PUBLIC => elgg_echo("PUBLIC")
+ );
+
$query = "SELECT ag.* FROM {$CONFIG->dbprefix}access_collections ag ";
- $query .= " WHERE (ag.site_guid = {$site_id} OR ag.site_guid = 0)";
- $query .= " AND (ag.owner_guid = {$user_id})";
- $query .= " AND ag.id >= 3";
-
- $tmp_access_array = array(
- ACCESS_PRIVATE => elgg_echo("PRIVATE"),
- ACCESS_FRIENDS => elgg_echo("access:friends:label"),
- ACCESS_LOGGED_IN => elgg_echo("LOGGED_IN"),
- ACCESS_PUBLIC => elgg_echo("PUBLIC")
- );
- if ($collections = get_data($query)) {
+ $query .= " WHERE (ag.site_guid = $site_id OR ag.site_guid = 0)";
+ $query .= " AND (ag.owner_guid = $user_id)";
+
+ $collections = get_data($query);
+ if ($collections) {
foreach ($collections as $collection) {
- $tmp_access_array[$collection->id] = $collection->name;
+ $access_array[$collection->id] = $collection->name;
}
}
- $access_array[$user_id] = $tmp_access_array;
+ if ($init_finished) {
+ $cache[$hash] = $access_array;
+ }
+ }
+
+ $options = array(
+ 'user_id' => $user_id,
+ 'site_id' => $site_id
+ );
+ return elgg_trigger_plugin_hook('access:collections:write', 'user',
+ $options, $access_array);
+}
+
+/**
+ * Can the user change this access collection?
+ *
+ * Use the plugin hook of 'access:collections:write', 'user' to change this.
+ * @see get_write_access_array() for details on the hook.
+ *
+ * Respects access control disabling for admin users and {@see elgg_set_ignore_access()}
+ *
+ * @see get_write_access_array()
+ *
+ * @param int $collection_id The collection id
+ * @param mixed $user_guid The user GUID to check for. Defaults to logged in user.
+ * @return bool
+ */
+function can_edit_access_collection($collection_id, $user_guid = null) {
+ if ($user_guid) {
+ $user = get_entity((int) $user_guid);
} else {
- $tmp_access_array = $access_array[$user_id];
+ $user = elgg_get_logged_in_user_entity();
}
- $options = array('user_id' => $user_id, 'site_id' => $site_id);
- $tmp_access_array = elgg_trigger_plugin_hook('access:collections:write', 'user',
- $options, $tmp_access_array);
+ $collection = get_access_collection($collection_id);
+
+ if (!($user instanceof ElggUser) || !$collection) {
+ return false;
+ }
- return $tmp_access_array;
+ $write_access = get_write_access_array($user->getGUID(), 0, true);
+
+ // don't ignore access when checking users.
+ if ($user_guid) {
+ return array_key_exists($collection_id, $write_access);
+ } else {
+ return elgg_get_ignore_access() || array_key_exists($collection_id, $write_access);
+ }
}
/**
@@ -416,6 +523,8 @@ function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) {
* Access colletions allow plugins and users to create granular access
* for entities.
*
+ * Triggers plugin hook 'access:collections:addcollection', 'collection'
+ *
* @internal Access collections are stored in the access_collections table.
* Memberships to collections are in access_collections_membership.
*
@@ -423,7 +532,7 @@ function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) {
* @param int $owner_guid The GUID of the owner (default: currently logged in user).
* @param int $site_guid The GUID of the site (default: current site).
*
- * @return int|false Depending on success (the collection ID if successful).
+ * @return int|false The collection ID if successful and false on failure.
* @link http://docs.elgg.org/Access/Collections
* @see update_access_collection()
* @see delete_access_collection()
@@ -448,7 +557,8 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) {
SET name = '{$name}',
owner_guid = {$owner_guid},
site_guid = {$site_guid}";
- if (!$id = insert_data($q)) {
+ $id = insert_data($q);
+ if (!$id) {
return false;
}
@@ -467,7 +577,7 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) {
* Updates the membership in an access collection.
*
* @warning Expects a full list of all members that should
- * be part o the access collection
+ * be part of the access collection
*
* @note This will run all hooks associated with adding or removing
* members to access collections.
@@ -475,45 +585,36 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) {
* @param int $collection_id The ID of the collection.
* @param array $members Array of member GUIDs
*
- * @return true|false Depending on success
+ * @return bool
* @link http://docs.elgg.org/Access/Collections
* @see add_user_to_access_collection()
* @see remove_user_from_access_collection()
*/
function update_access_collection($collection_id, $members) {
- global $CONFIG;
+ $acl = get_access_collection($collection_id);
- $collection_id = (int) $collection_id;
+ if (!$acl) {
+ return false;
+ }
$members = (is_array($members)) ? $members : array();
- $collections = get_write_access_array();
+ $cur_members = get_members_of_access_collection($collection_id, true);
+ $cur_members = (is_array($cur_members)) ? $cur_members : array();
- if (array_key_exists($collection_id, $collections)) {
- $cur_members = get_members_of_access_collection($collection_id, true);
- $cur_members = (is_array($cur_members)) ? $cur_members : array();
+ $remove_members = array_diff($cur_members, $members);
+ $add_members = array_diff($members, $cur_members);
- $remove_members = array_diff($cur_members, $members);
- $add_members = array_diff($members, $cur_members);
+ $result = true;
- $params = array(
- 'collection_id' => $collection_id,
- 'members' => $members,
- 'add_members' => $add_members,
- 'remove_members' => $remove_members
- );
-
- foreach ($add_members as $guid) {
- add_user_to_access_collection($guid, $collection_id);
- }
-
- foreach ($remove_members as $guid) {
- remove_user_from_access_collection($guid, $collection_id);
- }
+ foreach ($add_members as $guid) {
+ $result = $result && add_user_to_access_collection($guid, $collection_id);
+ }
- return true;
+ foreach ($remove_members as $guid) {
+ $result = $result && remove_user_from_access_collection($guid, $collection_id);
}
- return false;
+ return $result;
}
/**
@@ -527,27 +628,25 @@ function update_access_collection($collection_id, $members) {
* @see update_access_collection()
*/
function delete_access_collection($collection_id) {
+ global $CONFIG;
+
$collection_id = (int) $collection_id;
- $collections = get_write_access_array(null, null, TRUE);
$params = array('collection_id' => $collection_id);
if (!elgg_trigger_plugin_hook('access:collections:deletecollection', 'collection', $params, true)) {
return false;
}
- if (array_key_exists($collection_id, $collections)) {
- global $CONFIG;
- $query = "delete from {$CONFIG->dbprefix}access_collection_membership"
- . " where access_collection_id = {$collection_id}";
- delete_data($query);
+ // Deleting membership doesn't affect result of deleting ACL.
+ $q = "DELETE FROM {$CONFIG->dbprefix}access_collection_membership
+ WHERE access_collection_id = {$collection_id}";
+ delete_data($q);
- $query = "delete from {$CONFIG->dbprefix}access_collections where id = {$collection_id}";
- delete_data($query);
- return true;
- } else {
- return false;
- }
+ $q = "DELETE FROM {$CONFIG->dbprefix}access_collections
+ WHERE id = {$collection_id}";
+ $result = delete_data($q);
+ return (bool)$result;
}
/**
@@ -556,6 +655,8 @@ function delete_access_collection($collection_id) {
* @note This doesn't return the members of an access collection,
* just the database row of the actual collection.
*
+ * @see get_members_of_access_collection()
+ *
* @param int $collection_id The collection ID
*
* @return object|false
@@ -573,101 +674,88 @@ function get_access_collection($collection_id) {
/**
* Adds a user to an access collection.
*
- * Emits the access:collections:add_user, collection plugin hook.
+ * Triggers the 'access:collections:add_user', 'collection' plugin hook.
*
* @param int $user_guid The GUID of the user to add
* @param int $collection_id The ID of the collection to add them to
*
- * @return true|false Depending on success
- * @link http://docs.elgg.org/Access/Collections
+ * @return bool
* @see update_access_collection()
* @see remove_user_from_access_collection()
+ * @link http://docs.elgg.org/Access/Collections
*/
function add_user_to_access_collection($user_guid, $collection_id) {
+ global $CONFIG;
+
$collection_id = (int) $collection_id;
$user_guid = (int) $user_guid;
- $collections = get_write_access_array();
+ $user = get_user($user_guid);
- if (!($collection = get_access_collection($collection_id))) {
- return false;
- }
+ $collection = get_access_collection($collection_id);
- $user = get_user($user_guid);
- if (!$user) {
+ if (!($user instanceof Elgguser) || !$collection) {
return false;
}
- // to add someone to a collection, the user must be a member of the collection or
- // no one must own it
- if ((array_key_exists($collection_id, $collections) || $collection->owner_guid == 0)) {
- $result = true;
- } else {
- $result = false;
- }
-
$params = array(
'collection_id' => $collection_id,
- 'collection' => $collection,
'user_guid' => $user_guid
);
- $result = elgg_trigger_plugin_hook('access:collections:add_user', 'collection', $params, $result);
+ $result = elgg_trigger_plugin_hook('access:collections:add_user', 'collection', $params, true);
if ($result == false) {
return false;
}
- try {
- global $CONFIG;
- $query = "insert into {$CONFIG->dbprefix}access_collection_membership"
- . " set access_collection_id = {$collection_id}, user_guid = {$user_guid}";
- insert_data($query);
- } catch (DatabaseException $e) {
- // nothing.
- return false;
- }
+ // if someone tries to insert the same data twice, we do a no-op on duplicate key
+ $q = "INSERT INTO {$CONFIG->dbprefix}access_collection_membership
+ SET access_collection_id = $collection_id, user_guid = $user_guid
+ ON DUPLICATE KEY UPDATE user_guid = user_guid";
+ $result = insert_data($q);
- return true;
+ return $result !== false;
}
/**
* Removes a user from an access collection.
*
- * Emits the access:collections:remove_user, collection plugin hook.
+ * Triggers the 'access:collections:remove_user', 'collection' plugin hook.
*
* @param int $user_guid The user GUID
* @param int $collection_id The access collection ID
*
- * @return true|false Depending on success
+ * @return bool
+ * @see update_access_collection()
+ * @see remove_user_from_access_collection()
+ * @link http://docs.elgg.org/Access/Collections
*/
function remove_user_from_access_collection($user_guid, $collection_id) {
+ global $CONFIG;
+
$collection_id = (int) $collection_id;
$user_guid = (int) $user_guid;
- $collections = get_write_access_array();
- $user = $user = get_user($user_guid);
+ $user = get_user($user_guid);
+
+ $collection = get_access_collection($collection_id);
- if (!($collection = get_access_collection($collection_id))) {
+ if (!($user instanceof Elgguser) || !$collection) {
return false;
}
- if ((array_key_exists($collection_id, $collections) || $collection->owner_guid == 0) && $user) {
- global $CONFIG;
- $params = array(
- 'collection_id' => $collection_id,
- 'user_guid' => $user_guid
- );
-
- if (!elgg_trigger_plugin_hook('access:collections:remove_user', 'collection', $params, true)) {
- return false;
- }
-
- delete_data("delete from {$CONFIG->dbprefix}access_collection_membership "
- . "where access_collection_id = {$collection_id} and user_guid = {$user_guid}");
-
- return true;
+ $params = array(
+ 'collection_id' => $collection_id,
+ 'user_guid' => $user_guid
+ );
+ if (!elgg_trigger_plugin_hook('access:collections:remove_user', 'collection', $params, true)) {
+ return false;
}
- return false;
+ $q = "DELETE FROM {$CONFIG->dbprefix}access_collection_membership
+ WHERE access_collection_id = {$collection_id}
+ AND user_guid = {$user_guid}";
+
+ return (bool)delete_data($q);
}
/**
@@ -735,32 +823,13 @@ function get_members_of_access_collection($collection, $idonly = FALSE) {
}
/**
- * Displays a user's access collections, using the core/friends/collections view
- *
- * @param int $owner_guid The GUID of the owning user
- *
- * @return string A formatted rendition of the collections
- * @todo Move to the friends/collection.php page.
- */
-function elgg_view_access_collections($owner_guid) {
- if ($collections = get_user_access_collections($owner_guid)) {
- foreach ($collections as $key => $collection) {
- $collections[$key]->members = get_members_of_access_collection($collection->id, true);
- $collections[$key]->entities = get_user_friends($owner_guid, "", 9999);
- }
- }
-
- return elgg_view('core/friends/collections', array('collections' => $collections));
-}
-
-/**
* Return entities based upon access id.
*
- * @param array $options Any options accepted by {@link elgg_get_entities()} and:
+ * @param array $options Any options accepted by {@link elgg_get_entities()} and
* access_id => int The access ID of the entity.
*
* @see elgg_get_entities()
- * @return array
+ * @return mixed If count, int. If not count, array. false on errors.
* @since 1.7.0
*/
function elgg_get_entities_from_access_id(array $options = array()) {
@@ -793,7 +862,7 @@ function elgg_get_entities_from_access_id(array $options = array()) {
* @see elgg_list_entities()
* @see elgg_get_entities_from_access_id()
*
- * @return str
+ * @return string
*/
function elgg_list_entities_from_access_id(array $options = array()) {
return elgg_list_entities($options, 'elgg_get_entities_from_access_id');
@@ -805,28 +874,25 @@ function elgg_list_entities_from_access_id(array $options = array()) {
*
* @warning This function probably doesn't work how it's meant to.
*
- * @param int $entity_accessid The entity's access id
+ * @param int $entity_access_id The entity's access id
*
- * @return string e.g. Public, Private etc
+ * @return string 'Public', 'Private', etc.
* @since 1.7.0
* @todo I think this probably wants get_access_array() instead of get_write_access_array(),
* but those two functions return different types of arrays.
*/
-function get_readable_access_level($entity_accessid) {
- $access = (int) $entity_accessid;
+function get_readable_access_level($entity_access_id) {
+ $access = (int) $entity_access_id;
//get the access level for object in readable string
$options = get_write_access_array();
- //@todo Really? Use array_key_exists()
- foreach ($options as $key => $option) {
- if ($key == $access) {
- $entity_acl = htmlentities($option, ENT_QUOTES, 'UTF-8');
- return $entity_acl;
- break;
- }
+ if (array_key_exists($access, $options)) {
+ return $options[$access];
}
- return false;
+
+ // return 'Limited' if the user does not have access to the access collection
+ return elgg_echo('access:limited:label');
}
/**
@@ -835,13 +901,15 @@ function get_readable_access_level($entity_accessid) {
* The access system will not return entities in any getter
* functions if the user doesn't have access.
*
- * @internal For performance reasons this is done at the database level.
+ * @internal For performance reasons this is done at the database access clause level.
*
* @tip Use this to access entities in automated scripts
* when no user is logged in.
*
- * @warning This will not show disabled entities. Use {@link $ENTITY_SHOW_HIDDEN_OVERRIDE}
- * for that.
+ * @note This clears the access cache.
+ *
+ * @warning This will not show disabled entities.
+ * Use {@link access_show_hidden_entities()} to access disabled entities.
*
* @param bool $ignore If true, disables all access checks.
*
@@ -851,6 +919,8 @@ function get_readable_access_level($entity_accessid) {
* @see elgg_get_ignore_access()
*/
function elgg_set_ignore_access($ignore = true) {
+ $cache = _elgg_get_access_cache();
+ $cache->clear();
$elgg_access = elgg_get_access_object();
return $elgg_access->setIgnoreAccess($ignore);
}
@@ -868,17 +938,20 @@ function elgg_get_ignore_access() {
}
/**
- * Decides if the access system is being ignored.
+ * Decides if the access system should be ignored for a user.
*
- * The access system can be ignored if 1) an admin user is logged in
- * or 2) {@link elgg_set_ignore_access()} was called with true.
+ * Returns true (meaning ignore access) if either of these 2 conditions are true:
+ * 1) an admin user guid is passed to this function.
+ * 2) {@link elgg_get_ignore_access()} returns true.
*
- * @param mixed $user_guid The user to check against. Defaults to logged in.
+ * @see elgg_set_ignore_access()
+ *
+ * @param int $user_guid The user to check against.
*
* @return bool
* @since 1.7.0
*/
-function elgg_check_access_overrides($user_guid = null) {
+function elgg_check_access_overrides($user_guid = 0) {
if (!$user_guid || $user_guid <= 0) {
$is_admin = false;
} else {
@@ -891,6 +964,7 @@ function elgg_check_access_overrides($user_guid = null) {
/**
* Returns the ElggAccess object.
*
+ * // @todo comment is incomplete
* This is used to
*
* @return ElggAccess
@@ -912,7 +986,8 @@ function elgg_get_access_object() {
*
* @global bool $init_finished
* @access private
- * @todo investigate why this is needed
+ * @todo This is required to tell the access system to start caching because
+ * calls are made while in ignore access mode and before the user is logged in.
*/
$init_finished = false;
@@ -930,17 +1005,35 @@ function access_init() {
}
/**
- * Check if the access system should be overridden.
+ * Overrides the access system if appropriate.
*
* Allows admin users and calls after {@link elgg_set_ignore_access} to
- * by pass the access system.
+ * bypass the access system.
+ *
+ * Registered for the 'permissions_check', 'all' and the
+ * 'container_permissions_check', 'all' plugin hooks.
+ *
+ * Returns true to override the access system or null if no change is needed.
*
+ * @param string $hook
+ * @param string $type
+ * @param bool $value
+ * @param array $params
* @return true|null
- * @since 1.7.0
- * @elgg_event_handler permissions_check all
+ * @access private
*/
-function elgg_override_permissions_hook() {
- $user_guid = elgg_get_logged_in_user_guid();
+function elgg_override_permissions($hook, $type, $value, $params) {
+ $user = elgg_extract('user', $params);
+ if ($user) {
+ $user_guid = $user->getGUID();
+ } else {
+ $user_guid = elgg_get_logged_in_user_guid();
+ }
+
+ // don't do this so ignore access still works with no one logged in
+ //if (!$user instanceof ElggUser) {
+ // return false;
+ //}
// check for admin
if ($user_guid && elgg_is_admin_user($user_guid)) {
@@ -956,9 +1049,30 @@ function elgg_override_permissions_hook() {
return NULL;
}
-// This function will let us know when 'init' has finished
-elgg_register_event_handler('init', 'system', 'access_init', 9999);
+/**
+ * Runs unit tests for the entities object.
+ *
+ * @param string $hook
+ * @param string $type
+ * @param array $value
+ * @param array $params
+ * @return array
+ *
+ * @access private
+ */
+function access_test($hook, $type, $value, $params) {
+ global $CONFIG;
+
+ $value[] = $CONFIG->path . 'engine/tests/api/access_collections.php';
+ return $value;
+}
+
+// Tell the access functions the system has booted, plugins are loaded,
+// and the user is logged in so it can start caching
+elgg_register_event_handler('ready', 'system', 'access_init');
// For overrided permissions
-elgg_register_plugin_hook_handler('permissions_check', 'all', 'elgg_override_permissions_hook');
-elgg_register_plugin_hook_handler('container_permissions_check', 'all', 'elgg_override_permissions_hook');
+elgg_register_plugin_hook_handler('permissions_check', 'all', 'elgg_override_permissions');
+elgg_register_plugin_hook_handler('container_permissions_check', 'all', 'elgg_override_permissions');
+
+elgg_register_plugin_hook_handler('unit_test', 'system', 'access_test'); \ No newline at end of file
diff --git a/engine/lib/actions.php b/engine/lib/actions.php
index 407b99f87..8047914ac 100644
--- a/engine/lib/actions.php
+++ b/engine/lib/actions.php
@@ -2,21 +2,23 @@
/**
* Elgg Actions
*
- * Actions are the primary controllers (The C in MVC) in Elgg. They are
- * registered by {@link register_elgg_action()} and are called either by URL
- * http://elggsite.org/action/action_name or {@link action($action_name}. For
- * URLs, a rewrite rule in .htaccess passes the action name to
- * engine/handlers/action_handler.php, which dispatches the action.
+ * Actions are one of the primary controllers (The C in MVC) in Elgg. They are
+ * registered by {@link register_elgg_action()} and are called by URL
+ * http://elggsite.org/action/action_name. For URLs, a rewrite rule in
+ * .htaccess passes the action name to engine/handlers/action_handler.php,
+ * which dispatches the request for the action.
*
- * An action name should be registered to exactly one file in the system, usually under
- * the actions/ directory.
+ * An action name must be registered to a file in the system. Core actions are
+ * found in /actions/ and plugin actions are usually under /mod/<plugin>/actions/.
+ * It is recommended that actions be namespaced to avoid collisions.
*
* All actions require security tokens. Using the {@elgg_view input/form} view
- * will automatically add tokens as hidden inputs. To manually add hidden inputs,
- * use the {@elgg_view input/securitytoken} view.
+ * will automatically add tokens as hidden inputs as will the elgg_view_form()
+ * function. To manually add hidden inputs, use the {@elgg_view input/securitytoken} view.
*
* To include security tokens for actions called via GET, use
- * {@link elgg_add_security_tokens_to_url()}.
+ * {@link elgg_add_security_tokens_to_url()} or specify is_action as true when
+ * using {@lgg_view output/url}.
*
* Action tokens can be manually generated by using {@link generate_action_token()}.
*
@@ -31,30 +33,30 @@
*/
/**
-* Perform an action.
-*
-* This function executes the action with name $action as
-* registered by {@link elgg_register_action()}.
-*
-* The plugin hook action, $action_name will be emitted before
-* the action is executed. If a handler returns false, it will
-* prevent the action from being called.
-*
-* @note If an action isn't registered in the system or is registered
-* to an unavailable file the user will be forwarded to the site front
-* page and an error will be emitted via {@link register_error()}.
-*
-* @warning All actions require {@link http://docs.elgg.org/Actions/Tokens Action Tokens}.
-* @warning Most plugin shouldn't call this manually.
-*
-* @param string $action The requested action
-* @param string $forwarder Optionally, the location to forward to
-*
-* @link http://docs.elgg.org/Actions
-* @see elgg_register_action()
-*
-* @return void
-*/
+ * Perform an action.
+ *
+ * This function executes the action with name $action as registered
+ * by {@link elgg_register_action()}.
+ *
+ * The plugin hook 'action', $action_name will be triggered before the action
+ * is executed. If a handler returns false, it will prevent the action script
+ * from being called.
+ *
+ * @note If an action isn't registered in the system or is registered
+ * to an unavailable file the user will be forwarded to the site front
+ * page and an error will be emitted via {@link register_error()}.
+ *
+ * @warning All actions require {@link http://docs.elgg.org/Actions/Tokens Action Tokens}.
+ *
+ * @param string $action The requested action
+ * @param string $forwarder Optionally, the location to forward to
+ *
+ * @link http://docs.elgg.org/Actions
+ * @see elgg_register_action()
+ *
+ * @return void
+ * @access private
+ */
function action($action, $forwarder = "") {
global $CONFIG;
@@ -63,65 +65,50 @@ function action($action, $forwarder = "") {
// @todo REMOVE THESE ONCE #1509 IS IN PLACE.
// Allow users to disable plugins without a token in order to
// remove plugins that are incompatible.
- // Login and logout are for convenience.
+ // Logout for convenience.
// file/download (see #2010)
$exceptions = array(
'admin/plugins/disable',
'logout',
- 'login',
'file/download',
);
if (!in_array($action, $exceptions)) {
- // All actions require a token.
- action_gatekeeper();
+ action_gatekeeper($action);
}
$forwarder = str_replace(elgg_get_site_url(), "", $forwarder);
$forwarder = str_replace("http://", "", $forwarder);
$forwarder = str_replace("@", "", $forwarder);
-
if (substr($forwarder, 0, 1) == "/") {
$forwarder = substr($forwarder, 1);
}
- if (isset($CONFIG->actions[$action])) {
- if (elgg_is_admin_logged_in() || ($CONFIG->actions[$action]['access'] !== 'admin')) {
- if (elgg_is_logged_in() || ($CONFIG->actions[$action]['access'] === 'public')) {
-
- // Trigger action event
- // @todo This is only called before the primary action is called.
- $event_result = true;
- $event_result = elgg_trigger_plugin_hook('action', $action, null, $event_result);
-
- // Include action
- // Event_result being false doesn't produce an error
- // since i assume this will be handled in the hook itself.
- // @todo make this better!
- if ($event_result) {
- if (!include($CONFIG->actions[$action]['file'])) {
- register_error(elgg_echo('actionnotfound', array($action)));
- }
- }
- } else {
- register_error(elgg_echo('actionloggedout'));
+ if (!isset($CONFIG->actions[$action])) {
+ register_error(elgg_echo('actionundefined', array($action)));
+ } elseif (!elgg_is_admin_logged_in() && ($CONFIG->actions[$action]['access'] === 'admin')) {
+ register_error(elgg_echo('actionunauthorized'));
+ } elseif (!elgg_is_logged_in() && ($CONFIG->actions[$action]['access'] !== 'public')) {
+ register_error(elgg_echo('actionloggedout'));
+ } else {
+ // Returning falsy doesn't produce an error
+ // We assume this will be handled in the hook itself.
+ if (elgg_trigger_plugin_hook('action', $action, null, true)) {
+ if (!include($CONFIG->actions[$action]['file'])) {
+ register_error(elgg_echo('actionnotfound', array($action)));
}
- } else {
- register_error(elgg_echo('actionunauthorized'));
}
- } else {
- register_error(elgg_echo('actionundefined', array($action)));
}
+ $forwarder = empty($forwarder) ? REFERER : $forwarder;
forward($forwarder);
}
/**
* Registers an action.
*
- * Actions are registered to a single file in the system and are executed
- * either by the URL http://elggsite.org/action/action_name or by calling
- * {@link action()}.
+ * Actions are registered to a script in the system and are executed
+ * either by the URL http://elggsite.org/action/action_name/.
*
* $filename must be the full path of the file to register, or a path relative
* to the core actions/ dir.
@@ -133,8 +120,7 @@ function action($action, $forwarder = "") {
*
* @tip Put action files under the actions/<plugin_name> directory of your plugin.
*
- * @tip You don't need to include engine/start.php, call {@link gatekeeper()},
- * or call {@link admin_gatekeeper()}.
+ * @tip You don't need to include engine/start.php in your action files.
*
* @internal Actions are saved in $CONFIG->actions as an array in the form:
* <code>
@@ -147,12 +133,13 @@ function action($action, $forwarder = "") {
* @param string $action The name of the action (eg "register", "account/settings/save")
* @param string $filename Optionally, the filename where this action is located. If not specified,
* will assume the action is in elgg/actions/<action>.php
- * @param string $access Who is allowed to execute this action: admin, public, or logged_in.
+ * @param string $access Who is allowed to execute this action: public, logged_in, admin.
+ * (default: logged_in)
*
* @see action()
* @see http://docs.elgg.org/Actions
*
- * @return true
+ * @return bool
*/
function elgg_register_action($action, $filename = "", $access = 'logged_in') {
global $CONFIG;
@@ -182,16 +169,51 @@ function elgg_register_action($action, $filename = "", $access = 'logged_in') {
}
/**
+ * Unregisters an action
+ *
+ * @param string $action Action name
+ * @return bool
+ * @since 1.8.1
+ */
+function elgg_unregister_action($action) {
+ global $CONFIG;
+
+ if (isset($CONFIG->actions[$action])) {
+ unset($CONFIG->actions[$action]);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Is the token timestamp within acceptable range?
+ *
+ * @param int $ts timestamp from the CSRF token
+ *
+ * @return bool
+ */
+function _elgg_validate_token_timestamp($ts) {
+ $action_token_timeout = elgg_get_config('action_token_timeout');
+ // default is 2 hours
+ $timeout = ($action_token_timeout !== null) ? $action_token_timeout : 2;
+
+ $hour = 60 * 60;
+ $timeout = $timeout * $hour;
+ $now = time();
+
+ // Validate time to ensure its not crazy
+ return ($timeout == 0 || ($ts > $now - $timeout) && ($ts < $now + $timeout));
+}
+
+/**
* Validate an action token.
*
- * Calls to actions will automatically validate tokens.
- * If tokens are not present or invalid, the action will be
- * denied and the user will be redirected to the front page.
+ * Calls to actions will automatically validate tokens. If tokens are not
+ * present or invalid, the action will be denied and the user will be redirected.
*
* Plugin authors should never have to manually validate action tokens.
*
- * @access private
- *
* @param bool $visibleerrors Emit {@link register_error()} errors on failure?
* @param mixed $token The token to test against. Default: $_REQUEST['__elgg_token']
* @param mixed $ts The time stamp to test against. Default: $_REQUEST['__elgg_ts']
@@ -199,10 +221,9 @@ function elgg_register_action($action, $filename = "", $access = 'logged_in') {
* @return bool
* @see generate_action_token()
* @link http://docs.elgg.org/Actions/Tokens
+ * @access private
*/
function validate_action_token($visibleerrors = TRUE, $token = NULL, $ts = NULL) {
- global $CONFIG;
-
if (!$token) {
$token = get_input('__elgg_token');
}
@@ -211,29 +232,18 @@ function validate_action_token($visibleerrors = TRUE, $token = NULL, $ts = NULL)
$ts = get_input('__elgg_ts');
}
- if (!isset($CONFIG->action_token_timeout)) {
- // default to 2 hours
- $timeout = 2;
- } else {
- $timeout = $CONFIG->action_token_timeout;
- }
-
$session_id = session_id();
if (($token) && ($ts) && ($session_id)) {
// generate token, check with input and forward if invalid
- $generated_token = generate_action_token($ts);
+ $required_token = generate_action_token($ts);
// Validate token
- if ($token == $generated_token) {
- $hour = 60 * 60;
- $timeout = $timeout * $hour;
- $now = time();
-
- // Validate time to ensure its not crazy
- if ($timeout == 0 || ($ts > $now - $timeout) && ($ts < $now + $timeout)) {
+ if ($token == $required_token) {
+
+ if (_elgg_validate_token_timestamp($ts)) {
// We have already got this far, so unless anything
- // else says something to the contry we assume we're ok
+ // else says something to the contrary we assume we're ok
$returnval = true;
$returnval = elgg_trigger_plugin_hook('action_gatekeeper:permissions:check', 'all', array(
@@ -247,33 +257,75 @@ function validate_action_token($visibleerrors = TRUE, $token = NULL, $ts = NULL)
register_error(elgg_echo('actiongatekeeper:pluginprevents'));
}
} else if ($visibleerrors) {
- register_error(elgg_echo('actiongatekeeper:timeerror'));
+ // this is necessary because of #5133
+ if (elgg_is_xhr()) {
+ register_error(elgg_echo('js:security:token_refresh_failed', array(elgg_get_site_url())));
+ } else {
+ register_error(elgg_echo('actiongatekeeper:timeerror'));
+ }
}
} else if ($visibleerrors) {
- register_error(elgg_echo('actiongatekeeper:tokeninvalid'));
+ // this is necessary because of #5133
+ if (elgg_is_xhr()) {
+ register_error(elgg_echo('js:security:token_refresh_failed', array(elgg_get_site_url())));
+ } else {
+ register_error(elgg_echo('actiongatekeeper:tokeninvalid'));
+ }
+ }
+ } else {
+ if (! empty($_SERVER['CONTENT_LENGTH']) && empty($_POST)) {
+ // The size of $_POST or uploaded file has exceed the size limit
+ $error_msg = elgg_trigger_plugin_hook('action_gatekeeper:upload_exceeded_msg', 'all', array(
+ 'post_size' => $_SERVER['CONTENT_LENGTH'],
+ 'visible_errors' => $visibleerrors,
+ ), elgg_echo('actiongatekeeper:uploadexceeded'));
+ } else {
+ $error_msg = elgg_echo('actiongatekeeper:missingfields');
+ }
+ if ($visibleerrors) {
+ register_error($error_msg);
}
- } else if ($visibleerrors) {
- register_error(elgg_echo('actiongatekeeper:missingfields'));
}
return FALSE;
}
/**
-* Validates the presence of action tokens.
-*
-* This function is called for all actions. If action tokens are missing,
-* the user will be forwarded to the site front page and an error emitted.
-*
-* This function verifies form input for security features (like a generated token), and forwards
-* the page if they are invalid.
-*
-* @access private
-* @return mixed True if valid, or redirects to front page and exists.
-*/
-function action_gatekeeper() {
- if (validate_action_token()) {
- return TRUE;
+ * Validates the presence of action tokens.
+ *
+ * This function is called for all actions. If action tokens are missing,
+ * the user will be forwarded to the site front page and an error emitted.
+ *
+ * This function verifies form input for security features (like a generated token),
+ * and forwards if they are invalid.
+ *
+ * @param string $action The action being performed
+ *
+ * @return mixed True if valid or redirects.
+ * @access private
+ */
+function action_gatekeeper($action) {
+ if ($action === 'login') {
+ if (validate_action_token(false)) {
+ return true;
+ }
+
+ $token = get_input('__elgg_token');
+ $ts = (int)get_input('__elgg_ts');
+ if ($token && _elgg_validate_token_timestamp($ts)) {
+ // The tokens are present and the time looks valid: this is probably a mismatch due to the
+ // login form being on a different domain.
+ register_error(elgg_echo('actiongatekeeper:crosssitelogin'));
+
+
+ forward('login', 'csrf');
+ }
+
+ // let the validator send an appropriate msg
+ validate_action_token();
+
+ } elseif (validate_action_token()) {
+ return true;
}
forward(REFERER, 'csrf');
@@ -296,6 +348,7 @@ function action_gatekeeper() {
* @example actions/manual_tokens.php
*
* @return string|false
+ * @access private
*/
function generate_action_token($timestamp) {
$site_secret = get_site_secret();
@@ -311,16 +364,19 @@ function generate_action_token($timestamp) {
}
/**
- * Initialise the site secret hash.
+ * Initialise the site secret (32 bytes: "z" to indicate format + 186-bit key in Base64 URL).
*
* Used during installation and saves as a datalist.
*
+ * Note: Old secrets were hex encoded.
+ *
* @return mixed The site secret hash or false
* @access private
* @todo Move to better file.
*/
function init_site_secret() {
- $secret = md5(rand() . microtime());
+ $secret = 'z' . ElggCrypto::getRandomString(31);
+
if (datalist_set('__site_secret__', $secret)) {
return $secret;
}
@@ -347,7 +403,27 @@ function get_site_secret() {
}
/**
- * Check if an action is registered and its file exists.
+ * Get the strength of the site secret
+ *
+ * @return string "strong", "moderate", or "weak"
+ * @access private
+ */
+function _elgg_get_site_secret_strength() {
+ $secret = get_site_secret();
+ if ($secret[0] !== 'z') {
+ $rand_max = getrandmax();
+ if ($rand_max < pow(2, 16)) {
+ return 'weak';
+ }
+ if ($rand_max < pow(2, 32)) {
+ return 'moderate';
+ }
+ }
+ return 'strong';
+}
+
+/**
+ * Check if an action is registered and its script exists.
*
* @param string $action Action name
*
@@ -361,25 +437,15 @@ function elgg_action_exists($action) {
}
/**
- * Initialize some ajaxy actions features
- */
-function actions_init() {
- elgg_register_action('security/refreshtoken', '', 'public');
-
- elgg_register_simplecache_view('js/languages/en');
-
- elgg_register_plugin_hook_handler('action', 'all', 'ajax_action_hook');
- elgg_register_plugin_hook_handler('forward', 'all', 'ajax_forward_hook');
-}
-
-/**
* Checks whether the request was requested via ajax
*
* @return bool whether page was requested via ajax
+ * @since 1.8.0
*/
function elgg_is_xhr() {
return isset($_SERVER['HTTP_X_REQUESTED_WITH'])
- && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
+ && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest' ||
+ get_input('X-Requested-With') === 'XMLHttpRequest';
}
/**
@@ -403,10 +469,21 @@ function elgg_is_xhr() {
* @param string $type
* @param string $reason
* @param array $params
- *
+ * @return void
+ * @access private
*/
function ajax_forward_hook($hook, $type, $reason, $params) {
if (elgg_is_xhr()) {
+ // always pass the full structure to avoid boilerplate JS code.
+ $params = array(
+ 'output' => '',
+ 'status' => 0,
+ 'system_messages' => array(
+ 'error' => array(),
+ 'success' => array()
+ )
+ );
+
//grab any data echo'd in the action
$output = ob_get_clean();
@@ -419,15 +496,27 @@ function ajax_forward_hook($hook, $type, $reason, $params) {
}
//Grab any system messages so we can inject them via ajax too
- $params['system_messages'] = system_messages(NULL, "");
+ $system_messages = system_messages(NULL, "");
+
+ if (isset($system_messages['success'])) {
+ $params['system_messages']['success'] = $system_messages['success'];
+ }
- if (isset($params['system_messages']['error'])) {
+ if (isset($system_messages['error'])) {
+ $params['system_messages']['error'] = $system_messages['error'];
$params['status'] = -1;
+ }
+
+ // Check the requester can accept JSON responses, if not fall back to
+ // returning JSON in a plain-text response. Some libraries request
+ // JSON in an invisible iframe which they then read from the iframe,
+ // however some browsers will not accept the JSON MIME type.
+ if (stripos($_SERVER['HTTP_ACCEPT'], 'application/json') === FALSE) {
+ header("Content-type: text/plain");
} else {
- $params['status'] = 0;
+ header("Content-type: application/json");
}
- header("Content-type: application/json");
echo json_encode($params);
exit;
}
@@ -435,6 +524,8 @@ function ajax_forward_hook($hook, $type, $reason, $params) {
/**
* Buffer all output echo'd directly in the action for inclusion in the returned JSON.
+ * @return void
+ * @access private
*/
function ajax_action_hook() {
if (elgg_is_xhr()) {
@@ -442,4 +533,17 @@ function ajax_action_hook() {
}
}
+/**
+ * Initialize some ajaxy actions features
+ * @access private
+ */
+function actions_init() {
+ elgg_register_action('security/refreshtoken', '', 'public');
+
+ elgg_register_simplecache_view('js/languages/en');
+
+ elgg_register_plugin_hook_handler('action', 'all', 'ajax_action_hook');
+ elgg_register_plugin_hook_handler('forward', 'all', 'ajax_forward_hook');
+}
+
elgg_register_event_handler('init', 'system', 'actions_init');
diff --git a/engine/lib/admin.php b/engine/lib/admin.php
index a9a0382cc..f36f29668 100644
--- a/engine/lib/admin.php
+++ b/engine/lib/admin.php
@@ -79,6 +79,10 @@ function elgg_add_admin_notice($id, $message) {
if (elgg_admin_notice_exists($id)) {
return false;
}
+
+ // need to handle when no one is logged in
+ $old_ia = elgg_set_ignore_access(true);
+
$admin_notice = new ElggObject();
$admin_notice->subtype = 'admin_notice';
// admins can see ACCESS_PRIVATE but no one else can.
@@ -86,13 +90,16 @@ function elgg_add_admin_notice($id, $message) {
$admin_notice->admin_notice_id = $id;
$admin_notice->description = $message;
- return $admin_notice->save();
+ $result = $admin_notice->save();
+
+ elgg_set_ignore_access($old_ia);
+
+ return (bool)$result;
}
- return FALSE;
+ return false;
}
-
/**
* Remove an admin notice by ID.
*
@@ -127,11 +134,11 @@ function elgg_delete_admin_notice($id) {
}
/**
- * List all admin messages.
+ * Get admin notices. An admin must be logged in since the notices are private.
*
* @param int $limit Limit
*
- * @return array List of admin notices
+ * @return array Array of admin notices
* @since 1.8.0
*/
function elgg_get_admin_notices($limit = 10) {
@@ -151,11 +158,13 @@ function elgg_get_admin_notices($limit = 10) {
* @since 1.8.0
*/
function elgg_admin_notice_exists($id) {
+ $old_ia = elgg_set_ignore_access(true);
$notice = elgg_get_entities_from_metadata(array(
'type' => 'object',
'subtype' => 'admin_notice',
'metadata_name_value_pair' => array('name' => 'admin_notice_id', 'value' => $id)
));
+ elgg_set_ignore_access($old_ia);
return ($notice) ? TRUE : FALSE;
}
@@ -172,10 +181,10 @@ function elgg_admin_notice_exists($id) {
*
* This function handles registering the parent if it has not been registered.
*
- * @param string $section The menu section to add to
- * @param string $menu_id The unique ID of section
- * @param string $parent_id If a child section, the parent section id
- * @param int $priority The menu item priority
+ * @param string $section The menu section to add to
+ * @param string $menu_id The unique ID of section
+ * @param string $parent_id If a child section, the parent section id
+ * @param int $priority The menu item priority
*
* @return bool
* @since 1.8.0
@@ -183,7 +192,7 @@ function elgg_admin_notice_exists($id) {
function elgg_register_admin_menu_item($section, $menu_id, $parent_id = NULL, $priority = 100) {
// make sure parent is registered
- if ($parent_id && !elgg_is_menu_item_registered($menu_id, $parent_id)) {
+ if ($parent_id && !elgg_is_menu_item_registered('page', $parent_id)) {
elgg_register_admin_menu_item($section, $parent_id);
}
@@ -211,9 +220,9 @@ function elgg_register_admin_menu_item($section, $menu_id, $parent_id = NULL, $p
}
/**
- * Initialise the admin backend.
- *
+ * Initialize the admin backend.
* @return void
+ * @access private
*/
function admin_init() {
elgg_register_action('admin/user/ban', '', 'admin');
@@ -225,20 +234,25 @@ function admin_init() {
elgg_register_action('admin/site/update_basic', '', 'admin');
elgg_register_action('admin/site/update_advanced', '', 'admin');
+ elgg_register_action('admin/site/flush_cache', '', 'admin');
+ elgg_register_action('admin/site/unlock_upgrade', '', 'admin');
+ elgg_register_action('admin/site/regenerate_secret', '', 'admin');
elgg_register_action('admin/menu/save', '', 'admin');
elgg_register_action('admin/delete_admin_notice', '', 'admin');
- elgg_register_action('admin/plugins/simple_update_states', '', 'admin');
-
elgg_register_action('profile/fields/reset', '', 'admin');
elgg_register_action('profile/fields/add', '', 'admin');
elgg_register_action('profile/fields/edit', '', 'admin');
elgg_register_action('profile/fields/delete', '', 'admin');
elgg_register_action('profile/fields/reorder', '', 'admin');
+ elgg_register_simplecache_view('css/admin');
elgg_register_simplecache_view('js/admin');
+ $url = elgg_get_simplecache_url('js', 'admin');
+ elgg_register_js('elgg.admin', $url);
+ elgg_register_js('jquery.jeditable', 'vendors/jquery/jquery.jeditable.mini.js');
// administer
// dashboard
@@ -253,22 +267,32 @@ function admin_init() {
// statistics
elgg_register_admin_menu_item('administer', 'statistics', null, 20);
elgg_register_admin_menu_item('administer', 'overview', 'statistics');
+ elgg_register_admin_menu_item('administer', 'server', 'statistics');
// users
elgg_register_admin_menu_item('administer', 'users', null, 20);
elgg_register_admin_menu_item('administer', 'online', 'users', 10);
- elgg_register_admin_menu_item('administer', 'newest', 'users', 20);
- elgg_register_admin_menu_item('administer', 'add', 'users', 30);
+ elgg_register_admin_menu_item('administer', 'admins', 'users', 20);
+ elgg_register_admin_menu_item('administer', 'newest', 'users', 30);
+ elgg_register_admin_menu_item('administer', 'add', 'users', 40);
// configure
// plugins
- elgg_register_admin_menu_item('configure', 'plugins', null, 10);
- elgg_register_admin_menu_item('configure', 'simple', 'plugins', 10);
- elgg_register_admin_menu_item('configure', 'advanced', 'plugins', 20);
+ elgg_register_menu_item('page', array(
+ 'name' => 'plugins',
+ 'href' => 'admin/plugins',
+ 'text' => elgg_echo('admin:plugins'),
+ 'context' => 'admin',
+ 'priority' => 75,
+ 'section' => 'configure'
+ ));
// settings
+ elgg_register_admin_menu_item('configure', 'appearance', null, 50);
+ elgg_register_admin_menu_item('configure', 'settings', null, 100);
elgg_register_admin_menu_item('configure', 'basic', 'settings', 10);
elgg_register_admin_menu_item('configure', 'advanced', 'settings', 20);
+ elgg_register_admin_menu_item('configure', 'advanced/site_secret', 'settings', 25);
elgg_register_admin_menu_item('configure', 'menu_items', 'appearance', 30);
elgg_register_admin_menu_item('configure', 'profile_fields', 'appearance', 40);
// default widgets is added via an event handler elgg_default_widgets_init() in widgets.php
@@ -277,6 +301,11 @@ function admin_init() {
// plugin settings are added in elgg_admin_add_plugin_settings_menu() via the admin page handler
// for performance reasons.
+ // we want plugin settings menu items to be sorted alphabetical
+ if (elgg_in_context('admin')) {
+ elgg_register_plugin_hook_handler('prepare', 'menu:page', 'elgg_admin_sort_page_menu');
+ }
+
if (elgg_is_admin_logged_in()) {
elgg_register_menu_item('topbar', array(
'name' => 'administration',
@@ -288,7 +317,7 @@ function admin_init() {
}
// widgets
- $widgets = array('online_users', 'new_users', 'content_stats', 'admin_welcome');
+ $widgets = array('online_users', 'new_users', 'content_stats', 'admin_welcome', 'control_panel');
foreach ($widgets as $widget) {
elgg_register_widget_type(
$widget,
@@ -301,8 +330,9 @@ function admin_init() {
// automatic adding of widgets for admin
elgg_register_event_handler('make_admin', 'user', 'elgg_add_admin_widgets');
- elgg_register_page_handler('admin', 'admin_settings_page_handler');
+ elgg_register_page_handler('admin', 'admin_page_handler');
elgg_register_page_handler('admin_plugin_screenshot', 'admin_plugin_screenshot_page_handler');
+ elgg_register_page_handler('admin_plugin_text_file', 'admin_markdown_page_handler');
}
/**
@@ -313,28 +343,61 @@ function admin_init() {
*
* @return void
* @access private
+ * @since 1.8.0
*/
function elgg_admin_add_plugin_settings_menu() {
$active_plugins = elgg_get_plugins('active');
if (!$active_plugins) {
// nothing added because no items
- return FALSE;
+ return;
}
foreach ($active_plugins as $plugin) {
$plugin_id = $plugin->getID();
- if (elgg_view_exists("settings/$plugin_id/edit")) {
+ $settings_view_old = 'settings/' . $plugin_id . '/edit';
+ $settings_view_new = 'plugins/' . $plugin_id . '/settings';
+ if (elgg_view_exists($settings_view_new) || elgg_view_exists($settings_view_old)) {
elgg_register_menu_item('page', array(
'name' => $plugin_id,
'href' => "admin/plugin_settings/$plugin_id",
- 'text' => $plugin->manifest->getName(),
+ 'text' => $plugin->getManifest()->getName(),
'parent_name' => 'settings',
'context' => 'admin',
'section' => 'configure',
- ));
+ ));
+ }
+ }
+}
+
+/**
+ * Sort the plugin settings menu items
+ *
+ * @param string $hook
+ * @param string $type
+ * @param array $return
+ * @param array $params
+ *
+ * @return void
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_admin_sort_page_menu($hook, $type, $return, $params) {
+ $configure_items = $return['configure'];
+ /* @var ElggMenuItem[] $configure_items */
+ foreach ($configure_items as $menu_item) {
+ if ($menu_item->getName() == 'settings') {
+ $settings = $menu_item;
}
}
+
+ // keep the basic and advanced settings at the top
+ /* @var ElggMenuItem $settings */
+ $children = $settings->getChildren();
+ $site_settings = array_splice($children, 0, 2);
+ usort($children, array('ElggMenuBuilder', 'compareByText'));
+ array_splice($children, 0, 0, $site_settings);
+ $settings->setChildren($children);
}
/**
@@ -366,7 +429,7 @@ function admin_pagesetup() {
elgg_register_menu_item('admin_footer', array(
'name' => 'community_forums',
'text' => elgg_echo('admin:footer:community_forums'),
- 'href' => 'http://community.elgg.org/pg/groups/world/',
+ 'href' => 'http://community.elgg.org/groups/all/',
));
elgg_register_menu_item('admin_footer', array(
@@ -382,20 +445,17 @@ function admin_pagesetup() {
*
* @param array $page Array of pages
*
- * @return void
+ * @return bool
+ * @access private
*/
-function admin_settings_page_handler($page) {
+function admin_page_handler($page) {
admin_gatekeeper();
elgg_admin_add_plugin_settings_menu();
elgg_set_context('admin');
elgg_unregister_css('elgg');
- $url = elgg_get_simplecache_url('js', 'admin');
- elgg_register_js('elgg.admin', $url);
elgg_load_js('elgg.admin');
-
- elgg_register_js('jquery.jeditable', 'vendors/jquery/jquery.jeditable.mini.js');
elgg_load_js('jquery.jeditable');
// default to dashboard
@@ -412,14 +472,18 @@ function admin_settings_page_handler($page) {
$vars = array('page' => $page);
// special page for plugin settings since we create the form for them
- if ($page[0] == 'plugin_settings' && isset($page[1])
- && elgg_view_exists("settings/{$page[1]}/edit")) {
+ if ($page[0] == 'plugin_settings') {
+ if (isset($page[1]) && (elgg_view_exists("settings/{$page[1]}/edit") ||
+ elgg_view_exists("plugins/{$page[1]}/settings"))) {
- $view = 'admin/plugin_settings';
- $plugin = elgg_get_plugin_from_id($page[1]);
- $vars['plugin'] = $plugin;
+ $view = 'admin/plugin_settings';
+ $plugin = elgg_get_plugin_from_id($page[1]);
+ $vars['plugin'] = $plugin;
- $title = elgg_echo("admin:{$page[0]}");
+ $title = elgg_echo("admin:{$page[0]}");
+ } else {
+ forward('', '404');
+ }
} else {
$view = 'admin/' . implode('/', $page);
$title = elgg_echo("admin:{$page[0]}");
@@ -436,6 +500,7 @@ function admin_settings_page_handler($page) {
$body = elgg_view_layout('admin', array('content' => $content, 'title' => $title));
echo elgg_view_page($title, $body, 'admin');
+ return true;
}
/**
@@ -443,10 +508,12 @@ function admin_settings_page_handler($page) {
* admin_plugin_screenshot/<plugin_id>/<size>/<ss_name>.<ext>
*
* @param array $pages The pages array
- * @return true
+ * @return bool
+ * @access private
*/
function admin_plugin_screenshot_page_handler($pages) {
- admin_gatekeeper(); // only admins can use this - security feature
+ // only admins can use this for security
+ admin_gatekeeper();
$plugin_id = elgg_extract(0, $pages);
// only thumbnail or full.
@@ -480,14 +547,90 @@ function admin_plugin_screenshot_page_handler($pages) {
echo file_get_contents($file);
break;
}
+ return true;
+}
+
+/**
+ * Formats and serves out markdown files from plugins.
+ *
+ * URLs in format like admin_plugin_text_file/<plugin_id>/filename.ext
+ *
+ * The only valid files are:
+ * * README.txt
+ * * CHANGES.txt
+ * * INSTALL.txt
+ * * COPYRIGHT.txt
+ * * LICENSE.txt
+ *
+ * @param array $pages
+ * @return bool
+ * @access private
+ */
+function admin_markdown_page_handler($pages) {
+ admin_gatekeeper();
+
+ elgg_set_context('admin');
+
+ elgg_unregister_css('elgg');
+ elgg_load_js('elgg.admin');
+ elgg_load_js('jquery.jeditable');
+ elgg_load_library('elgg:markdown');
+
+ $plugin_id = elgg_extract(0, $pages);
+ $plugin = elgg_get_plugin_from_id($plugin_id);
+ $filename = elgg_extract(1, $pages);
+
+ $error = false;
+ if (!$plugin) {
+ $error = elgg_echo('admin:plugins:markdown:unknown_plugin');
+ $body = elgg_view_layout('admin', array('content' => $error, 'title' => $error));
+ echo elgg_view_page($error, $body, 'admin');
+ return true;
+ }
+
+ $text_files = $plugin->getAvailableTextFiles();
+
+ if (!array_key_exists($filename, $text_files)) {
+ $error = elgg_echo('admin:plugins:markdown:unknown_file');
+ }
+
+ $file = $text_files[$filename];
+ $file_contents = file_get_contents($file);
+
+ if (!$file_contents) {
+ $error = elgg_echo('admin:plugins:markdown:unknown_file');
+ }
+ if ($error) {
+ $title = $error;
+ $body = elgg_view_layout('admin', array('content' => $error, 'title' => $title));
+ echo elgg_view_page($title, $body, 'admin');
+ return true;
+ }
+
+ $title = $plugin->getManifest()->getName() . ": $filename";
+ $text = Markdown($file_contents);
+
+ $body = elgg_view_layout('admin', array(
+ // setting classes here because there's no way to pass classes
+ // to the layout
+ 'content' => '<div class="elgg-markdown">' . $text . '</div>',
+ 'title' => $title
+ ));
+
+ echo elgg_view_page($title, $body, 'admin');
return true;
}
/**
* Adds default admin widgets to the admin dashboard.
*
- * @return void
+ * @param string $event
+ * @param string $type
+ * @param ElggUser $user
+ *
+ * @return null|true
+ * @access private
*/
function elgg_add_admin_widgets($event, $type, $user) {
elgg_set_ignore_access(true);
@@ -499,7 +642,7 @@ function elgg_add_admin_widgets($event, $type, $user) {
// In the form column => array of handlers in order, top to bottom
$adminWidgets = array(
- 1 => array('admin_welcome'),
+ 1 => array('control_panel', 'admin_welcome'),
2 => array('online_users', 'new_users', 'content_stats'),
);
@@ -508,6 +651,7 @@ function elgg_add_admin_widgets($event, $type, $user) {
$guid = elgg_create_widget($user->getGUID(), $handler, 'admin');
if ($guid) {
$widget = get_entity($guid);
+ /* @var ElggWidget $widget */
$widget->move($column, $position);
}
}
diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php
index 1178a079f..5e9b530de 100644
--- a/engine/lib/annotations.php
+++ b/engine/lib/annotations.php
@@ -13,9 +13,11 @@
* @param stdClass $row Db row result object
*
* @return ElggAnnotation
+ * @access private
*/
function row_to_elggannotation($row) {
if (!($row instanceof stdClass)) {
+ // @todo should throw in this case?
return $row;
}
@@ -29,7 +31,7 @@ function row_to_elggannotation($row) {
*
* @param int $id The id of the annotation object being retrieved.
*
- * @return false|ElggAnnotation
+ * @return ElggAnnotation|false
*/
function elgg_get_annotation_from_id($id) {
return elgg_get_metastring_based_object_from_id($id, 'annotations');
@@ -55,14 +57,14 @@ function elgg_delete_annotation_by_id($id) {
* @param int $entity_guid Entity Guid
* @param string $name Name of annotation
* @param string $value Value of annotation
- * @param string $value_type Type of value
- * @param int $owner_guid Owner of annotation
+ * @param string $value_type Type of value (default is auto detection)
+ * @param int $owner_guid Owner of annotation (default is logged in user)
* @param int $access_id Access level of annotation
*
* @return int|bool id on success or false on failure
*/
-function create_annotation($entity_guid, $name, $value, $value_type,
-$owner_guid, $access_id = ACCESS_PRIVATE) {
+function create_annotation($entity_guid, $name, $value, $value_type = '',
+$owner_guid = 0, $access_id = ACCESS_PRIVATE) {
global $CONFIG;
$result = false;
@@ -94,8 +96,6 @@ $owner_guid, $access_id = ACCESS_PRIVATE) {
$entity = get_entity($entity_guid);
if (elgg_trigger_event('annotate', $entity->type, $entity)) {
- system_log($entity, 'annotate');
-
// If ok then add it
$result = insert_data("INSERT into {$CONFIG->dbprefix}annotations
(entity_guid, name_id, value_id, value_type, owner_guid, time_created, access_id) VALUES
@@ -162,13 +162,9 @@ function update_annotation($annotation_id, $name, $value, $value_type, $owner_gu
where id=$annotation_id and $access");
if ($result !== false) {
+ // @todo add plugin hook that sends old and new annotation information before db access
$obj = elgg_get_annotation_from_id($annotation_id);
- if (elgg_trigger_event('update', 'annotation', $obj)) {
- return true;
- } else {
- // @todo add plugin hook that sends old and new annotation information before db access
- elgg_delete_annotation_by_id($annotation_id);
- }
+ elgg_trigger_event('update', 'annotation', $obj);
}
return $result;
@@ -182,26 +178,40 @@ function update_annotation($annotation_id, $name, $value, $value_type, $owner_gu
*
* @param array $options Array in format:
*
- * annotation_names => NULL|ARR Annotation names
- *
- * annotation_values => NULL|ARR Annotation values
- *
- * annotation_ids => NULL|ARR annotation ids
- *
- * annotation_case_sensitive => BOOL Overall Case sensitive
- *
- * annotation_owner_guids => NULL|ARR guids for annotation owners
- *
- * annotation_created_time_lower => INT Lower limit for created time.
- *
- * annotation_created_time_upper => INT Upper limit for created time.
- *
- * annotation_calculation => STR Perform the MySQL function on the annotation values returned.
- *
- * @return mixed
+ * annotation_names => NULL|ARR Annotation names
+ * annotation_values => NULL|ARR Annotation values
+ * annotation_ids => NULL|ARR annotation ids
+ * annotation_case_sensitive => BOOL Overall Case sensitive
+ * annotation_owner_guids => NULL|ARR guids for annotation owners
+ * annotation_created_time_lower => INT Lower limit for created time.
+ * annotation_created_time_upper => INT Upper limit for created time.
+ * annotation_calculation => STR Perform the MySQL function on the annotation values returned.
+ * Do not confuse this "annotation_calculation" option with the
+ * "calculation" option to elgg_get_entities_from_annotation_calculation().
+ * The "annotation_calculation" option causes this function to
+ * return the result of performing a mathematical calculation on
+ * all annotations that match the query instead of ElggAnnotation
+ * objects.
+ * See the docs for elgg_get_entities_from_annotation_calculation()
+ * for the proper use of the "calculation" option.
+ *
+ *
+ * @return ElggAnnotation[]|mixed
* @since 1.8.0
*/
function elgg_get_annotations(array $options = array()) {
+
+ // @todo remove support for count shortcut - see #4393
+ if (isset($options['__egefac']) && $options['__egefac']) {
+ unset($options['__egefac']);
+ } else {
+ // support shortcut of 'count' => true for 'annotation_calculation' => 'count'
+ if (isset($options['count']) && $options['count']) {
+ $options['annotation_calculation'] = 'count';
+ unset($options['count']);
+ }
+ }
+
$options['metastring_type'] = 'annotations';
return elgg_get_metastring_based_objects($options);
}
@@ -210,10 +220,12 @@ function elgg_get_annotations(array $options = array()) {
* Deletes annotations based on $options.
*
* @warning Unlike elgg_get_annotations() this will not accept an empty options array!
+ * This requires at least one constraint: annotation_owner_guid(s),
+ * annotation_name(s), annotation_value(s), or guid(s) must be set.
*
* @param array $options An options array. {@See elgg_get_annotations()}
- * @return mixed
- * @since 1.8
+ * @return bool|null true on success, false on failure, null if no annotations to delete.
+ * @since 1.8.0
*/
function elgg_delete_annotations(array $options) {
if (!elgg_is_valid_options_for_batch_operation($options, 'annotations')) {
@@ -221,7 +233,7 @@ function elgg_delete_annotations(array $options) {
}
$options['metastring_type'] = 'annotations';
- return elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback');
+ return elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback', false);
}
/**
@@ -230,16 +242,20 @@ function elgg_delete_annotations(array $options) {
* @warning Unlike elgg_get_annotations() this will not accept an empty options array!
*
* @param array $options An options array. {@See elgg_get_annotations()}
- * @return mixed
- * @since 1.8
+ * @return bool|null true on success, false on failure, null if no annotations disabled.
+ * @since 1.8.0
*/
function elgg_disable_annotations(array $options) {
if (!elgg_is_valid_options_for_batch_operation($options, 'annotations')) {
return false;
}
+
+ // if we can see hidden (disabled) we need to use the offset
+ // otherwise we risk an infinite loop if there are more than 50
+ $inc_offset = access_get_show_hidden_status();
- $options['metastrings_type'] = 'annotations';
- return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback');
+ $options['metastring_type'] = 'annotations';
+ return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', $inc_offset);
}
/**
@@ -247,9 +263,12 @@ function elgg_disable_annotations(array $options) {
*
* @warning Unlike elgg_get_annotations() this will not accept an empty options array!
*
+ * @warning In order to enable annotations, you must first use
+ * {@link access_show_hidden_entities()}.
+ *
* @param array $options An options array. {@See elgg_get_annotations()}
- * @return mixed
- * @since 1.8
+ * @return bool|null true on success, false on failure, null if no metadata enabled.
+ * @since 1.8.0
*/
function elgg_enable_annotations(array $options) {
if (!$options || !is_array($options)) {
@@ -267,7 +286,7 @@ function elgg_enable_annotations(array $options) {
* {@see elgg_get_annotations()} and {@see elgg_list_entities()}.
*
* @return string The list of entities
- * @since 1.8
+ * @since 1.8.0
*/
function elgg_list_annotations($options) {
$defaults = array(
@@ -285,14 +304,12 @@ function elgg_list_annotations($options) {
*/
/**
- * Returns entities based upon annotations. Accepts the same values as
- * elgg_get_entities_from_metadata() but uses the annotations table.
+ * Returns entities based upon annotations. Also accepts all options available
+ * to elgg_get_entities() and elgg_get_entities_from_metadata().
*
- * NB: Entity creation time is selected as max_time. To sort based upon
+ * Entity creation time is selected as maxtime. To sort based upon
* this, pass 'order_by' => 'maxtime asc' || 'maxtime desc'
*
- * time_created in this case will be the time the annotation was created.
- *
* @see elgg_get_entities
* @see elgg_get_entities_from_metadata
*
@@ -319,9 +336,7 @@ function elgg_list_annotations($options) {
*
* annotation_owner_guids => NULL|ARR guids for annotaiton owners
*
- * annotation_ids => NULL|ARR Annotation IDs
- *
- * @return array
+ * @return mixed If count, int. If not count, array. false on errors.
* @since 1.7.0
*/
function elgg_get_entities_from_annotations(array $options = array()) {
@@ -339,8 +354,6 @@ function elgg_get_entities_from_annotations(array $options = array()) {
'annotation_owner_guids' => ELGG_ENTITIES_ANY_VALUE,
- 'annotation_ids' => ELGG_ENTITIES_ANY_VALUE,
-
'order_by' => 'maxtime desc',
'group_by' => 'a.entity_guid'
);
@@ -348,12 +361,13 @@ function elgg_get_entities_from_annotations(array $options = array()) {
$options = array_merge($defaults, $options);
$singulars = array('annotation_name', 'annotation_value',
- 'annotation_name_value_pair', 'annotation_owner_guid', 'annotation_id');
+ 'annotation_name_value_pair', 'annotation_owner_guid');
$options = elgg_normalise_plural_options_array($options, $singulars);
+ $options = elgg_entities_get_metastrings_options('annotation', $options);
- if (!$options = elgg_entities_get_metastrings_options('annotation', $options)) {
- return FALSE;
+ if (!$options) {
+ return false;
}
// special sorting for annotations
@@ -379,28 +393,38 @@ function elgg_get_entities_from_annotations(array $options = array()) {
* @see elgg_get_entities_from_annotations()
* @see elgg_list_entities()
*
- * @return str
+ * @return string
*/
function elgg_list_entities_from_annotations($options = array()) {
return elgg_list_entities($options, 'elgg_get_entities_from_annotations');
}
/**
- * Get entities ordered by a mathematical calculation
+ * Get entities ordered by a mathematical calculation on annotation values
*
* @param array $options An options array:
- * 'calculation' => The calculation to use. Must be a valid MySQL function.
- * Defaults to sum. Result selected as 'calculated'.
- * 'order_by' => The order for the sorting. Defaults to 'calculated desc'.
- *
- * @return mixed
+ * 'calculation' => The calculation to use. Must be a valid MySQL function.
+ * Defaults to sum. Result selected as 'annotation_calculation'.
+ * Don't confuse this "calculation" option with the
+ * "annotation_calculation" option to elgg_get_annotations().
+ * This "calculation" option is applied to each entity's set of
+ * annotations and is selected as annotation_calculation for that row.
+ * See the docs for elgg_get_annotations() for proper use of the
+ * "annotation_calculation" option.
+ * 'order_by' => The order for the sorting. Defaults to 'annotation_calculation desc'.
+ * 'annotation_names' => The names of annotations on the entity.
+ * 'annotation_values' => The values of annotations on the entity.
+ *
+ * 'metadata_names' => The name of metadata on the entity.
+ * 'metadata_values' => The value of metadata on the entitiy.
+ *
+ * @return mixed If count, int. If not count, array. false on errors.
*/
function elgg_get_entities_from_annotation_calculation($options) {
- global $CONFIG;
-
+ $db_prefix = elgg_get_config('dbprefix');
$defaults = array(
- 'calculation' => 'sum',
- 'order_by' => 'calculated desc',
+ 'calculation' => 'sum',
+ 'order_by' => 'annotation_calculation desc'
);
$options = array_merge($defaults, $options);
@@ -408,17 +432,23 @@ function elgg_get_entities_from_annotation_calculation($options) {
$function = sanitize_string(elgg_extract('calculation', $options, 'sum', false));
// you must cast this as an int or it sorts wrong.
- $options['selects'][] = "$function(cast(msv.string as signed)) as calculated";
- $options['selects'][] = "msn.string as value";
- $options['order_by'] = 'calculated desc';
+ $options['selects'][] = 'e.*';
+ $options['selects'][] = "$function(cast(a_msv.string as signed)) as annotation_calculation";
+
+ // need our own join to get the values because the lower level functions don't
+ // add all the joins if it's a different callback.
+ $options['joins'][] = "JOIN {$db_prefix}metastrings a_msv ON n_table.value_id = a_msv.id";
+
+ // don't need access control because it's taken care of by elgg_get_annotations.
+ $options['group_by'] = 'n_table.entity_guid';
- // need our own join to get the values.
- $db_prefix = get_config('dbprefix');
- $options['joins'][] = "JOIN {$db_prefix}annotations calc_table on e.guid = calc_table.entity_guid";
- $options['joins'][] = "JOIN {$db_prefix}metastrings msv on calc_table.value_id = msv.id";
- $options['wheres'][] = "calc_table.name_id = n_table.name_id";
+ $options['callback'] = 'entity_row_to_elggstar';
- return elgg_get_entities_from_annotations($options);
+ // see #4393
+ // @todo remove after the 'count' shortcut is removed from elgg_get_annotations()
+ $options['__egefac'] = true;
+
+ return elgg_get_annotations($options);
}
/**
@@ -431,22 +461,30 @@ function elgg_get_entities_from_annotation_calculation($options) {
* @return string
*/
function elgg_list_entities_from_annotation_calculation($options) {
+ $defaults = array(
+ 'calculation' => 'sum',
+ 'order_by' => 'annotation_calculation desc'
+ );
+ $options = array_merge($defaults, $options);
+
return elgg_list_entities($options, 'elgg_get_entities_from_annotation_calculation');
}
/**
- * Handler called by trigger_plugin_hook on the "export" event.
+ * Export the annotations for the specified entity
*
* @param string $hook 'export'
- * @param string $entity_type 'all'
+ * @param string $type 'all'
* @param mixed $returnvalue Default return value
- * @param mixed $params List of params to export
+ * @param mixed $params Parameters determining what annotations to export
*
* @elgg_plugin_hook export all
*
- * @return mixed
+ * @return array
+ * @throws InvalidParameterException
+ * @access private
*/
-function export_annotation_plugin_hook($hook, $entity_type, $returnvalue, $params) {
+function export_annotation_plugin_hook($hook, $type, $returnvalue, $params) {
// Sanity check values
if ((!is_array($params)) && (!isset($params['guid']))) {
throw new InvalidParameterException(elgg_echo('InvalidParameterException:GUIDNotForExport'));
@@ -457,12 +495,12 @@ function export_annotation_plugin_hook($hook, $entity_type, $returnvalue, $param
}
$guid = (int)$params['guid'];
- $name = $params['name'];
+ $options = array('guid' => $guid, 'limit' => 0);
+ if (isset($params['name'])) {
+ $options['annotation_name'] = $params['name'];
+ }
- $result = elgg_get_annotations(array(
- 'guid' => $guid,
- 'limit' => 0
- ));
+ $result = elgg_get_annotations($options);
if ($result) {
foreach ($result as $r) {
@@ -507,15 +545,16 @@ function elgg_annotation_exists($entity_guid, $annotation_type, $owner_guid = NU
return FALSE;
}
- $entity_guid = (int)$entity_guid;
- $annotation_type = sanitise_string($annotation_type);
+ $entity_guid = sanitize_int($entity_guid);
+ $owner_guid = sanitize_int($owner_guid);
+ $annotation_type = sanitize_string($annotation_type);
- $sql = "select a.id" .
- " FROM {$CONFIG->dbprefix}annotations a, {$CONFIG->dbprefix}metastrings m " .
- " WHERE a.owner_guid={$owner_guid} AND a.entity_guid={$entity_guid} " .
- " AND a.name_id=m.id AND m.string='{$annotation_type}'";
+ $sql = "SELECT a.id FROM {$CONFIG->dbprefix}annotations a" .
+ " JOIN {$CONFIG->dbprefix}metastrings m ON a.name_id = m.id" .
+ " WHERE a.owner_guid = $owner_guid AND a.entity_guid = $entity_guid" .
+ " AND m.string = '$annotation_type'";
- if ($check_annotation = get_data_row($sql)) {
+ if (get_data_row($sql)) {
return TRUE;
}
@@ -523,10 +562,25 @@ function elgg_annotation_exists($entity_guid, $annotation_type, $owner_guid = NU
}
/**
+ * Return the URL for a comment
+ *
+ * @param ElggAnnotation $comment The comment object
+ * @return string
+ * @access private
+ */
+function elgg_comment_url_handler(ElggAnnotation $comment) {
+ $entity = $comment->getEntity();
+ if ($entity) {
+ return $entity->getURL() . '#item-annotation-' . $comment->id;
+ }
+ return "";
+}
+
+/**
* Register an annotation url handler.
*
- * @param string $function_name The function.
* @param string $extender_name The name, default 'all'.
+ * @param string $function_name The function.
*
* @return string
*/
@@ -534,16 +588,31 @@ function elgg_register_annotation_url_handler($extender_name = "all", $function_
return elgg_register_extender_url_handler('annotation', $extender_name, $function_name);
}
-/** Register the hook */
-elgg_register_plugin_hook_handler("export", "all", "export_annotation_plugin_hook", 2);
-
-elgg_register_plugin_hook_handler('unit_test', 'system', 'annotations_test');
-
/**
* Register annotation unit tests
+ *
+ * @param string $hook
+ * @param string $type
+ * @param array $value
+ * @param array $params
+ * @return array
+ * @access private
*/
function annotations_test($hook, $type, $value, $params) {
global $CONFIG;
$value[] = $CONFIG->path . 'engine/tests/api/annotations.php';
return $value;
}
+
+/**
+ * Initialize the annotation library
+ * @access private
+ */
+function elgg_annotations_init() {
+ elgg_register_annotation_url_handler('generic_comment', 'elgg_comment_url_handler');
+
+ elgg_register_plugin_hook_handler("export", "all", "export_annotation_plugin_hook", 2);
+ elgg_register_plugin_hook_handler('unit_test', 'system', 'annotations_test');
+}
+
+elgg_register_event_handler('init', 'system', 'elgg_annotations_init');
diff --git a/engine/lib/cache.php b/engine/lib/cache.php
index d4888f9d9..3116c1a9b 100644
--- a/engine/lib/cache.php
+++ b/engine/lib/cache.php
@@ -10,15 +10,14 @@
/* Filepath Cache */
/**
- * Returns an ElggCache object suitable for caching view
- * file load paths to disk under $CONFIG->dataroot.
+ * Returns an ElggCache object suitable for caching system information
*
* @todo Can this be done in a cleaner way?
* @todo Swap to memcache etc?
*
- * @return ElggFileCache A cache object suitable for caching file load paths.
+ * @return ElggFileCache
*/
-function elgg_get_filepath_cache() {
+function elgg_get_system_cache() {
global $CONFIG;
/**
@@ -27,35 +26,34 @@ function elgg_get_filepath_cache() {
static $FILE_PATH_CACHE;
if (!$FILE_PATH_CACHE) {
- $FILE_PATH_CACHE = new ElggFileCache($CONFIG->dataroot);
+ $FILE_PATH_CACHE = new ElggFileCache($CONFIG->dataroot . 'system_cache/');
}
return $FILE_PATH_CACHE;
}
/**
- * Function which resets the file path cache.
+ * Reset the system cache by deleting the caches
*
+ * @return void
*/
-function elgg_filepath_cache_reset() {
- $cache = elgg_get_filepath_cache();
- $view_types_result = $cache->delete('view_types');
- $views_result = $cache->delete('views');
- return $view_types_result && $views_result;
+function elgg_reset_system_cache() {
+ $cache = elgg_get_system_cache();
+ $cache->clear();
}
/**
- * Saves a filepath cache.
+ * Saves a system cache.
*
- * @param string $type
- * @param string $data
+ * @param string $type The type or identifier of the cache
+ * @param string $data The data to be saved
* @return bool
*/
-function elgg_filepath_cache_save($type, $data) {
+function elgg_save_system_cache($type, $data) {
global $CONFIG;
- if ($CONFIG->viewpath_cache_enabled) {
- $cache = elgg_get_filepath_cache();
+ if ($CONFIG->system_cache_enabled) {
+ $cache = elgg_get_system_cache();
return $cache->save($type, $data);
}
@@ -63,16 +61,16 @@ function elgg_filepath_cache_save($type, $data) {
}
/**
- * Retrieve the contents of the filepath cache.
+ * Retrieve the contents of a system cache.
*
* @param string $type The type of cache to load
* @return string
*/
-function elgg_filepath_cache_load($type) {
+function elgg_load_system_cache($type) {
global $CONFIG;
- if ($CONFIG->viewpath_cache_enabled) {
- $cache = elgg_get_filepath_cache();
+ if ($CONFIG->system_cache_enabled) {
+ $cache = elgg_get_system_cache();
$cached_data = $cache->load($type);
if ($cached_data) {
@@ -84,35 +82,74 @@ function elgg_filepath_cache_load($type) {
}
/**
- * Enables the views file paths disk cache.
+ * Enables the system disk cache.
*
- * Uses the 'viewpath_cache_enabled' datalist with a boolean value.
- * Resets the views paths cache.
+ * Uses the 'system_cache_enabled' datalist with a boolean value.
+ * Resets the system cache.
*
- * @return null
+ * @return void
*/
-function elgg_enable_filepath_cache() {
+function elgg_enable_system_cache() {
global $CONFIG;
- datalist_set('viewpath_cache_enabled', 1);
- $CONFIG->viewpath_cache_enabled = 1;
- elgg_filepath_cache_reset();
+ datalist_set('system_cache_enabled', 1);
+ $CONFIG->system_cache_enabled = 1;
+ elgg_reset_system_cache();
}
/**
- * Disables the views file paths disk cache.
+ * Disables the system disk cache.
*
- * Uses the 'viewpath_cache_enabled' datalist with a boolean value.
- * Resets the views paths cache.
+ * Uses the 'system_cache_enabled' datalist with a boolean value.
+ * Resets the system cache.
*
- * @return null
+ * @return void
*/
-function elgg_disable_filepath_cache() {
+function elgg_disable_system_cache() {
global $CONFIG;
- datalist_set('viewpath_cache_enabled', 0);
- $CONFIG->viewpath_cache_enabled = 0;
- elgg_filepath_cache_reset();
+ datalist_set('system_cache_enabled', 0);
+ $CONFIG->system_cache_enabled = 0;
+ elgg_reset_system_cache();
+}
+
+/** @todo deprecate in Elgg 1.9 **/
+
+/**
+ * @access private
+ */
+function elgg_get_filepath_cache() {
+ return elgg_get_system_cache();
+}
+/**
+ * @access private
+ */
+function elgg_filepath_cache_reset() {
+ elgg_reset_system_cache();
+}
+/**
+ * @access private
+ */
+function elgg_filepath_cache_save($type, $data) {
+ return elgg_save_system_cache($type, $data);
+}
+/**
+ * @access private
+ */
+function elgg_filepath_cache_load($type) {
+ return elgg_load_system_cache($type);
+}
+/**
+ * @access private
+ */
+function elgg_enable_filepath_cache() {
+ elgg_enable_system_cache();
+}
+/**
+ * @access private
+ */
+function elgg_disable_filepath_cache() {
+ elgg_disable_system_cache();
}
/* Simplecache */
@@ -129,7 +166,11 @@ function elgg_disable_filepath_cache() {
* @warning Simple cached views must take no parameters and return
* the same content no matter who is logged in.
*
- * @note CSS and the basic JS views are cached by the engine.
+ * @example
+ * $blog_js = elgg_get_simplecache_url('js', 'blog/save_draft');
+ * elgg_register_simplecache_view('js/blog/save_draft');
+ * elgg_register_js('elgg.blog', $blog_js);
+ * elgg_load_js('elgg.blog');
*
* @param string $viewname View name
*
@@ -155,6 +196,9 @@ function elgg_register_simplecache_view($viewname) {
/**
* Get the URL for the cached file
*
+ * @warning You must register the view with elgg_register_simplecache_view()
+ * for caching to work. See elgg_register_simplecache_view() for a full example.
+ *
* @param string $type The file type: css or js
* @param string $view The view name
* @return string
@@ -163,22 +207,25 @@ function elgg_register_simplecache_view($viewname) {
function elgg_get_simplecache_url($type, $view) {
global $CONFIG;
$lastcache = (int)$CONFIG->lastcache;
-
+ $viewtype = elgg_get_viewtype();
+ elgg_register_simplecache_view("$type/$view");// see #5302
if (elgg_is_simplecache_enabled()) {
- $viewtype = elgg_get_viewtype();
- $url = elgg_get_site_url() . "cache/$type/$view/$viewtype/$view.$lastcache.$type";
+ $url = elgg_get_site_url() . "cache/$type/$viewtype/$view.$lastcache.$type";
} else {
$url = elgg_get_site_url() . "$type/$view.$lastcache.$type";
+ $elements = array("view" => $viewtype);
+ $url = elgg_http_add_url_query_elements($url, $elements);
}
+
return $url;
}
/**
* Regenerates the simple cache.
*
- * @warning This does not invalidate the cache, but actively resets it.
+ * @warning This does not invalidate the cache, but actively rebuilds it.
*
- * @param string $viewtype Optional viewtype to regenerate
+ * @param string $viewtype Optional viewtype to regenerate. Defaults to all valid viewtypes.
*
* @return void
* @see elgg_register_simplecache_view()
@@ -300,7 +347,8 @@ function elgg_disable_simplecache() {
}
/**
- * Invalidates all cached views in the simplecache
+ * Deletes all cached views in the simplecache and sets the lastcache and
+ * lastupdate time to 0 for every valid viewtype.
*
* @return bool
* @since 1.7.4
@@ -308,19 +356,98 @@ function elgg_disable_simplecache() {
function elgg_invalidate_simplecache() {
global $CONFIG;
- $return = TRUE;
+ if (!isset($CONFIG->views->simplecache) || !is_array($CONFIG->views->simplecache)) {
+ return false;
+ }
+
+ $handle = opendir($CONFIG->dataroot . 'views_simplecache');
- if ($handle = opendir($CONFIG->dataroot . 'views_simplecache')) {
- while (false !== ($file = readdir($handle))) {
- if ($file != "." && $file != "..") {
- $return = $return && unlink($CONFIG->dataroot . 'views_simplecache/' . $file);
- }
+ if (!$handle) {
+ return false;
+ }
+
+ // remove files.
+ $return = true;
+ while (false !== ($file = readdir($handle))) {
+ if ($file != "." && $file != "..") {
+ $return &= unlink($CONFIG->dataroot . 'views_simplecache/' . $file);
}
- closedir($handle);
- } else {
- $return = FALSE;
+ }
+ closedir($handle);
+
+ // reset cache times
+ $viewtypes = $CONFIG->view_types;
+
+ if (!is_array($viewtypes)) {
+ return false;
+ }
+
+ foreach ($viewtypes as $viewtype) {
+ $return &= datalist_set("simplecache_lastupdate_$viewtype", 0);
+ $return &= datalist_set("simplecache_lastcached_$viewtype", 0);
}
return $return;
}
+/**
+ * @see elgg_reset_system_cache()
+ * @access private
+ */
+function _elgg_load_cache() {
+ global $CONFIG;
+
+ $CONFIG->system_cache_loaded = false;
+
+ $CONFIG->views = new stdClass();
+ $data = elgg_load_system_cache('view_locations');
+ if (!is_string($data)) {
+ return;
+ }
+ $CONFIG->views->locations = unserialize($data);
+
+ $data = elgg_load_system_cache('view_types');
+ if (!is_string($data)) {
+ return;
+ }
+ $CONFIG->view_types = unserialize($data);
+
+ $CONFIG->system_cache_loaded = true;
+}
+
+/**
+ * @access private
+ */
+function _elgg_cache_init() {
+ global $CONFIG;
+
+ $viewtype = elgg_get_viewtype();
+
+ // Regenerate the simple cache if expired.
+ // Don't do it on upgrade because upgrade does it itself.
+ // @todo - move into function and perhaps run off init system event
+ if (!defined('UPGRADING')) {
+ $lastupdate = datalist_get("simplecache_lastupdate_$viewtype");
+ $lastcached = datalist_get("simplecache_lastcached_$viewtype");
+ if ($lastupdate == 0 || $lastcached < $lastupdate) {
+ elgg_regenerate_simplecache($viewtype);
+ $lastcached = datalist_get("simplecache_lastcached_$viewtype");
+ }
+ $CONFIG->lastcache = $lastcached;
+ }
+
+ // cache system data if enabled and not loaded
+ if ($CONFIG->system_cache_enabled && !$CONFIG->system_cache_loaded) {
+ elgg_save_system_cache('view_locations', serialize($CONFIG->views->locations));
+ elgg_save_system_cache('view_types', serialize($CONFIG->view_types));
+ }
+
+ if ($CONFIG->system_cache_enabled && !$CONFIG->i18n_loaded_from_cache) {
+ reload_all_translations();
+ foreach ($CONFIG->translations as $lang => $map) {
+ elgg_save_system_cache("$lang.lang", serialize($map));
+ }
+ }
+}
+
+elgg_register_event_handler('ready', 'system', '_elgg_cache_init');
diff --git a/engine/lib/calendar.php b/engine/lib/calendar.php
index a882aedbe..e6f95934c 100644
--- a/engine/lib/calendar.php
+++ b/engine/lib/calendar.php
@@ -16,6 +16,7 @@
* @param int $year Year
*
* @return int
+ * @access private
*/
function get_day_start($day = null, $month = null, $year = null) {
return mktime(0, 0, 0, $month, $day, $year);
@@ -29,6 +30,7 @@ function get_day_start($day = null, $month = null, $year = null) {
* @param int $year Year
*
* @return int
+ * @access private
*/
function get_day_end($day = null, $month = null, $year = null) {
return mktime(23, 59, 59, $month, $day, $year);
@@ -37,6 +39,8 @@ function get_day_end($day = null, $month = null, $year = null) {
/**
* Return the notable entities for a given time period.
*
+ * @todo this function also accepts an array(type => subtypes) for 3rd arg. Should we document this?
+ *
* @param int $start_time The start time as a unix timestamp.
* @param int $end_time The end time as a unix timestamp.
* @param string $type The type of entity (eg "user", "object" etc)
@@ -50,6 +54,7 @@ function get_day_end($day = null, $month = null, $year = null) {
* @param mixed $container_guid Container or containers to get entities from (default: any).
*
* @return array|false
+ * @access private
*/
function get_notable_entities($start_time, $end_time, $type = "", $subtype = "", $owner_guid = 0,
$order_by = "asc", $limit = 10, $offset = 0, $count = false, $site_guid = 0,
@@ -197,6 +202,7 @@ $container_guid = null) {
* @param bool $count If true, returns count instead of entities. (Default: false)
*
* @return int|array A list of entities, or a count if $count is set to true
+ * @access private
*/
function get_notable_entities_from_metadata($start_time, $end_time, $meta_name, $meta_value = "",
$entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "",
@@ -326,6 +332,7 @@ $site_guid = 0, $count = false) {
* @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any
*
* @return array|int|false An array of entities, or the number of entities, or false on failure
+ * @access private
*/
function get_noteable_entities_from_relationship($start_time, $end_time, $relationship,
$relationship_guid, $inverse_relationship = false, $type = "", $subtype = "", $owner_guid = 0,
@@ -435,6 +442,7 @@ $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
* @param mixed $container_guid Container(s) to get entities from (default: any).
*
* @return array|false
+ * @access private
*/
function get_todays_entities($type = "", $subtype = "", $owner_guid = 0, $order_by = "",
$limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null) {
@@ -461,6 +469,7 @@ $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null
* @param bool $count If true, returns count instead of entities. (Default: false)
*
* @return int|array A list of entities, or a count if $count is set to true
+ * @access private
*/
function get_todays_entities_from_metadata($meta_name, $meta_value = "", $entity_type = "",
$entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0,
@@ -491,6 +500,7 @@ $count = false) {
* @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any
*
* @return array|int|false An array of entities, or the number of entities, or false on failure
+ * @access private
*/
function get_todays_entities_from_relationship($relationship, $relationship_guid,
$inverse_relationship = false, $type = "", $subtype = "", $owner_guid = 0,
@@ -520,6 +530,7 @@ $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
* @param boolean $navigation Display pagination? Default: true
*
* @return string A viewable list of entities
+ * @access private
*/
function list_notable_entities($start_time, $end_time, $type= "", $subtype = "", $owner_guid = 0,
$limit = 10, $fullview = true, $listtypetoggle = false, $navigation = true) {
@@ -549,6 +560,7 @@ $limit = 10, $fullview = true, $listtypetoggle = false, $navigation = true) {
* @param boolean $navigation Display pagination? Default: true
*
* @return string A viewable list of entities
+ * @access private
*/
function list_todays_entities($type= "", $subtype = "", $owner_guid = 0, $limit = 10,
$fullview = true, $listtypetoggle = false, $navigation = true) {
diff --git a/engine/lib/configuration.php b/engine/lib/configuration.php
index cbc083bd0..55e5bbd36 100644
--- a/engine/lib/configuration.php
+++ b/engine/lib/configuration.php
@@ -3,8 +3,9 @@
* Elgg configuration procedural code.
*
* Includes functions for manipulating the configuration values stored in the database
- * Plugin authors should use the {@link get_config()}, {@link set_config()},
- * and {@unset_config()} functions to access or update config values.
+ * Plugin authors should use the {@link elgg_get_config()}, {@link elgg_set_config()},
+ * {@link elgg_save_config()}, and {@unset_config()} functions to access or update
+ * config values.
*
* Elgg's configuration is split among 2 tables and 1 file:
* - dbprefix_config
@@ -35,6 +36,7 @@ function elgg_get_site_url($site_guid = 0) {
if (!$site instanceof ElggSite) {
return false;
}
+ /* @var ElggSite $site */
return $site->url;
}
@@ -90,23 +92,29 @@ function elgg_get_config($name, $site_guid = 0) {
return $CONFIG->$name;
}
- if ($site_guid === NULL) {
+ if ($site_guid === null) {
// installation wide setting
$value = datalist_get($name);
} else {
- // site specific setting
- if ($site_guid == 0) {
- $site_guid = (int) $CONFIG->site_id;
+ // hit DB only if we're not sure if value exists or not
+ if (!isset($CONFIG->site_config_loaded)) {
+ // site specific setting
+ if ($site_guid == 0) {
+ $site_guid = (int) $CONFIG->site_id;
+ }
+ $value = get_config($name, $site_guid);
+ } else {
+ $value = null;
}
- $value = get_config($name, $site_guid);
}
- if ($value !== false) {
- $CONFIG->$name = $value;
- return $value;
+ // @todo document why we don't cache false
+ if ($value === false) {
+ return null;
}
- return null;
+ $CONFIG->$name = $value;
+ return $value;
}
/**
@@ -131,7 +139,7 @@ function elgg_set_config($name, $value) {
/**
* Save a configuration setting
*
- * @param string $name Configuration name (cannot be greater than 32 characters)
+ * @param string $name Configuration name (cannot be greater than 255 characters)
* @param mixed $value Configuration value. Should be string for installation setting
* @param int $site_guid NULL for installation setting, 0 for default site
*
@@ -166,14 +174,15 @@ function elgg_save_config($name, $value, $site_guid = 0) {
/**
* Check that installation has completed and the database is populated.
*
- * @throws InstallationException
+ * @throws InstallationException|DatabaseException
* @return void
+ * @access private
*/
function verify_installation() {
global $CONFIG;
if (isset($CONFIG->installed)) {
- return $CONFIG->installed;
+ return;
}
try {
@@ -212,15 +221,16 @@ $DATALIST_CACHE = array();
*
* @param string $name The name of the datalist
* @return string|null|false String if value exists, null if doesn't, false on error
+ * @access private
*/
function datalist_get($name) {
global $CONFIG, $DATALIST_CACHE;
$name = trim($name);
- // cannot store anything longer than 32 characters in db, so catch here
- if (elgg_strlen($name) > 32) {
- elgg_log("The name length for configuration variables cannot be greater than 32", "ERROR");
+ // cannot store anything longer than 255 characters in db, so catch here
+ if (elgg_strlen($name) > 255) {
+ elgg_log("The name length for configuration variables cannot be greater than 255", "ERROR");
return false;
}
@@ -272,18 +282,19 @@ function datalist_get($name) {
* @param string $value The new value
*
* @return bool
+ * @access private
*/
function datalist_set($name, $value) {
global $CONFIG, $DATALIST_CACHE;
- // cannot store anything longer than 32 characters in db, so catch before we set
+ // cannot store anything longer than 255 characters in db, so catch before we set
if (elgg_strlen($name) > 255) {
elgg_log("The name length for configuration variables cannot be greater than 255", "ERROR");
return false;
}
- $name = sanitise_string($name);
- $value = sanitise_string($value);
+ $sanitised_name = sanitise_string($name);
+ $sanitised_value = sanitise_string($value);
// If memcache is available then invalidate the cached copy
static $datalist_memcache;
@@ -295,13 +306,16 @@ function datalist_set($name, $value) {
$datalist_memcache->delete($name);
}
- insert_data("INSERT into {$CONFIG->dbprefix}datalists"
- . " set name = '{$name}', value = '{$value}'"
- . " ON DUPLICATE KEY UPDATE value='{$value}'");
+ $success = insert_data("INSERT into {$CONFIG->dbprefix}datalists"
+ . " set name = '{$sanitised_name}', value = '{$sanitised_value}'"
+ . " ON DUPLICATE KEY UPDATE value='{$sanitised_value}'");
- $DATALIST_CACHE[$name] = $value;
-
- return true;
+ if ($success !== FALSE) {
+ $DATALIST_CACHE[$name] = $value;
+ return true;
+ } else {
+ return false;
+ }
}
/**
@@ -319,7 +333,7 @@ function datalist_set($name, $value) {
* This will cause the run once function to be run on all installations. To perform
* additional upgrades, create new functions for each release.
*
- * @warning The function name cannot be longer than 32 characters long due to
+ * @warning The function name cannot be longer than 255 characters long due to
* the current schema for the datalist table.
*
* @internal A datalist entry $functioname is created with the value of time().
@@ -394,20 +408,21 @@ function unset_config($name, $site_guid = 0) {
* @param string $value Its value
* @param int $site_guid Optionally, the GUID of the site (current site is assumed by default)
*
- * @return 0
+ * @return bool
* @todo The config table doens't have numeric primary keys so insert_data returns 0.
* @todo Use "INSERT ... ON DUPLICATE KEY UPDATE" instead of trying to delete then add.
* @see unset_config()
* @see get_config()
+ * @access private
*/
function set_config($name, $value, $site_guid = 0) {
global $CONFIG;
$name = trim($name);
- // cannot store anything longer than 32 characters in db, so catch before we set
- if (elgg_strlen($name) > 32) {
- elgg_log("The name length for configuration variables cannot be greater than 32", "ERROR");
+ // cannot store anything longer than 255 characters in db, so catch before we set
+ if (elgg_strlen($name) > 255) {
+ elgg_log("The name length for configuration variables cannot be greater than 255", "ERROR");
return false;
}
@@ -440,6 +455,7 @@ function set_config($name, $value, $site_guid = 0) {
* @return mixed|null
* @see set_config()
* @see unset_config()
+ * @access private
*/
function get_config($name, $site_guid = 0) {
global $CONFIG;
@@ -461,21 +477,18 @@ function get_config($name, $site_guid = 0) {
$dep_version = 1.8;
break;
- case 'wwwroot':
- $new_name = 'www_root';
- $dep_version = 1.8;
- break;
-
case 'sitename':
$new_name = 'site_name';
$dep_version = 1.8;
break;
}
+ // @todo these haven't really been implemented in Elgg 1.8. Complete in 1.9.
// show dep message
if ($new_name) {
+ // $msg = "Config value $name has been renamed as $new_name";
$name = $new_name;
- elgg_deprecated_notice($msg, $dep_version);
+ // elgg_deprecated_notice($msg, $dep_version);
}
// decide from where to return the value
@@ -506,6 +519,7 @@ function get_config($name, $site_guid = 0) {
* @param int $site_guid Optionally, the GUID of the site (current site is assumed by default)
*
* @return bool
+ * @access private
*/
function get_all_config($site_guid = 0) {
global $CONFIG;
@@ -513,10 +527,10 @@ function get_all_config($site_guid = 0) {
$site_guid = (int) $site_guid;
if ($site_guid == 0) {
- $site_guid = (int) $CONFIG->site_id;
+ $site_guid = (int) $CONFIG->site_guid;
}
- if ($result = get_data("SELECT * from {$CONFIG->dbprefix}config where site_guid = {$site_guid}")) {
+ if ($result = get_data("SELECT * FROM {$CONFIG->dbprefix}config WHERE site_guid = $site_guid")) {
foreach ($result as $r) {
$name = $r->name;
$value = $r->value;
@@ -529,38 +543,51 @@ function get_all_config($site_guid = 0) {
}
/**
- * Sets defaults for or attempts to autodetect some common config values and
- * loads them into $CONFIG.
+ * Loads configuration related to this site
*
- * @return true
+ * This loads from the config database table and the site entity
+ * @access private
*/
-function set_default_config() {
+function _elgg_load_site_config() {
global $CONFIG;
- $install_root = str_replace("\\", "/", dirname(dirname(dirname(__FILE__))));
-
- // @todo this seldom works right.
- $pathpart = str_replace("//", "/", str_replace($_SERVER['DOCUMENT_ROOT'], "", $install_root));
- if (substr($pathpart, 0, 1) != "/") {
- $pathpart = "/" . $pathpart;
+ $CONFIG->site_guid = (int) datalist_get('default_site');
+ $CONFIG->site_id = $CONFIG->site_guid;
+ $CONFIG->site = get_entity($CONFIG->site_guid);
+ if (!$CONFIG->site) {
+ throw new InstallationException(elgg_echo('InstallationException:SiteNotInstalled'));
}
- $www_root = "http://" . $_SERVER['HTTP_HOST'] . $pathpart;
+ $CONFIG->wwwroot = $CONFIG->site->url;
+ $CONFIG->sitename = $CONFIG->site->name;
+ $CONFIG->sitedescription = $CONFIG->site->description;
+ $CONFIG->siteemail = $CONFIG->site->email;
+ $CONFIG->url = $CONFIG->wwwroot;
+
+ get_all_config();
+ // gives hint to elgg_get_config function how to approach missing values
+ $CONFIG->site_config_loaded = true;
+}
+
+/**
+ * Loads configuration related to Elgg as an application
+ *
+ * This loads from the datalists database table
+ * @access private
+ */
+function _elgg_load_application_config() {
+ global $CONFIG;
+
+ $install_root = str_replace("\\", "/", dirname(dirname(dirname(__FILE__))));
$defaults = array(
'path' => "$install_root/",
'view_path' => "$install_root/views/",
'plugins_path' => "$install_root/mod/",
- 'www_root' => $www_root,
- 'url' => $www_root,
- 'site_name' => 'New Elgg site',
'language' => 'en',
- // compatibility with old names for ppl not using get_config()
+ // compatibility with old names for plugins not using elgg_get_config()
'viewpath' => "$install_root/views/",
'pluginspath' => "$install_root/mod/",
- 'wwwroot' => $www_root,
- 'url' => $www_root,
- 'sitename' => 'New Elgg site',
);
foreach ($defaults as $name => $value) {
@@ -569,22 +596,6 @@ function set_default_config() {
}
}
- return true;
-}
-
-/**
- * Loads values into $CONFIG.
- *
- * If Elgg is installed, this function pulls all rows from dbprefix_config
- * and cherry picks some values from dbprefix_datalists. This also extracts
- * some commonly used values from the default site object.
- *
- * @elgg_event boot system
- * @return true|null
- */
-function configuration_boot() {
- global $CONFIG;
-
$path = datalist_get('path');
if (!empty($path)) {
$CONFIG->path = $path;
@@ -599,22 +610,23 @@ function configuration_boot() {
} else {
$CONFIG->simplecache_enabled = 1;
}
- $viewpath_cache_enabled = datalist_get('viewpath_cache_enabled');
- if ($viewpath_cache_enabled !== false) {
- $CONFIG->viewpath_cache_enabled = $viewpath_cache_enabled;
+ $system_cache_enabled = datalist_get('system_cache_enabled');
+ if ($system_cache_enabled !== false) {
+ $CONFIG->system_cache_enabled = $system_cache_enabled;
} else {
- $CONFIG->viewpath_cache_enabled = 1;
- }
- if (isset($CONFIG->site) && ($CONFIG->site instanceof ElggSite)) {
- $CONFIG->wwwroot = $CONFIG->site->url;
- $CONFIG->sitename = $CONFIG->site->name;
- $CONFIG->sitedescription = $CONFIG->site->description;
- $CONFIG->siteemail = $CONFIG->site->email;
+ $CONFIG->system_cache_enabled = 1;
}
- $CONFIG->url = $CONFIG->wwwroot;
- // Load default settings from database
- get_all_config();
-}
+ // initialize context here so it is set before the get_input call
+ $CONFIG->context = array();
-elgg_register_event_handler('boot', 'system', 'configuration_boot', 10);
+ // needs to be set before system, init for links in html head
+ $viewtype = get_input('view', 'default');
+ $lastcached = datalist_get("simplecache_lastcached_$viewtype");
+ $CONFIG->lastcache = $lastcached;
+
+ $CONFIG->i18n_loaded_from_cache = false;
+
+ // this must be synced with the enum for the entities table
+ $CONFIG->entity_types = array('group', 'object', 'site', 'user');
+}
diff --git a/engine/lib/cron.php b/engine/lib/cron.php
index 2a0b1d665..4f3d05b93 100644
--- a/engine/lib/cron.php
+++ b/engine/lib/cron.php
@@ -10,6 +10,7 @@
* Cron initialization
*
* @return void
+ * @access private
*/
function cron_init() {
// Register a pagehandler for cron
@@ -24,11 +25,11 @@ function cron_init() {
*
* @param array $page Pages
*
- * @return void
+ * @return bool
+ * @throws CronException
+ * @access private
*/
function cron_page_handler($page) {
- global $CONFIG;
-
if (!isset($page[0])) {
forward();
}
@@ -48,12 +49,7 @@ function cron_page_handler($page) {
$params = array();
$params['time'] = time();
- foreach ($CONFIG->input as $k => $v) {
- $params[$k] = $v;
- }
-
// Data to return to
- $std_out = "";
$old_stdout = "";
ob_start();
@@ -61,6 +57,7 @@ function cron_page_handler($page) {
$std_out = ob_get_clean();
echo $std_out . $old_stdout;
+ return true;
}
/**
@@ -72,6 +69,7 @@ function cron_page_handler($page) {
* @param mixed $params Params
*
* @return array
+ * @access private
*/
function cron_public_pages($hook, $type, $return_value, $params) {
$return_value[] = 'cron/minute';
diff --git a/engine/lib/database.php b/engine/lib/database.php
index a9c4017a0..a7949788d 100644
--- a/engine/lib/database.php
+++ b/engine/lib/database.php
@@ -12,15 +12,19 @@
/**
* Query cache for all queries.
*
- * Each query and its results are stored in this array as:
+ * Each query and its results are stored in this cache as:
* <code>
- * $DB_QUERY_CACHE[$query] => array(result1, result2, ... resultN)
+ * $DB_QUERY_CACHE[query hash] => array(result1, result2, ... resultN)
* </code>
+ * @see elgg_query_runner() for details on the hash.
*
- * @global array $DB_QUERY_CACHE
+ * @warning Elgg used to set this as an empty array to turn off the cache
+ *
+ * @global ElggLRUCache|null $DB_QUERY_CACHE
+ * @access private
*/
global $DB_QUERY_CACHE;
-$DB_QUERY_CACHE = array();
+$DB_QUERY_CACHE = null;
/**
* Queries to be executed upon shutdown.
@@ -38,6 +42,7 @@ $DB_QUERY_CACHE = array();
* </code>
*
* @global array $DB_DELAYED_QUERIES
+ * @access private
*/
global $DB_DELAYED_QUERIES;
$DB_DELAYED_QUERIES = array();
@@ -48,7 +53,8 @@ $DB_DELAYED_QUERIES = array();
* Each database link created with establish_db_link($name) is stored in
* $dblink as $dblink[$name] => resource. Use get_db_link($name) to retrieve it.
*
- * @global array $dblink
+ * @global resource[] $dblink
+ * @access private
*/
global $dblink;
$dblink = array();
@@ -59,6 +65,7 @@ $dblink = array();
* Each call to the database increments this counter.
*
* @global integer $dbcalls
+ * @access private
*/
global $dbcalls;
$dbcalls = 0;
@@ -72,10 +79,12 @@ $dbcalls = 0;
* resource. eg "read", "write", or "readwrite".
*
* @return void
+ * @throws DatabaseException
+ * @access private
*/
function establish_db_link($dblinkname = "readwrite") {
// Get configuration, and globalise database link
- global $CONFIG, $dblink, $DB_QUERY_CACHE, $dbcalls;
+ global $CONFIG, $dblink, $DB_QUERY_CACHE;
if ($dblinkname != "readwrite" && isset($CONFIG->db[$dblinkname])) {
if (is_array($CONFIG->db[$dblinkname])) {
@@ -119,7 +128,8 @@ function establish_db_link($dblinkname = "readwrite") {
// Set up cache if global not initialized and query cache not turned off
if ((!$DB_QUERY_CACHE) && (!$db_cache_off)) {
- $DB_QUERY_CACHE = new ElggStaticVariableCache('db_query_cache');
+ // @todo if we keep this cache in 1.9, expose the size as a config parameter
+ $DB_QUERY_CACHE = new ElggLRUCache(200);
}
}
@@ -130,9 +140,10 @@ function establish_db_link($dblinkname = "readwrite") {
* links up separately; otherwise just create the one database link.
*
* @return void
+ * @access private
*/
function setup_db_connections() {
- global $CONFIG, $dblink;
+ global $CONFIG;
if (!empty($CONFIG->db->split)) {
establish_db_link('read');
@@ -146,6 +157,7 @@ function setup_db_connections() {
* Display profiling information about db at NOTICE debug level upon shutdown.
*
* @return void
+ * @access private
*/
function db_profiling_shutdown_hook() {
global $dbcalls;
@@ -158,15 +170,23 @@ function db_profiling_shutdown_hook() {
* Execute any delayed queries upon shutdown.
*
* @return void
+ * @access private
*/
function db_delayedexecution_shutdown_hook() {
global $DB_DELAYED_QUERIES;
foreach ($DB_DELAYED_QUERIES as $query_details) {
- // use one of our db functions so it is included in profiling.
- $result = execute_query($query_details['q'], $query_details['l']);
-
try {
+ $link = $query_details['l'];
+
+ if ($link == 'read' || $link == 'write') {
+ $link = get_db_link($link);
+ } elseif (!is_resource($link)) {
+ elgg_log("Link for delayed query not valid resource or db_link type. Query: {$query_details['q']}", 'WARNING');
+ }
+
+ $result = execute_query($query_details['q'], $link);
+
if ((isset($query_details['h'])) && (is_callable($query_details['h']))) {
$query_details['h']($result);
}
@@ -178,21 +198,6 @@ function db_delayedexecution_shutdown_hook() {
}
/**
- * Registers shutdown functions for database profiling and delayed queries.
- *
- * @note Database connections are established upon first call to database.
- *
- * @return true
- * @elgg_event_handler boot system
- */
-function init_db() {
- register_shutdown_function('db_delayedexecution_shutdown_hook');
- register_shutdown_function('db_profiling_shutdown_hook');
-
- return true;
-}
-
-/**
* Returns (if required, also creates) a database link resource.
*
* Database link resources are stored in the {@link $dblink} global. These
@@ -201,7 +206,8 @@ function init_db() {
*
* @param string $dblinktype The type of link we want: "read", "write" or "readwrite".
*
- * @return object Database link
+ * @return resource Database link
+ * @access private
*/
function get_db_link($dblinktype) {
global $dblink;
@@ -219,10 +225,11 @@ function get_db_link($dblinktype) {
/**
* Execute an EXPLAIN for $query.
*
- * @param str $query The query to explain
+ * @param string $query The query to explain
* @param mixed $link The database link resource to user.
*
* @return mixed An object of the query's result, or FALSE
+ * @access private
*/
function explain_query($query, $link) {
if ($result = execute_query("explain " . $query, $link)) {
@@ -242,20 +249,23 @@ function explain_query($query, $link) {
* {@link $dbcalls} is incremented and the query is saved into the {@link $DB_QUERY_CACHE}.
*
* @param string $query The query
- * @param link $dblink The DB link
+ * @param resource $dblink The DB link
*
- * @return The result of mysql_query()
+ * @return resource result of mysql_query()
* @throws DatabaseException
+ * @access private
*/
function execute_query($query, $dblink) {
- global $CONFIG, $dbcalls;
+ global $dbcalls;
- // remove newlines so logs are easier to read
- $query = preg_replace("/[\r\n]/", "", $query);
if ($query == NULL) {
throw new DatabaseException(elgg_echo('DatabaseException:InvalidQuery'));
}
+ if (!is_resource($dblink)) {
+ throw new DatabaseException(elgg_echo('DatabaseException:InvalidDBLink'));
+ }
+
$dbcalls++;
$result = mysql_query($query, $dblink);
@@ -274,10 +284,11 @@ function execute_query($query, $dblink) {
* the raw result from {@link mysql_query()}.
*
* @param string $query The query to execute
- * @param resource $dblink The database link to use
+ * @param resource|string $dblink The database link to use or the link type (read | write)
* @param string $handler A callback function to pass the results array to
*
* @return true
+ * @access private
*/
function execute_delayed_query($query, $dblink, $handler = "") {
global $DB_DELAYED_QUERIES;
@@ -286,6 +297,10 @@ function execute_delayed_query($query, $dblink, $handler = "") {
$DB_DELAYED_QUERIES = array();
}
+ if (!is_resource($dblink) && $dblink != 'read' && $dblink != 'write') {
+ return false;
+ }
+
// Construct delayed query
$delayed_query = array();
$delayed_query['q'] = $query;
@@ -306,9 +321,10 @@ function execute_delayed_query($query, $dblink, $handler = "") {
* @return true
* @uses execute_delayed_query()
* @uses get_db_link()
+ * @access private
*/
function execute_delayed_write_query($query, $handler = "") {
- return execute_delayed_query($query, get_db_link('write'), $handler);
+ return execute_delayed_query($query, 'write', $handler);
}
/**
@@ -320,9 +336,10 @@ function execute_delayed_write_query($query, $handler = "") {
* @return true
* @uses execute_delayed_query()
* @uses get_db_link()
+ * @access private
*/
function execute_delayed_read_query($query, $handler = "") {
- return execute_delayed_query($query, get_db_link('read'), $handler);
+ return execute_delayed_query($query, 'read', $handler);
}
/**
@@ -339,6 +356,7 @@ function execute_delayed_read_query($query, $handler = "") {
*
* @return array An array of database result objects or callback function results. If the query
* returned nothing, an empty array.
+ * @access private
*/
function get_data($query, $callback = "") {
return elgg_query_runner($query, $callback, false);
@@ -355,6 +373,7 @@ function get_data($query, $callback = "") {
* @param string $callback A callback function
*
* @return mixed A single database result object or the result of the callback function.
+ * @access private
*/
function get_data_row($query, $callback = "") {
return elgg_query_runner($query, $callback, true);
@@ -362,7 +381,7 @@ function get_data_row($query, $callback = "") {
/**
* Handles returning data from a query, running it through a callback function,
- * and caching the results.
+ * and caching the results. This is for R queries (from CRUD).
*
* @access private
*
@@ -373,21 +392,21 @@ function get_data_row($query, $callback = "") {
* @return array An array of database result objects or callback function results. If the query
* returned nothing, an empty array.
* @since 1.8.0
+ * @access private
*/
function elgg_query_runner($query, $callback = null, $single = false) {
- global $CONFIG, $DB_QUERY_CACHE;
+ global $DB_QUERY_CACHE;
- // since we want to cache results of running the callback, we need to
- // need to namespace the query with the callback, and single result request.
- $hash = (string)$callback . (string)$single . $query;
+ // Since we want to cache results of running the callback, we need to
+ // need to namespace the query with the callback and single result request.
+ // https://github.com/elgg/elgg/issues/4049
+ $hash = (string)$callback . (int)$single . $query;
// Is cached?
if ($DB_QUERY_CACHE) {
- $cached_query = $DB_QUERY_CACHE[$hash];
-
- if ($cached_query !== FALSE) {
- elgg_log("$query results returned from cache (hash: $hash)");
- return $cached_query;
+ if (isset($DB_QUERY_CACHE[$hash])) {
+ elgg_log("DB query $query results returned from cache (hash: $hash)", 'NOTICE');
+ return $DB_QUERY_CACHE[$hash];
}
}
@@ -398,7 +417,7 @@ function elgg_query_runner($query, $callback = null, $single = false) {
// test for callback once instead of on each iteration.
// @todo check profiling to see if this needs to be broken out into
- // explicit cases instead of checking in the interation.
+ // explicit cases instead of checking in the iteration.
$is_callable = is_callable($callback);
while ($row = mysql_fetch_object($result)) {
if ($is_callable) {
@@ -415,13 +434,13 @@ function elgg_query_runner($query, $callback = null, $single = false) {
}
if (empty($return)) {
- elgg_log("DB query \"$query\" returned no results.");
+ elgg_log("DB query $query returned no results.", 'NOTICE');
}
// Cache result
if ($DB_QUERY_CACHE) {
$DB_QUERY_CACHE[$hash] = $return;
- elgg_log("$query results cached (hash: $hash)");
+ elgg_log("DB query $query results cached (hash: $hash)", 'NOTICE');
}
return $return;
@@ -436,18 +455,15 @@ function elgg_query_runner($query, $callback = null, $single = false) {
*
* @return int|false The database id of the inserted row if a AUTO_INCREMENT field is
* defined, 0 if not, and false on failure.
+ * @access private
*/
function insert_data($query) {
- global $CONFIG, $DB_QUERY_CACHE;
+ elgg_log("DB query $query", 'NOTICE');
+
$dblink = get_db_link('write');
- // Invalidate query cache
- if ($DB_QUERY_CACHE) {
- $DB_QUERY_CACHE->clear();
- }
-
- elgg_log("Query cache invalidated");
+ _elgg_invalidate_query_cache();
if (execute_query("$query", $dblink)) {
return mysql_insert_id($dblink);
@@ -457,24 +473,22 @@ function insert_data($query) {
}
/**
- * Update a row in the database.
+ * Update the database.
*
* @note Altering the DB invalidates all queries in {@link $DB_QUERY_CACHE}.
*
* @param string $query The query to run.
*
- * @return Bool
+ * @return bool
+ * @access private
*/
function update_data($query) {
- global $CONFIG, $DB_QUERY_CACHE;
+
+ elgg_log("DB query $query", 'NOTICE');
$dblink = get_db_link('write');
- // Invalidate query cache
- if ($DB_QUERY_CACHE) {
- $DB_QUERY_CACHE->clear();
- elgg_log("Query cache invalidated");
- }
+ _elgg_invalidate_query_cache();
if (execute_query("$query", $dblink)) {
return TRUE;
@@ -484,24 +498,22 @@ function update_data($query) {
}
/**
- * Remove a row from the database.
+ * Remove data from the database.
*
* @note Altering the DB invalidates all queries in {@link $DB_QUERY_CACHE}.
*
* @param string $query The SQL query to run
*
* @return int|false The number of affected rows or false on failure
+ * @access private
*/
function delete_data($query) {
- global $CONFIG, $DB_QUERY_CACHE;
+
+ elgg_log("DB query $query", 'NOTICE');
$dblink = get_db_link('write');
- // Invalidate query cache
- if ($DB_QUERY_CACHE) {
- $DB_QUERY_CACHE->clear();
- elgg_log("Query cache invalidated");
- }
+ _elgg_invalidate_query_cache();
if (execute_query("$query", $dblink)) {
return mysql_affected_rows($dblink);
@@ -510,6 +522,22 @@ function delete_data($query) {
return FALSE;
}
+/**
+ * Invalidate the query cache
+ *
+ * @access private
+ */
+function _elgg_invalidate_query_cache() {
+ global $DB_QUERY_CACHE;
+ if ($DB_QUERY_CACHE instanceof ElggLRUCache) {
+ $DB_QUERY_CACHE->clear();
+ elgg_log("Query cache invalidated", 'NOTICE');
+ } elseif ($DB_QUERY_CACHE) {
+ // In case someone sets the cache to an array and primes it with data
+ $DB_QUERY_CACHE = array();
+ elgg_log("Query cache invalidated", 'NOTICE');
+ }
+}
/**
* Return tables matching the database prefix {@link $CONFIG->dbprefix}% in the currently
@@ -517,6 +545,7 @@ function delete_data($query) {
*
* @return array|false List of tables or false on failure
* @static array $tables Tables found matching the database prefix
+ * @access private
*/
function get_db_tables() {
global $CONFIG;
@@ -559,6 +588,7 @@ function get_db_tables() {
* @param string $table The name of the table to optimise
*
* @return bool
+ * @access private
*/
function optimize_table($table) {
$table = sanitise_string($table);
@@ -571,6 +601,7 @@ function optimize_table($table) {
* @param resource $dblink The DB link
*
* @return string Database error message
+ * @access private
*/
function get_db_error($dblink) {
return mysql_error($dblink);
@@ -595,6 +626,7 @@ function get_db_error($dblink) {
*
* @return void
* @throws DatabaseException
+ * @access private
*/
function run_sql_script($scriptlocation) {
if ($script = file_get_contents($scriptlocation)) {
@@ -613,7 +645,7 @@ function run_sql_script($scriptlocation) {
$statement = str_replace("prefix_", $CONFIG->dbprefix, $statement);
if (!empty($statement)) {
try {
- $result = update_data($statement);
+ update_data($statement);
} catch (DatabaseException $e) {
$errors[] = $e->getMessage();
}
@@ -635,6 +667,18 @@ function run_sql_script($scriptlocation) {
}
/**
+ * Format a query string for logging
+ *
+ * @param string $query Query string
+ * @return string
+ * @access private
+ */
+function elgg_format_query($query) {
+ // remove newlines and extra spaces so logs are easier to read
+ return preg_replace('/\s\s+/', ' ', $query);
+}
+
+/**
* Sanitise a string for database use, but with the option of escaping extra characters.
*
* @param string $string The string to sanitise
@@ -679,26 +723,42 @@ function sanitize_string($string) {
/**
* Sanitises an integer for database use.
*
- * @param int $int Integer
- *
- * @return int Sanitised integer
+ * @param int $int Value to be sanitized
+ * @param bool $signed Whether negative values should be allowed (true)
+ * @return int
*/
-function sanitise_int($int) {
+function sanitise_int($int, $signed = true) {
+ $int = (int) $int;
+
+ if ($signed === false) {
+ if ($int < 0) {
+ $int = 0;
+ }
+ }
+
return (int) $int;
}
/**
- * Wrapper function for alternate English spelling
- *
- * @param int $int Integer
+ * Sanitizes an integer for database use.
+ * Wrapper function for alternate English spelling (@see sanitise_int)
*
- * @return int Sanitised integer
+ * @param int $int Value to be sanitized
+ * @param bool $signed Whether negative values should be allowed (true)
+ * @return int
*/
-function sanitize_int($int) {
- return (int) $int;
+function sanitize_int($int, $signed = true) {
+ return sanitise_int($int, $signed);
}
/**
- * @elgg_register_event boot system init_db
+ * Registers shutdown functions for database profiling and delayed queries.
+ *
+ * @access private
*/
-elgg_register_event_handler('boot', 'system', 'init_db', 0);
+function init_db() {
+ register_shutdown_function('db_delayedexecution_shutdown_hook');
+ register_shutdown_function('db_profiling_shutdown_hook');
+}
+
+elgg_register_event_handler('init', 'system', 'init_db');
diff --git a/engine/lib/deprecated-1.7.php b/engine/lib/deprecated-1.7.php
index 519eea89d..ee95b5611 100644
--- a/engine/lib/deprecated-1.7.php
+++ b/engine/lib/deprecated-1.7.php
@@ -1137,6 +1137,7 @@ function make_register_object($register_name, $register_value, $children_array =
* @param int $guid GUID
*
* @return 1
+ * @deprecated 1.7
*/
function delete_object_entity($guid) {
system_message(elgg_echo('deprecatedfunction', array('delete_user_entity')));
@@ -1154,6 +1155,7 @@ function delete_object_entity($guid) {
* @param int $guid User GUID
*
* @return 1
+ * @deprecated 1.7
*/
function delete_user_entity($guid) {
system_message(elgg_echo('deprecatedfunction', array('delete_user_entity')));
diff --git a/engine/lib/deprecated-1.8.php b/engine/lib/deprecated-1.8.php
index 165546d31..91068d047 100644
--- a/engine/lib/deprecated-1.8.php
+++ b/engine/lib/deprecated-1.8.php
@@ -1,20 +1,106 @@
<?php
/**
- * @return str
+ * ***************************************************************************
+ * NOTE: If this is ever removed from Elgg, sites lose the ability to upgrade
+ * from 1.7.x and earlier to the latest version of Elgg without upgrading to
+ * 1.8 first.
+ * ***************************************************************************
+ *
+ * Upgrade the database schema in an ordered sequence.
+ *
+ * Executes all upgrade files in elgg/engine/schema/upgrades/ in sequential order.
+ * Upgrade files must be in the standard Elgg release format of YYYYMMDDII.sql
+ * where II is an incrementor starting from 01.
+ *
+ * Files that are < $version will be ignored.
+ *
+ * @warning Plugin authors should not call this function directly.
+ *
+ * @param int $version The version you are upgrading from in the format YYYYMMDDII.
+ * @param string $fromdir Optional directory to load upgrades from. default: engine/schema/upgrades/
+ * @param bool $quiet If true, suppress all error messages. Only use for the upgrade from <=1.6.
+ *
+ * @return int The number of upgrades run.
+ * @see upgrade.php
+ * @see version.php
+ * @deprecated 1.8 Use PHP upgrades for sql changes.
+ */
+function db_upgrade($version, $fromdir = "", $quiet = FALSE) {
+ global $CONFIG;
+
+ elgg_deprecated_notice('db_upgrade() is deprecated by using PHP upgrades.', 1.8);
+
+ $version = (int) $version;
+
+ if (!$fromdir) {
+ $fromdir = $CONFIG->path . 'engine/schema/upgrades/';
+ }
+
+ $i = 0;
+
+ if ($handle = opendir($fromdir)) {
+ $sqlupgrades = array();
+
+ while ($sqlfile = readdir($handle)) {
+ if (!is_dir($fromdir . $sqlfile)) {
+ if (preg_match('/^([0-9]{10})\.(sql)$/', $sqlfile, $matches)) {
+ $sql_version = (int) $matches[1];
+ if ($sql_version > $version) {
+ $sqlupgrades[] = $sqlfile;
+ }
+ }
+ }
+ }
+
+ asort($sqlupgrades);
+
+ if (sizeof($sqlupgrades) > 0) {
+ foreach ($sqlupgrades as $sqlfile) {
+
+ // hide all errors.
+ if ($quiet) {
+ try {
+ run_sql_script($fromdir . $sqlfile);
+ } catch (DatabaseException $e) {
+ error_log($e->getmessage());
+ }
+ } else {
+ run_sql_script($fromdir . $sqlfile);
+ }
+ $i++;
+ }
+ }
+ }
+
+ return $i;
+}
+
+/**
+ * Lists entities from an access collection
+ *
* @deprecated 1.8 Use elgg_list_entities_from_access_id()
+ *
+ * @return str
*/
function list_entities_from_access_id($access_id, $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $listtypetoggle = true, $pagination = true) {
elgg_deprecated_notice("All list_entities* functions were deprecated in 1.8. Use elgg_list_entities* instead.", 1.8);
echo elgg_list_entities_from_access_id(array('access_id' => $access_id,
- 'types' => $entity_type, 'subtypes' => $entity_subtype, 'owner_guids' => $owner_guid,
+ 'type' => $entity_type, 'subtype' => $entity_subtype, 'owner_guids' => $owner_guid,
'limit' => $limit, 'full_view' => $fullview, 'list_type_toggle' => $listtypetoggle,
'pagination' => $pagination,));
}
/**
+ * Registers a particular action in memory
+ *
* @deprecated 1.8 Use {@link elgg_register_action()} instead
+ *
+ * @param string $action The name of the action (eg "register", "account/settings/save")
+ * @param boolean $public Can this action be accessed by people not logged into the system?
+ * @param string $filename Optionally, the filename where this action is located
+ * @param boolean $admin_only Whether this action is only available to admin users.
*/
function register_action($action, $public = false, $filename = "", $admin_only = false) {
elgg_deprecated_notice("register_action() was deprecated by elgg_register_action()", 1.8);
@@ -35,6 +121,8 @@ function register_action($action, $public = false, $filename = "", $admin_only =
* This function extends the view "admin/main" with the provided view.
* This view should provide a description and either a control or a link to.
*
+ * @deprecated 1.8 Extend admin views manually
+ *
* Usage:
* - To add a control to the main admin panel then extend admin/main
* - To add a control to a new page create a page which renders a view admin/subpage
@@ -48,8 +136,6 @@ function register_action($action, $public = false, $filename = "", $admin_only =
* @param string $view The view to extend, by default this is 'admin/main'.
* @param int $priority Optional priority to govern the appearance in the list.
*
- * @deprecated 1.8 Extend admin views manually
- *
* @return void
*/
function extend_elgg_admin_page($new_admin_view, $view = 'admin/main', $priority = 500) {
@@ -115,7 +201,7 @@ function get_entities_from_annotations_calculate_x($sum = "sum", $entity_type =
$options['limit'] = $limit;
$options['offset'] = $offset;
- $options['order_by'] = "calculated $orderdir";
+ $options['order_by'] = "annotation_calculation $orderdir";
$options['count'] = $count;
@@ -125,6 +211,12 @@ function get_entities_from_annotations_calculate_x($sum = "sum", $entity_type =
/**
* Returns entities ordered by the sum of an annotation
*
+ * @warning This is function uses sum instead of count. THIS IS SLOW. See #3366.
+ * This should be used when you have annotations with different values and you
+ * want a list of entities ordered by the sum of all of those values.
+ * If you want a list of entities ordered by the number of annotations on each entity,
+ * use __get_entities_from_annotations_calculate_x() and pass 'count' as the first param.
+ *
* @deprecated 1.8 Use elgg_get_entities_from_annotation_calculation()
*
* @param string $entity_type Type of Entity
@@ -179,7 +271,7 @@ function get_entities_from_annotation_count($entity_type = "", $entity_subtype =
$options['limit'] = $limit;
$options['offset'] = $offset;
- $options['order_by'] = "calculated $orderdir";
+ $options['order_by'] = "annotation_calculation $orderdir";
$options['count'] = $count;
@@ -241,7 +333,7 @@ function list_entities_from_annotation_count($entity_type = "", $entity_subtype
$options['limit'] = $limit;
- $options['order_by'] = "calculated $orderdir";
+ $options['order_by'] = "annotation_calculation $orderdir";
return elgg_get_entities_from_annotation_calculation($options);
}
@@ -249,6 +341,8 @@ function list_entities_from_annotation_count($entity_type = "", $entity_subtype
/**
* Adds an entry in $CONFIG[$register_name][$subregister_name].
*
+ * @deprecated 1.8 Use the new menu system.
+ *
* This is only used for the site-wide menu. See {@link add_menu()}.
*
* @param string $register_name The name of the top-level register
@@ -257,7 +351,6 @@ function list_entities_from_annotation_count($entity_type = "", $entity_subtype
* @param array $children_array Optionally, an array of children
*
* @return true|false Depending on success
- * @deprecated 1.8
*/
function add_to_register($register_name, $subregister_name, $subregister_value, $children_array = array()) {
elgg_deprecated_notice("add_to_register() has been deprecated", 1.8);
@@ -290,6 +383,8 @@ function add_to_register($register_name, $subregister_name, $subregister_value,
/**
* Removes a register entry from $CONFIG[register_name][subregister_name]
*
+ * @deprecated 1.8 Use the new menu system.
+ *
* This is used to by {@link remove_menu()} to remove site-wide menu items.
*
* @param string $register_name The name of the top-level register
@@ -297,7 +392,6 @@ function add_to_register($register_name, $subregister_name, $subregister_value,
*
* @return true|false Depending on success
* @since 1.7.0
- * @deprecated 1.8
*/
function remove_from_register($register_name, $subregister_name) {
elgg_deprecated_notice("remove_from_register() has been deprecated", 1.8);
@@ -326,10 +420,11 @@ function remove_from_register($register_name, $subregister_name) {
/**
* If it exists, returns a particular register as an array
*
+ * @deprecated 1.8 Use the new menu system
+ *
* @param string $register_name The name of the register
*
* @return array|false Depending on success
- * @deprecated 1.8
*/
function get_register($register_name) {
elgg_deprecated_notice("get_register() has been deprecated", 1.8);
@@ -363,6 +458,8 @@ function get_register($register_name) {
* Deprecated events core function. Code divided between elgg_register_event_handler()
* and trigger_elgg_event().
*
+ * @deprecated 1.8 Use explicit register/trigger event functions
+ *
* @param string $event The type of event (eg 'init', 'update', 'delete')
* @param string $object_type The type of object (eg 'system', 'blog', 'user')
* @param string $function The name of the function that will handle the event
@@ -371,7 +468,6 @@ function get_register($register_name) {
* @param mixed $object Optionally, the object the event is being performed on (eg a user)
*
* @return true|false Depending on success
- * @deprecated 1.8 Use explicit register/trigger event functions
*/
function events($event = "", $object_type = "", $function = "", $priority = 500, $call = false, $object = null) {
@@ -386,7 +482,14 @@ function events($event = "", $object_type = "", $function = "", $priority = 500,
}
/**
+ * Alias function for events, that registers a function to a particular kind of event
+ *
* @deprecated 1.8 Use elgg_register_event_handler() instead
+ *
+ * @param string $event The event type
+ * @param string $object_type The object type
+ * @param string $function The function name
+ * @return true|false Depending on success
*/
function register_elgg_event_handler($event, $object_type, $callback, $priority = 500) {
elgg_deprecated_notice("register_elgg_event_handler() was deprecated by elgg_register_event_handler()", 1.8);
@@ -394,7 +497,14 @@ function register_elgg_event_handler($event, $object_type, $callback, $priority
}
/**
+ * Unregisters a function to a particular kind of event
+ *
* @deprecated 1.8 Use elgg_unregister_event_handler instead
+ *
+ * @param string $event The event type
+ * @param string $object_type The object type
+ * @param string $function The function name
+ * @since 1.7.0
*/
function unregister_elgg_event_handler($event, $object_type, $callback) {
elgg_deprecated_notice('unregister_elgg_event_handler => elgg_unregister_event_handler', 1.8);
@@ -402,7 +512,14 @@ function unregister_elgg_event_handler($event, $object_type, $callback) {
}
/**
+ * Alias function for events, that triggers a particular kind of event
+ *
* @deprecated 1.8 Use elgg_trigger_event() instead
+ *
+ * @param string $event The event type
+ * @param string $object_type The object type
+ * @param string $function The function name
+ * @return true|false Depending on success
*/
function trigger_elgg_event($event, $object_type, $object = null) {
elgg_deprecated_notice('trigger_elgg_event() was deprecated by elgg_trigger_event()', 1.8);
@@ -410,7 +527,29 @@ function trigger_elgg_event($event, $object_type, $object = null) {
}
/**
+ * Register a function to a plugin hook for a particular entity type, with a given priority.
+ *
* @deprecated 1.8 Use elgg_register_plugin_hook_handler() instead
+ *
+ * eg if you want the function "export_user" to be called when the hook "export" for "user" entities
+ * is run, use:
+ *
+ * register_plugin_hook("export", "user", "export_user");
+ *
+ * "all" is a valid value for both $hook and $entity_type. "none" is a valid value for $entity_type.
+ *
+ * The export_user function would then be defined as:
+ *
+ * function export_user($hook, $entity_type, $returnvalue, $params);
+ *
+ * Where $returnvalue is the return value returned by the last function returned by the hook, and
+ * $params is an array containing a set of parameters (or nothing).
+ *
+ * @param string $hook The name of the hook
+ * @param string $entity_type The name of the type of entity (eg "user", "object" etc)
+ * @param string $function The name of a valid function to be run
+ * @param string $priority The priority - 0 is first, 1000 last, default is 500
+ * @return true|false Depending on success
*/
function register_plugin_hook($hook, $type, $callback, $priority = 500) {
elgg_deprecated_notice("register_plugin_hook() was deprecated by elgg_register_plugin_hook_handler()", 1.8);
@@ -418,7 +557,14 @@ function register_plugin_hook($hook, $type, $callback, $priority = 500) {
}
/**
+ * Unregister a function to a plugin hook for a particular entity type
+ *
* @deprecated 1.8 Use elgg_unregister_plugin_hook_handler() instead
+ *
+ * @param string $hook The name of the hook
+ * @param string $entity_type The name of the type of entity (eg "user", "object" etc)
+ * @param string $function The name of a valid function to be run
+ * @since 1.7.0
*/
function unregister_plugin_hook($hook, $entity_type, $callback) {
elgg_deprecated_notice("unregister_plugin_hook() was deprecated by elgg_unregister_plugin_hook_handler()", 1.8);
@@ -426,7 +572,20 @@ function unregister_plugin_hook($hook, $entity_type, $callback) {
}
/**
+ * Triggers a plugin hook, with various parameters as an array. For example, to provide
+ * a 'foo' hook that concerns an entity of type 'bar', with a parameter called 'param1'
+ * with value 'value1', that by default returns true, you'd call:
+ *
* @deprecated 1.8 Use elgg_trigger_plugin_hook() instead
+ *
+ * trigger_plugin_hook('foo', 'bar', array('param1' => 'value1'), true);
+ *
+ * @see register_plugin_hook
+ * @param string $hook The name of the hook to trigger
+ * @param string $entity_type The name of the entity type to trigger it for (or "all", or "none")
+ * @param array $params Any parameters. It's good practice to name the keys, i.e. by using array('name' => 'value', 'name2' => 'value2')
+ * @param mixed $returnvalue An initial return value
+ * @return mixed|null The cumulative return value for the plugin hook functions
*/
function trigger_plugin_hook($hook, $type, $params = null, $returnvalue = null) {
elgg_deprecated_notice("trigger_plugin_hook() was deprecated by elgg_trigger_plugin_hook()", 1.8);
@@ -987,7 +1146,7 @@ function get_entities_from_metadata_groups_multi($group_guid, $meta_array, $enti
* @param bool $navigation Display pagination? Default: true
*
* @return string A viewable list of entities
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_get_entities_from_location()
*/
function list_entities_in_area($lat, $long, $radius, $type = "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $listtypetoggle = false, $navigation = true) {
elgg_deprecated_notice('list_entities_in_area() was deprecated. Use elgg_list_entities_from_location()', 1.8);
@@ -1036,7 +1195,7 @@ function list_entities_in_area($lat, $long, $radius, $type = "", $subtype = "",
* @param bool $navigation Display pagination? Default: true
*
* @return string A viewable list of entities
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_list_entities_from_location()
*/
function list_entities_location($location, $type = "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $listtypetoggle = false, $navigation = true) {
elgg_deprecated_notice('list_entities_location() was deprecated. Use elgg_list_entities_from_metadata()', 1.8);
@@ -1061,7 +1220,7 @@ function list_entities_location($location, $type = "", $subtype = "", $owner_gui
* @param int|array $container_guid Container GUID
*
* @return array A list of entities.
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_get_entities_from_location()
*/
function get_entities_in_area($lat, $long, $radius, $type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = NULL) {
elgg_deprecated_notice('get_entities_in_area() was deprecated by elgg_get_entities_from_location()!', 1.8);
@@ -1152,10 +1311,22 @@ function list_entities_from_metadata($meta_name, $meta_value = "", $entity_type
$offset = (int)get_input('offset');
$limit = (int)$limit;
- $options = array('metadata_name' => $meta_name, 'metadata_value' => $meta_value,
- 'types' => $entity_type, 'subtypes' => $entity_subtype, 'owner_guid' => $owner_guid,
- 'limit' => $limit, 'offset' => $offset, 'count' => TRUE,
- 'metadata_case_sensitive' => $case_sensitive);
+ $options = array(
+ 'metadata_name' => $meta_name,
+ 'metadata_value' => $meta_value,
+ 'type' => $entity_type,
+ 'subtype' => $entity_subtype,
+ 'limit' => $limit,
+ 'offset' => $offset,
+ 'count' => TRUE,
+ 'metadata_case_sensitive' => $case_sensitive
+ );
+
+ // previous function allowed falsy $owner_guid for anything
+ if ($owner_guid) {
+ $options['owner_guid'] = $owner_guid;
+ }
+
$count = elgg_get_entities_from_metadata($options);
$options['count'] = FALSE;
@@ -1198,7 +1369,7 @@ function list_entities_from_metadata_multi($meta_array, $entity_type = "", $enti
* Deprecated by elgg_register_menu_item(). Set $menu_name to 'page'.
*
* @see elgg_register_menu_item()
- * @deprecated 1.8
+ * @deprecated 1.8 Use the new menu system
*
* @param string $label The label
* @param string $link The link
@@ -1240,7 +1411,7 @@ function add_submenu_item($label, $link, $group = 'default', $onclick = false, $
/**
* Remove an item from submenu by label
*
- * @deprecated 1.8
+ * @deprecated 1.8 Use the new menu system
* @see elgg_unregister_menu_item()
*
* @param string $label The item label
@@ -1258,7 +1429,7 @@ function remove_submenu_item($label, $group = 'a') {
* Use elgg_view_menu(). Set $menu_name to 'owner_block'.
*
* @see elgg_view_menu()
- * @deprecated 1.8
+ * @deprecated 1.8 Use the new menu system. elgg_view_menu()
*
* @return string
*/
@@ -1294,7 +1465,7 @@ function add_menu($menu_name, $menu_url, $menu_children = array(), $context = ""
* @param string $menu_name The name of the menu item
*
* @return true|false Depending on success
- * @deprecated 1.8
+ * @deprecated 1.8 Use the new menu system
*/
function remove_menu($menu_name) {
elgg_deprecated_notice("remove_menu() deprecated by elgg_unregister_menu_item()", 1.8);
@@ -1307,7 +1478,7 @@ function remove_menu($menu_name) {
* @param string $title The title
*
* @return string The optimised title
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_get_friendly_title()
*/
function friendly_title($title) {
elgg_deprecated_notice('friendly_title was deprecated by elgg_get_friendly_title', 1.8);
@@ -1320,7 +1491,7 @@ function friendly_title($title) {
* @param int $time A UNIX epoch timestamp
*
* @return string The friendly time
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_view_friendly_time()
*/
function friendly_time($time) {
elgg_deprecated_notice('friendly_time was deprecated by elgg_view_friendly_time', 1.8);
@@ -1330,7 +1501,7 @@ function friendly_time($time) {
/**
* Filters a string into an array of significant words
*
- * @deprecated 1.8
+ * @deprecated 1.8 Don't use this.
*
* @param string $string A string
*
@@ -1368,7 +1539,7 @@ function filter_string($string) {
/**
* Returns true if the word in $input is considered significant
*
- * @deprecated 1.8
+ * @deprecated 1.8 Don't use this.
*
* @param string $input A word
*
@@ -1405,7 +1576,7 @@ function page_owner() {
/**
* Gets the owner entity for the current page.
*
- * @deprecated 1.8 Use elgg_get_page_owner()
+ * @deprecated 1.8 Use elgg_get_page_owner_entity()
* @return ElggEntity|false The current page owner or false if none.
*/
function page_owner_entity() {
@@ -1474,7 +1645,7 @@ function get_context() {
/**
* Returns a list of plugins to load, in the order that they should be loaded.
*
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_get_plugin_ids_in_dir() or elgg_get_plugins()
*
* @return array List of plugins
*/
@@ -1503,9 +1674,9 @@ function get_plugin_list() {
* otherwise you may experience view display artifacts. Do this with the following code:
*
* elgg_regenerate_simplecache();
- * elgg_filepath_cache_reset();
+ * elgg_reset_system_cache();
*
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_generate_plugin_entities() and elgg_set_plugin_priorities()
*
* @param array $pluginorder Optionally, a list of existing plugins and their orders
*
@@ -1537,7 +1708,7 @@ function regenerate_plugin_list($pluginorder = FALSE) {
*
* i.e., if the last plugin was in /mod/foobar/, get_plugin_name would return foo_bar.
*
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_get_calling_plugin_id()
*
* @param boolean $mainfilename If set to true, this will instead determine the
* context from the main script filename called by
@@ -1556,7 +1727,7 @@ function get_plugin_name($mainfilename = false) {
*
* @example plugins/manifest.xml Example 1.8-style manifest file.
*
- * @deprecated 1.8
+ * @deprecated 1.8 Use ElggPlugin->getManifest()
*
* @param string $plugin Plugin name.
* @return array of values
@@ -1579,7 +1750,7 @@ function load_plugin_manifest($plugin) {
* This function checks a plugin manifest 'elgg_version' value against the current install
* returning TRUE if the elgg_version is >= the current install's version.
*
- * @deprecated 1.8
+ * @deprecated 1.8 Use ElggPlugin->canActivate()
*
* @param string $manifest_elgg_version_string The build version (eg 2009010201).
* @return bool
@@ -1602,7 +1773,7 @@ function check_plugin_compatibility($manifest_elgg_version_string) {
/**
* Shorthand function for finding the plugin settings.
*
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_get_calling_plugin_entity() or elgg_get_plugin_from_id()
*
* @param string $plugin_id Optional plugin id, if not specified
* then it is detected from where you are calling.
@@ -1621,7 +1792,7 @@ function find_plugin_settings($plugin_id = null) {
/**
* Return an array of installed plugins.
*
- * @deprecated 1.8
+ * @deprecated 1.8 use elgg_get_plugins()
*
* @param string $status any|enabled|disabled
* @return array
@@ -1655,7 +1826,7 @@ function get_installed_plugins($status = 'all') {
if ($include) {
$installed_plugins[$plugin->getID()] = array(
'active' => $plugin->isActive(),
- 'manifest' => $plugin->manifest->getManifest()
+ 'manifest' => $plugin->getManifest()->getManifest()
);
}
}
@@ -1670,9 +1841,9 @@ function get_installed_plugins($status = 'all') {
* otherwise you may experience view display artifacts. Do this with the following code:
*
* elgg_regenerate_simplecache();
- * elgg_filepath_cache_reset();
+ * elgg_reset_system_cache();
*
- * @deprecated 1.8
+ * @deprecated 1.8 Use ElggPlugin->activate()
*
* @param string $plugin The plugin name.
* @param int $site_guid The site id, if not specified then this is detected.
@@ -1711,9 +1882,9 @@ function enable_plugin($plugin, $site_guid = null) {
* otherwise you may experience view display artifacts. Do this with the following code:
*
* elgg_regenerate_simplecache();
- * elgg_filepath_cache_reset();
+ * elgg_reset_system_cache();
*
- * @deprecated 1.8
+ * @deprecated 1.8 Use ElggPlugin->deactivate()
*
* @param string $plugin The plugin name.
* @param int $site_guid The site id, if not specified then this is detected.
@@ -1744,7 +1915,7 @@ function disable_plugin($plugin, $site_guid = 0) {
/**
* Return whether a plugin is enabled or not.
*
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_is_active_plugin()
*
* @param string $plugin The plugin name.
* @param int $site_guid The site id, if not specified then this is detected.
@@ -1772,7 +1943,7 @@ function is_plugin_enabled($plugin, $site_guid = 0) {
* @param mixed $container_guid The container(s) GUIDs
*
* @return array A list of entities.
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_get_entities_from_private_settings()
*/
function get_entities_from_private_setting($name = "", $value = "", $type = "", $subtype = "",
$owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0,
@@ -1851,13 +2022,13 @@ $container_guid = null) {
* @param mixed $container_guid Container GUID
*
* @return array A list of entities.
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_get_entities_from_private_settings()
*/
function get_entities_from_private_setting_multi(array $name, $type = "", $subtype = "",
$owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false,
$site_guid = 0, $container_guid = null) {
- elgg_deprecated_notice('get_entities_from_private_setting_multi() was deprecated by elgg_get_entities_from_private_setting()!', 1.8);
+ elgg_deprecated_notice('get_entities_from_private_setting_multi() was deprecated by elgg_get_entities_from_private_settings()!', 1.8);
$options = array();
@@ -1949,8 +2120,8 @@ $fullview = true, $listtypetoggle = false, $pagination = true, $order_by = '') {
'relationship' => $relationship,
'relationship_guid' => $relationship_guid,
'inverse_relationship' => $inverse_relationship,
- 'types' => $type,
- 'subtypes' => $subtype,
+ 'type' => $type,
+ 'subtype' => $subtype,
'owner_guid' => $owner_guid,
'order_by' => $order_by,
'limit' => $limit,
@@ -2023,7 +2194,7 @@ $subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $count = false, $site_
/**
* Displays a human-readable list of entities
*
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_list_entities_from_relationship_count()
*
* @param string $relationship The relationship eg "friends_of"
* @param bool $inverse_relationship Inverse relationship owners
@@ -2074,7 +2245,7 @@ $listtypetoggle = false, $pagination = true) {
* Gets the number of entities by a the number of entities related to
* them in a particular way also constrained by metadata.
*
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_get_entities_from_relationship()
*
* @param string $relationship The relationship eg "friends_of"
* @param int $relationship_guid The guid of the entity to use query
@@ -2166,7 +2337,7 @@ $subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $count = false, $site_
* @param int $posted_max The maximum time period to look at. Default: none
*
* @return array|false Depending on success
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_get_river()
*/
function get_river_items($subject_guid = 0, $object_guid = 0, $subject_relationship = '',
$type = '', $subtype = '', $action_type = '', $limit = 20, $offset = 0, $posted_min = 0,
@@ -2233,7 +2404,7 @@ $posted_max = 0) {
* @param bool $pagination Show pagination?
*
* @return string Human-readable river.
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_list_river()
*/
function elgg_view_river_items($subject_guid = 0, $object_guid = 0, $subject_relationship = '',
$type = '', $subtype = '', $action_type = '', $limit = 20, $posted_min = 0,
@@ -2253,7 +2424,7 @@ $posted_max = 0, $pagination = true) {
'offset' => $offset,
'limit' => $limit,
'pagination' => $pagination,
- 'list-class' => 'elgg-river-list',
+ 'list-class' => 'elgg-list-river',
);
return elgg_view('page/components/list', $params);
@@ -2262,7 +2433,8 @@ $posted_max = 0, $pagination = true) {
/**
* Construct and execute the query required for the activity stream.
*
- * @deprecated 1.8
+ * @deprecated 1.8 This is outdated and uses the systemlog table instead of the river table.
+ * Don't use it.
*/
function get_activity_stream_data($limit = 10, $offset = 0, $type = "", $subtype = "",
$owner_guid = "", $owner_relationship = "") {
@@ -2394,9 +2566,9 @@ $owner_guid = "", $owner_relationship = "") {
'relationship' => $owner_relationship,
'relationship_guid' => $owner_guid[0],
'inverse_relationship' => FALSE,
- 'types' => 'user',
- 'subtypes' => $subtype,
- 'limit' => 9999))
+ 'type' => 'user',
+ 'subtype' => $subtype,
+ 'limit' => false))
) {
$friendsarray = array();
@@ -2497,7 +2669,7 @@ function list_site_members($site_guid, $limit = 10, $fullview = true) {
* @param int $collection_guid Collection GUID
*
* @return mixed
- * @deprecated 1.8
+ * @deprecated 1.8 Don't use this.
*/
function add_site_collection($site_guid, $collection_guid) {
elgg_deprecated_notice("add_site_collection has been deprecated", 1.8);
@@ -2516,7 +2688,7 @@ function add_site_collection($site_guid, $collection_guid) {
* @param int $collection_guid Collection GUID
*
* @return mixed
- * @deprecated 1.8
+ * @deprecated 1.8 Don't use this.
*/
function remove_site_collection($site_guid, $collection_guid) {
elgg_deprecated_notice("remove_site_collection has been deprecated", 1.8);
@@ -2535,7 +2707,7 @@ function remove_site_collection($site_guid, $collection_guid) {
* @param int $offset Offset
*
* @return mixed
- * @deprecated 1.8
+ * @deprecated 1.8 Don't use this.
*/
function get_site_collections($site_guid, $subtype = "", $limit = 10, $offset = 0) {
elgg_deprecated_notice("get_site_collections has been deprecated", 1.8);
@@ -2549,8 +2721,8 @@ function get_site_collections($site_guid, $subtype = "", $limit = 10, $offset =
'relationship' => 'member_of_site',
'relationship_guid' => $site_guid,
'inverse_relationship' => TRUE,
- 'types' => 'collection',
- 'subtypes' => $subtype,
+ 'type' => 'collection',
+ 'subtype' => $subtype,
'limit' => $limit,
'offset' => $offset
));
@@ -2773,7 +2945,7 @@ $limit = 0, $offset = 0) {
* @param bool $status Validated (true) or false
* @param string $method Optional method to say how a user was validated
* @return bool
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_set_user_validation_status()
*/
function set_user_validation_status($user_guid, $status, $method = '') {
elgg_deprecated_notice("set_user_validation_status() is deprecated", 1.8);
@@ -2786,7 +2958,7 @@ function set_user_validation_status($user_guid, $status, $method = '') {
* This function invalidates any existing validation value.
*
* @param int $user_guid User's GUID
- * @deprecated 1.8
+ * @deprecated 1.8 Hook into the register, user plugin hook and request validation.
*/
function request_user_validation($user_guid) {
elgg_deprecated_notice("request_user_validation() is deprecated.
@@ -2832,6 +3004,13 @@ $priority = 500) {
}
/**
+ * Returns a representation of a full 'page' (which might be an HTML page,
+ * RSS file, etc, depending on the current viewtype)
+ *
+ * @param string $title
+ * @param string $body
+ * @return string
+ *
* @deprecated 1.8 Use elgg_view_page()
*/
function page_draw($title, $body, $sidebar = "") {
@@ -3136,7 +3315,7 @@ function clear_all_plugin_settings($plugin_id = "") {
* @param int $entity_owner_guid Owner guid for the entity
*
* @return array
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_get_annotations()
*/
function get_annotations($entity_guid = 0, $entity_type = "", $entity_subtype = "", $name = "",
$value = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "asc", $timelower = 0,
@@ -3201,7 +3380,7 @@ $timeupper = 0, $entity_owner_guid = 0) {
* @param true|false $asc Display annotations in ascending order. (Default: true)
*
* @return string HTML (etc) version of the annotation list
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_list_annotations()
*/
function list_annotations($entity_guid, $name = "", $limit = 25, $asc = true) {
elgg_deprecated_notice('list_annotations() is deprecated by elgg_list_annotations()', 1.8);
@@ -3234,7 +3413,8 @@ function list_annotations($entity_guid, $name = "", $limit = 25, $asc = true) {
* @param unknown_type $timelower
* @param unknown_type $timeupper
* @param unknown_type $calculation
- * @deprecated 1.8
+ * @internal Don't use this at all.
+ * @deprecated 1.8 Use elgg_get_annotations()
*/
function elgg_deprecated_annotation_calculation($entity_guid = 0, $entity_type = "", $entity_subtype = "",
$name = "", $value = "", $value_type = "", $owner_guid = 0, $timelower = 0,
@@ -3412,7 +3592,7 @@ $value = "", $value_type = "", $owner_guid = 0) {
* @param int $timeupper Upper time limit
*
* @return int
- * @deprecated 1.8
+ * @deprecated 1.8 Use elgg_get_annotations() and pass anntoation_calculation => <calculation>
*/
function get_annotations_calculate_x($sum = "avg", $entity_guid, $entity_type = "",
$entity_subtype = "", $name = "", $value = "", $value_type = "", $owner_guid = 0,
@@ -3492,14 +3672,18 @@ $asc = false, $fullview = true, $listtypetoggle = false, $pagination = true, $or
$options['limit'] = $limit;
- $options['order_by'] = "calculated $orderdir";
+ $options['order_by'] = "annotation_calculation $orderdir";
return elgg_get_entities_from_annotation_calculation($options);
}
/**
- * @deprecated 1.8
- * @see elgg_set_view_location()
+ * Set an alternative base location for a view (as opposed to the default of $CONFIG->viewpath)
+ *
+ * @param string $view The name of the view
+ * @param string $location The base location path
+ *
+ * @deprecated 1.8 Use elgg_set_view_location()
*/
function set_view_location($view, $location, $viewtype = '') {
elgg_deprecated_notice("set_view_location() was deprecated by elgg_set_view_location()", 1.8);
@@ -3507,8 +3691,14 @@ function set_view_location($view, $location, $viewtype = '') {
}
/**
- * @deprecated 1.8
- * @see elgg_register_entity_url_handler()
+ * Sets the URL handler for a particular entity type and subtype
+ *
+ * @param string $function_name The function to register
+ * @param string $entity_type The entity type
+ * @param string $entity_subtype The entity subtype
+ * @return true|false Depending on success
+ *
+ * @deprecated 1.8 Use elgg_register_entity_url_handler()
*/
function register_entity_url_handler($function_name, $entity_type = "all", $entity_subtype = "all") {
elgg_deprecated_notice("register_entity_url_handler() was deprecated by elgg_register_entity_url_handler()", 1.8);
@@ -3795,6 +3985,27 @@ function clear_annotations_by_owner($owner_guid) {
}
/**
+ * Registers a page handler for a particular identifier
+ *
+ * For example, you can register a function called 'blog_page_handler' for handler type 'blog'
+ * Now for all URLs of type http://yoururl/pg/blog/*, the blog_page_handler() function will be called.
+ * The part of the URL marked with * above will be exploded on '/' characters and passed as an
+ * array to that function.
+ * For example, the URL http://yoururl/blog/username/friends/ would result in the call:
+ * blog_page_handler(array('username','friends'), blog);
+ *
+ * Page handler functions should return true or the default page handler will be called.
+ *
+ * A request to register a page handler with the same identifier as previously registered
+ * handler will replace the previous one.
+ *
+ * The context is set to the page handler identifier before the registered
+ * page handler function is called. For the above example, the context is set to 'blog'.
+ *
+ * @param string $handler The page type to handle
+ * @param string $function Your function name
+ * @return true|false Depending on success
+ *
* @deprecated 1.8 Use {@link elgg_register_page_handler()}
*/
function register_page_handler($handler, $function){
@@ -3803,6 +4014,13 @@ function register_page_handler($handler, $function){
}
/**
+ * Unregister a page handler for an identifier
+ *
+ * Note: to replace a page handler, call register_page_handler()
+ *
+ * @param string $handler The page type identifier
+ * @since 1.7.2
+ *
* @deprecated 1.8 Use {@link elgg_unregister_page_handler()}
*/
function unregister_page_handler($handler) {
@@ -3811,6 +4029,11 @@ function unregister_page_handler($handler) {
}
/**
+ * Register an annotation url handler.
+ *
+ * @param string $function_name The function.
+ * @param string $extender_name The name, default 'all'.
+ *
* @deprecated 1.8 Use {@link elgg_register_annotation_url_handler()}
*/
function register_annotation_url_handler($function, $extender_name) {
@@ -3819,6 +4042,15 @@ function register_annotation_url_handler($function, $extender_name) {
}
/**
+ * Sets the URL handler for a particular extender type and name.
+ * It is recommended that you do not call this directly, instead use one of the wrapper functions in the
+ * subtype files.
+ *
+ * @param string $function_name The function to register
+ * @param string $extender_type Extender type
+ * @param string $extender_name The name of the extender
+ * @return true|false Depending on success
+ *
* @deprecated 1.8 Use {@link elgg_register_extender_url_handler()}
*/
function register_extender_url_handler($function, $type = "all", $name = "all") {
@@ -3827,6 +4059,14 @@ function register_extender_url_handler($function, $type = "all", $name = "all")
}
/**
+ * Registers and entity type and subtype to return in search and other places.
+ * A description in the elgg_echo languages file of the form item:type:subtype
+ * is also expected.
+ *
+ * @param string $type The type of entity (object, site, user, group)
+ * @param string $subtype The subtype to register (may be blank)
+ * @return true|false Depending on success
+ *
* @deprecated 1.8 Use {@link elgg_register_entity_type()}
*/
function register_entity_type($type, $subtype = null) {
@@ -3835,6 +4075,11 @@ function register_entity_type($type, $subtype = null) {
}
/**
+ * Register a metadata url handler.
+ *
+ * @param string $function_name The function.
+ * @param string $extender_name The name, default 'all'.
+ *
* @deprecated 1.8 Use {@link elgg_register_metadata_url_handler()}
*/
function register_metadata_url_handler($function, $extender_name = "all") {
@@ -3842,7 +4087,12 @@ function register_metadata_url_handler($function, $extender_name = "all") {
}
/**
+ * Sets the URL handler for a particular relationship type
*
+ * @param string $function_name The function to register
+ * @param string $relationship_type The relationship type.
+ * @return true|false Depending on success
+ *
* @deprecated 1.8 Use {@link elgg_register_relationship_url_handler()}
*/
function register_relationship_url_handler($function_name, $relationship_type = "all") {
@@ -3851,6 +4101,15 @@ function register_relationship_url_handler($function_name, $relationship_type =
}
/**
+ * Registers a view to be simply cached
+ *
+ * Views cached in this manner must take no parameters and be login agnostic -
+ * that is to say, they look the same no matter who is logged in (or logged out).
+ *
+ * CSS and the basic jS views are automatically cached like this.
+ *
+ * @param string $viewname View name
+ *
* @deprecated 1.8 Use {@link elgg_register_simplecache_view()}
*/
function elgg_view_register_simplecache($viewname) {
@@ -3859,6 +4118,11 @@ function elgg_view_register_simplecache($viewname) {
}
/**
+ * Regenerates the simple cache.
+ *
+ * @param string $viewtype Optional viewtype to regenerate
+ * @see elgg_view_register_simplecache()
+ *
* @deprecated 1.8 Use {@link elgg_regenerate_simplecache()}
*/
function elgg_view_regenerate_simplecache($viewtype = NULL) {
@@ -3867,6 +4131,10 @@ function elgg_view_regenerate_simplecache($viewtype = NULL) {
}
/**
+ * Enables the simple cache.
+ *
+ * @see elgg_view_register_simplecache()
+ *
* @deprecated 1.8 Use {@link elgg_enable_simplecache()}
*/
function elgg_view_enable_simplecache() {
@@ -3875,6 +4143,10 @@ function elgg_view_enable_simplecache() {
}
/**
+ * Disables the simple cache.
+ *
+ * @see elgg_view_register_simplecache()
+ *
* @deprecated 1.8 Use {@link elgg_disable_simplecache()}
*/
function elgg_view_disable_simplecache() {
@@ -3900,6 +4172,22 @@ function is_installed() {
}
/**
+ * Attempt to authenticate.
+ * This function will process all registered PAM handlers or stop when the first
+ * handler fails. A handler fails by either returning false or throwing an
+ * exception. The advantage of throwing an exception is that it returns a message
+ * through the global $_PAM_HANDLERS_MSG which can be used in communication with
+ * a user. The order that handlers are processed is determined by the order that
+ * they were registered.
+ *
+ * If $credentials are provided the PAM handler should authenticate using the
+ * provided credentials, if not then credentials should be prompted for or
+ * otherwise retrieved (eg from the HTTP header or $_SESSION).
+ *
+ * @param mixed $credentials Mixed PAM handler specific credentials (e.g. username, password)
+ * @param string $policy - the policy type, default is "user"
+ * @return bool true if authenticated, false if not.
+ *
* @deprecated 1.8 See {@link ElggPAM}
*/
function pam_authenticate($credentials = NULL, $policy = "user") {
@@ -4215,7 +4503,7 @@ function save_widget_info($widget_guid, $params) {
* @param int $owner Owner guid
*
* @return void
- * @deprecated 1.8
+ * @deprecated 1.8 Don't use.
*/
function reorder_widgets_from_panel($panelstring1, $panelstring2, $panelstring3, $context, $owner) {
elgg_deprecated_notice("reorder_widgets_from_panel() is deprecated", 1.8);
@@ -4323,7 +4611,7 @@ function reorder_widgets_from_panel($panelstring1, $panelstring2, $panelstring3,
* @param string $context The context we wish to enable context for
*
* @return void
- * @deprecated 1.8
+ * @deprecated 1.8 Don't use.
*/
function use_widgets($context) {
elgg_deprecated_notice("use_widgets is deprecated", 1.8);
@@ -4346,7 +4634,7 @@ function use_widgets($context) {
* Determines whether or not the current context is using widgets
*
* @return bool Depending on widget status
- * @deprecated 1.8
+ * @deprecated 1.8 Don't use.
*/
function using_widgets() {
elgg_deprecated_notice("using_widgets is deprecated", 1.8);
@@ -4363,99 +4651,170 @@ function using_widgets() {
}
/**
- * @deprecated 1.8
+ * Displays a particular widget
+ *
+ * @param ElggObject $widget The widget to display
+ * @return string The HTML for the widget, including JavaScript wrapper
+ *
+ * @deprecated 1.8 Use elgg_view_entity()
*/
function display_widget(ElggObject $widget) {
elgg_deprecated_notice("display_widget() was been deprecated. Use elgg_view_entity().", 1.8);
return elgg_view_entity($widget);
}
+/**
+ * Count the number of comments attached to an entity
+ *
+ * @param ElggEntity $entity
+ * @return int Number of comments
+ * @deprecated 1.8 Use ElggEntity->countComments()
+ */
+function elgg_count_comments($entity) {
+ elgg_deprecated_notice('elgg_count_comments() is deprecated by ElggEntity->countComments()', 1.8);
+
+ if ($entity instanceof ElggEntity) {
+ return $entity->countComments();
+ }
+
+ return 0;
+}
/**
- * ***************************************************************************
- * NOTE: If this is ever removed from Elgg, sites lose the ability to upgrade
- * from 1.7.x and earlier to the latest version of Elgg without upgrading to
- * 1.8 first.
- * ***************************************************************************
+ * Removes all items relating to a particular acting entity from the river
*
- * Upgrade the database schema in an ordered sequence.
+ * @param int $subject_guid The GUID of the entity
*
- * Executes all upgrade files in elgg/engine/schema/upgrades/ in sequential order.
- * Upgrade files must be in the standard Elgg release format of YYYYMMDDII.sql
- * where II is an incrementor starting from 01.
+ * @return bool Depending on success
+ * @deprecated 1.8 Use elgg_delete_river()
+ */
+function remove_from_river_by_subject($subject_guid) {
+ elgg_deprecated_notice("remove_from_river_by_subject() deprecated by elgg_delete_river()", 1.8);
+
+ return elgg_delete_river(array('subject_guid' => $subject_guid));
+}
+
+/**
+ * Removes all items relating to a particular entity being acted upon from the river
*
- * Files that are < $version will be ignored.
+ * @param int $object_guid The GUID of the entity
*
- * @warning Plugin authors should not call this function directly.
+ * @return bool Depending on success
+ * @deprecated 1.8 Use elgg_delete_river()
+ */
+function remove_from_river_by_object($object_guid) {
+ elgg_deprecated_notice("remove_from_river_by_object() deprecated by elgg_delete_river()", 1.8);
+
+ return elgg_delete_river(array('object_guid' => $object_guid));
+}
+
+/**
+ * Removes all items relating to a particular annotation being acted upon from the river
*
- * @param int $version The version you are upgrading from in the format YYYYMMDDII.
- * @param string $fromdir Optional directory to load upgrades from. default: engine/schema/upgrades/
- * @param bool $quiet If true, suppress all error messages. Only use for the upgrade from <=1.6.
+ * @param int $annotation_id The ID of the annotation
*
- * @return bool
- * @see upgrade.php
- * @see version.php
- * @deprecated 1.8 Use PHP upgrades for sql changes.
+ * @return bool Depending on success
+ * @since 1.7.0
+ * @deprecated 1.8 Use elgg_delete_river()
*/
-function db_upgrade($version, $fromdir = "", $quiet = FALSE) {
- global $CONFIG;
+function remove_from_river_by_annotation($annotation_id) {
+ elgg_deprecated_notice("remove_from_river_by_annotation() deprecated by elgg_delete_river()", 1.8);
- elgg_deprecated_notice('db_upgrade() is deprecated by using PHP upgrades.', 1.8);
+ return elgg_delete_river(array('annotation_id' => $annotation_id));
+}
- $version = (int) $version;
+/**
+ * Removes a single river entry
+ *
+ * @param int $id The ID of the river entry
+ *
+ * @return bool Depending on success
+ * @since 1.7.2
+ * @deprecated 1.8 Use elgg_delete_river()
+ */
+function remove_from_river_by_id($id) {
+ elgg_deprecated_notice("remove_from_river_by_id() deprecated by elgg_delete_river()", 1.8);
- if (!$fromdir) {
- $fromdir = $CONFIG->path . 'engine/schema/upgrades/';
- }
+ return elgg_delete_river(array('id' => $id));
+}
- if ($handle = opendir($fromdir)) {
- $sqlupgrades = array();
+/**
+ * A default page handler
+ * Tries to locate a suitable file to include. Only works for core pages, not plugins.
+ *
+ * @param array $page The page URL elements
+ * @param string $handler The base handler
+ *
+ * @return true|false Depending on success
+ * @deprecated 1.8
+ */
+function default_page_handler($page, $handler) {
+ global $CONFIG;
- while ($sqlfile = readdir($handle)) {
- if (!is_dir($fromdir . $sqlfile)) {
- if (preg_match('/^([0-9]{10})\.(sql)$/', $sqlfile, $matches)) {
- $sql_version = (int) $matches[1];
- if ($sql_version > $version) {
- $sqlupgrades[] = $sqlfile;
- }
- }
- }
- }
+ elgg_deprecated_notice("default_page_handler is deprecated", "1.8");
- asort($sqlupgrades);
+ $page = implode('/', $page);
- if (sizeof($sqlupgrades) > 0) {
- foreach ($sqlupgrades as $sqlfile) {
+ // protect against including arbitary files
+ $page = str_replace("..", "", $page);
- // hide all errors.
- if ($quiet) {
- try {
- run_sql_script($fromdir . $sqlfile);
- } catch (DatabaseException $e) {
- error_log($e->getmessage());
- }
- } else {
- run_sql_script($fromdir . $sqlfile);
- }
+ $callpath = $CONFIG->path . $handler . "/" . $page;
+ if (is_dir($callpath)) {
+ $callpath = sanitise_filepath($callpath);
+ $callpath .= "index.php";
+ if (file_exists($callpath)) {
+ if (include($callpath)) {
+ return TRUE;
}
}
+ } else if (file_exists($callpath)) {
+ include($callpath);
+ return TRUE;
}
- return TRUE;
+ return FALSE;
}
/**
- * Count the number of comments attached to an entity
+ * Invalidate this class's entry in the cache.
*
- * @param ElggEntity $entity
- * @return int Number of comments
+ * @param int $guid The entity guid
+ *
+ * @return void
+ * @access private
+ * @deprecated 1.8
*/
-function elgg_count_comments($entity) {
- elgg_deprecated_notice('elgg_count_comments() is deprecated by ElggEntity->countComments()', 1.8);
+function invalidate_cache_for_entity($guid) {
+ elgg_deprecated_notice('invalidate_cache_for_entity() is a private function and should not be used.', 1.8);
+ _elgg_invalidate_cache_for_entity($guid);
+}
- if ($entity instanceof ElggEntity) {
- return $entity->countComments();
- }
+/**
+ * Cache an entity.
+ *
+ * Stores an entity in $ENTITY_CACHE;
+ *
+ * @param ElggEntity $entity Entity to cache
+ *
+ * @return void
+ * @access private
+ * @deprecated 1.8
+ */
+function cache_entity(ElggEntity $entity) {
+ elgg_deprecated_notice('cache_entity() is a private function and should not be used.', 1.8);
+ _elgg_cache_entity($entity);
+}
- return 0;
-} \ No newline at end of file
+/**
+ * Retrieve a entity from the cache.
+ *
+ * @param int $guid The guid
+ *
+ * @return ElggEntity|bool false if entity not cached, or not fully loaded
+ * @access private
+ * @deprecated 1.8
+ */
+function retrieve_cached_entity($guid) {
+ elgg_deprecated_notice('retrieve_cached_entity() is a private function and should not be used.', 1.8);
+ return _elgg_retrieve_cached_entity($guid);
+}
diff --git a/engine/lib/deprecated-1.9.php b/engine/lib/deprecated-1.9.php
new file mode 100644
index 000000000..31d03428f
--- /dev/null
+++ b/engine/lib/deprecated-1.9.php
@@ -0,0 +1,582 @@
+<?php
+/**
+ * Return a timestamp for the start of a given day (defaults today).
+ *
+ * @param int $day Day
+ * @param int $month Month
+ * @param int $year Year
+ *
+ * @return int
+ * @access private
+ * @deprecated 1.9
+ */
+function get_day_start($day = null, $month = null, $year = null) {
+ elgg_deprecated_notice('get_day_start() has been deprecated', 1.9);
+ return mktime(0, 0, 0, $month, $day, $year);
+}
+
+/**
+ * Return a timestamp for the end of a given day (defaults today).
+ *
+ * @param int $day Day
+ * @param int $month Month
+ * @param int $year Year
+ *
+ * @return int
+ * @access private
+ * @deprecated 1.9
+ */
+function get_day_end($day = null, $month = null, $year = null) {
+ elgg_deprecated_notice('get_day_end() has been deprecated', 1.9);
+ return mktime(23, 59, 59, $month, $day, $year);
+}
+
+/**
+ * Return the notable entities for a given time period.
+ *
+ * @param int $start_time The start time as a unix timestamp.
+ * @param int $end_time The end time as a unix timestamp.
+ * @param string $type The type of entity (eg "user", "object" etc)
+ * @param string $subtype The arbitrary subtype of the entity
+ * @param int $owner_guid The GUID of the owning user
+ * @param string $order_by The field to order by; by default, time_created desc
+ * @param int $limit The number of entities to return; 10 by default
+ * @param int $offset The indexing offset, 0 by default
+ * @param boolean $count Set to true to get a count instead of entities. Defaults to false.
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any.
+ * @param mixed $container_guid Container or containers to get entities from (default: any).
+ *
+ * @return array|false
+ * @access private
+ * @deprecated 1.9
+ */
+function get_notable_entities($start_time, $end_time, $type = "", $subtype = "", $owner_guid = 0,
+$order_by = "asc", $limit = 10, $offset = 0, $count = false, $site_guid = 0,
+$container_guid = null) {
+ elgg_deprecated_notice('get_notable_entities() has been deprecated', 1.9);
+ global $CONFIG;
+
+ if ($subtype === false || $subtype === null || $subtype === 0) {
+ return false;
+ }
+
+ $start_time = (int)$start_time;
+ $end_time = (int)$end_time;
+ $order_by = sanitise_string($order_by);
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+ $site_guid = (int) $site_guid;
+ if ($site_guid == 0) {
+ $site_guid = $CONFIG->site_guid;
+ }
+
+ $where = array();
+
+ if (is_array($type)) {
+ $tempwhere = "";
+ if (sizeof($type)) {
+ foreach ($type as $typekey => $subtypearray) {
+ foreach ($subtypearray as $subtypeval) {
+ $typekey = sanitise_string($typekey);
+ if (!empty($subtypeval)) {
+ $subtypeval = (int) get_subtype_id($typekey, $subtypeval);
+ } else {
+ $subtypeval = 0;
+ }
+ if (!empty($tempwhere)) {
+ $tempwhere .= " or ";
+ }
+ $tempwhere .= "(e.type = '{$typekey}' and e.subtype = {$subtypeval})";
+ }
+ }
+ }
+ if (!empty($tempwhere)) {
+ $where[] = "({$tempwhere})";
+ }
+ } else {
+ $type = sanitise_string($type);
+ $subtype = get_subtype_id($type, $subtype);
+
+ if ($type != "") {
+ $where[] = "e.type='$type'";
+ }
+
+ if ($subtype !== "") {
+ $where[] = "e.subtype=$subtype";
+ }
+ }
+
+ if ($owner_guid != "") {
+ if (!is_array($owner_guid)) {
+ $owner_array = array($owner_guid);
+ $owner_guid = (int) $owner_guid;
+ $where[] = "e.owner_guid = '$owner_guid'";
+ } else if (sizeof($owner_guid) > 0) {
+ $owner_array = array_map('sanitise_int', $owner_guid);
+ // Cast every element to the owner_guid array to int
+ $owner_guid = implode(",", $owner_guid);
+ $where[] = "e.owner_guid in ({$owner_guid})";
+ }
+ if (is_null($container_guid)) {
+ $container_guid = $owner_array;
+ }
+ }
+
+ if ($site_guid > 0) {
+ $where[] = "e.site_guid = {$site_guid}";
+ }
+
+ if (!is_null($container_guid)) {
+ if (is_array($container_guid)) {
+ foreach ($container_guid as $key => $val) {
+ $container_guid[$key] = (int) $val;
+ }
+ $where[] = "e.container_guid in (" . implode(",", $container_guid) . ")";
+ } else {
+ $container_guid = (int) $container_guid;
+ $where[] = "e.container_guid = {$container_guid}";
+ }
+ }
+
+ // Add the calendar stuff
+ $cal_join = "
+ JOIN {$CONFIG->dbprefix}metadata cal_start on e.guid=cal_start.entity_guid
+ JOIN {$CONFIG->dbprefix}metastrings cal_start_name on cal_start.name_id=cal_start_name.id
+ JOIN {$CONFIG->dbprefix}metastrings cal_start_value on cal_start.value_id=cal_start_value.id
+
+ JOIN {$CONFIG->dbprefix}metadata cal_end on e.guid=cal_end.entity_guid
+ JOIN {$CONFIG->dbprefix}metastrings cal_end_name on cal_end.name_id=cal_end_name.id
+ JOIN {$CONFIG->dbprefix}metastrings cal_end_value on cal_end.value_id=cal_end_value.id
+ ";
+ $where[] = "cal_start_name.string='calendar_start'";
+ $where[] = "cal_start_value.string>=$start_time";
+ $where[] = "cal_end_name.string='calendar_end'";
+ $where[] = "cal_end_value.string <= $end_time";
+
+
+ if (!$count) {
+ $query = "SELECT e.* from {$CONFIG->dbprefix}entities e $cal_join where ";
+ } else {
+ $query = "SELECT count(e.guid) as total from {$CONFIG->dbprefix}entities e $cal_join where ";
+ }
+ foreach ($where as $w) {
+ $query .= " $w and ";
+ }
+
+ $query .= get_access_sql_suffix('e'); // Add access controls
+
+ if (!$count) {
+ $query .= " order by n.calendar_start $order_by";
+ // Add order and limit
+ if ($limit) {
+ $query .= " limit $offset, $limit";
+ }
+ $dt = get_data($query, "entity_row_to_elggstar");
+
+ return $dt;
+ } else {
+ $total = get_data_row($query);
+ return $total->total;
+ }
+}
+
+/**
+ * Return the notable entities for a given time period based on an item of metadata.
+ *
+ * @param int $start_time The start time as a unix timestamp.
+ * @param int $end_time The end time as a unix timestamp.
+ * @param mixed $meta_name Metadata name
+ * @param mixed $meta_value Metadata value
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param string $entity_subtype The subtype of the entity.
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Optional ordering.
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any.
+ * @param bool $count If true, returns count instead of entities. (Default: false)
+ *
+ * @return int|array A list of entities, or a count if $count is set to true
+ * @access private
+ * @deprecated 1.9
+ */
+function get_notable_entities_from_metadata($start_time, $end_time, $meta_name, $meta_value = "",
+$entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "",
+$site_guid = 0, $count = false) {
+ elgg_deprecated_notice('get_notable_entities_from_metadata() has been deprecated', 1.9);
+
+ global $CONFIG;
+
+ $meta_n = get_metastring_id($meta_name);
+ $meta_v = get_metastring_id($meta_value);
+
+ $start_time = (int)$start_time;
+ $end_time = (int)$end_time;
+ $entity_type = sanitise_string($entity_type);
+ $entity_subtype = get_subtype_id($entity_type, $entity_subtype);
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+ if ($order_by == "") {
+ $order_by = "e.time_created desc";
+ }
+ $order_by = sanitise_string($order_by);
+ $site_guid = (int) $site_guid;
+ if ((is_array($owner_guid) && (count($owner_guid)))) {
+ foreach ($owner_guid as $key => $guid) {
+ $owner_guid[$key] = (int) $guid;
+ }
+ } else {
+ $owner_guid = (int) $owner_guid;
+ }
+
+ if ($site_guid == 0) {
+ $site_guid = $CONFIG->site_guid;
+ }
+
+ //$access = get_access_list();
+
+ $where = array();
+
+ if ($entity_type != "") {
+ $where[] = "e.type='$entity_type'";
+ }
+
+ if ($entity_subtype) {
+ $where[] = "e.subtype=$entity_subtype";
+ }
+
+ if ($meta_name != "") {
+ $where[] = "m.name_id='$meta_n'";
+ }
+
+ if ($meta_value != "") {
+ $where[] = "m.value_id='$meta_v'";
+ }
+
+ if ($site_guid > 0) {
+ $where[] = "e.site_guid = {$site_guid}";
+ }
+
+ if (is_array($owner_guid)) {
+ $where[] = "e.container_guid in (" . implode(",", $owner_guid) . ")";
+ } else if ($owner_guid > 0) {
+ $where[] = "e.container_guid = {$owner_guid}";
+ }
+
+ // Add the calendar stuff
+ $cal_join = "
+ JOIN {$CONFIG->dbprefix}metadata cal_start on e.guid=cal_start.entity_guid
+ JOIN {$CONFIG->dbprefix}metastrings cal_start_name on cal_start.name_id=cal_start_name.id
+ JOIN {$CONFIG->dbprefix}metastrings cal_start_value on cal_start.value_id=cal_start_value.id
+
+ JOIN {$CONFIG->dbprefix}metadata cal_end on e.guid=cal_end.entity_guid
+ JOIN {$CONFIG->dbprefix}metastrings cal_end_name on cal_end.name_id=cal_end_name.id
+ JOIN {$CONFIG->dbprefix}metastrings cal_end_value on cal_end.value_id=cal_end_value.id
+ ";
+
+ $where[] = "cal_start_name.string='calendar_start'";
+ $where[] = "cal_start_value.string>=$start_time";
+ $where[] = "cal_end_name.string='calendar_end'";
+ $where[] = "cal_end_value.string <= $end_time";
+
+ if (!$count) {
+ $query = "SELECT distinct e.* ";
+ } else {
+ $query = "SELECT count(distinct e.guid) as total ";
+ }
+
+ $query .= "from {$CONFIG->dbprefix}entities e"
+ . " JOIN {$CONFIG->dbprefix}metadata m on e.guid = m.entity_guid $cal_join where";
+
+ foreach ($where as $w) {
+ $query .= " $w and ";
+ }
+
+ // Add access controls
+ $query .= get_access_sql_suffix("e");
+ $query .= ' and ' . get_access_sql_suffix("m");
+
+ if (!$count) {
+ // Add order and limit
+ $query .= " order by $order_by limit $offset, $limit";
+ return get_data($query, "entity_row_to_elggstar");
+ } else {
+ if ($row = get_data_row($query)) {
+ return $row->total;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Return the notable entities for a given time period based on their relationship.
+ *
+ * @param int $start_time The start time as a unix timestamp.
+ * @param int $end_time The end time as a unix timestamp.
+ * @param string $relationship The relationship eg "friends_of"
+ * @param int $relationship_guid The guid of the entity to use query
+ * @param bool $inverse_relationship Reverse the normal function of the query to say
+ * "give me all entities for whom $relationship_guid is a
+ * $relationship of"
+ * @param string $type Entity type
+ * @param string $subtype Entity subtype
+ * @param int $owner_guid Owner GUID
+ * @param string $order_by Optional Order by
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param boolean $count If true returns a count of entities (default false)
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any
+ *
+ * @return array|int|false An array of entities, or the number of entities, or false on failure
+ * @access private
+ * @deprecated 1.9
+ */
+function get_noteable_entities_from_relationship($start_time, $end_time, $relationship,
+$relationship_guid, $inverse_relationship = false, $type = "", $subtype = "", $owner_guid = 0,
+$order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
+ elgg_deprecated_notice('get_noteable_entities_from_relationship() has been deprecated', 1.9);
+
+ global $CONFIG;
+
+ $start_time = (int)$start_time;
+ $end_time = (int)$end_time;
+ $relationship = sanitise_string($relationship);
+ $relationship_guid = (int)$relationship_guid;
+ $inverse_relationship = (bool)$inverse_relationship;
+ $type = sanitise_string($type);
+ $subtype = get_subtype_id($type, $subtype);
+ $owner_guid = (int)$owner_guid;
+ if ($order_by == "") {
+ $order_by = "time_created desc";
+ }
+ $order_by = sanitise_string($order_by);
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+ $site_guid = (int) $site_guid;
+ if ($site_guid == 0) {
+ $site_guid = $CONFIG->site_guid;
+ }
+
+ //$access = get_access_list();
+
+ $where = array();
+
+ if ($relationship != "") {
+ $where[] = "r.relationship='$relationship'";
+ }
+ if ($relationship_guid) {
+ $where[] = $inverse_relationship ?
+ "r.guid_two='$relationship_guid'" : "r.guid_one='$relationship_guid'";
+ }
+ if ($type != "") {
+ $where[] = "e.type='$type'";
+ }
+ if ($subtype) {
+ $where[] = "e.subtype=$subtype";
+ }
+ if ($owner_guid != "") {
+ $where[] = "e.container_guid='$owner_guid'";
+ }
+ if ($site_guid > 0) {
+ $where[] = "e.site_guid = {$site_guid}";
+ }
+
+ // Add the calendar stuff
+ $cal_join = "
+ JOIN {$CONFIG->dbprefix}metadata cal_start on e.guid=cal_start.entity_guid
+ JOIN {$CONFIG->dbprefix}metastrings cal_start_name on cal_start.name_id=cal_start_name.id
+ JOIN {$CONFIG->dbprefix}metastrings cal_start_value on cal_start.value_id=cal_start_value.id
+
+ JOIN {$CONFIG->dbprefix}metadata cal_end on e.guid=cal_end.entity_guid
+ JOIN {$CONFIG->dbprefix}metastrings cal_end_name on cal_end.name_id=cal_end_name.id
+ JOIN {$CONFIG->dbprefix}metastrings cal_end_value on cal_end.value_id=cal_end_value.id
+ ";
+ $where[] = "cal_start_name.string='calendar_start'";
+ $where[] = "cal_start_value.string>=$start_time";
+ $where[] = "cal_end_name.string='calendar_end'";
+ $where[] = "cal_end_value.string <= $end_time";
+
+ // Select what we're joining based on the options
+ $joinon = "e.guid = r.guid_one";
+ if (!$inverse_relationship) {
+ $joinon = "e.guid = r.guid_two";
+ }
+
+ if ($count) {
+ $query = "SELECT count(distinct e.guid) as total ";
+ } else {
+ $query = "SELECT distinct e.* ";
+ }
+ $query .= " from {$CONFIG->dbprefix}entity_relationships r"
+ . " JOIN {$CONFIG->dbprefix}entities e on $joinon $cal_join where ";
+
+ foreach ($where as $w) {
+ $query .= " $w and ";
+ }
+ // Add access controls
+ $query .= get_access_sql_suffix("e");
+ if (!$count) {
+ $query .= " order by $order_by limit $offset, $limit"; // Add order and limit
+ return get_data($query, "entity_row_to_elggstar");
+ } else {
+ if ($count = get_data_row($query)) {
+ return $count->total;
+ }
+ }
+ return false;
+}
+
+/**
+ * Get all entities for today.
+ *
+ * @param string $type The type of entity (eg "user", "object" etc)
+ * @param string $subtype The arbitrary subtype of the entity
+ * @param int $owner_guid The GUID of the owning user
+ * @param string $order_by The field to order by; by default, time_created desc
+ * @param int $limit The number of entities to return; 10 by default
+ * @param int $offset The indexing offset, 0 by default
+ * @param boolean $count If true returns a count of entities (default false)
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any
+ * @param mixed $container_guid Container(s) to get entities from (default: any).
+ *
+ * @return array|false
+ * @access private
+ * @deprecated 1.9
+ */
+function get_todays_entities($type = "", $subtype = "", $owner_guid = 0, $order_by = "",
+$limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null) {
+ elgg_deprecated_notice('get_todays_entities() has been deprecated', 1.9);
+
+ $day_start = get_day_start();
+ $day_end = get_day_end();
+
+ return get_notable_entities($day_start, $day_end, $type, $subtype, $owner_guid, $order_by,
+ $limit, $offset, $count, $site_guid, $container_guid);
+}
+
+/**
+ * Get entities for today from metadata.
+ *
+ * @param mixed $meta_name Metadata name
+ * @param mixed $meta_value Metadata value
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param string $entity_subtype The subtype of the entity.
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Optional ordering.
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any.
+ * @param bool $count If true, returns count instead of entities. (Default: false)
+ *
+ * @return int|array A list of entities, or a count if $count is set to true
+ * @access private
+ * @deprecated 1.9
+ */
+function get_todays_entities_from_metadata($meta_name, $meta_value = "", $entity_type = "",
+$entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0,
+$count = false) {
+ elgg_deprecated_notice('get_todays_entities_from_metadata() has been deprecated', 1.9);
+
+ $day_start = get_day_start();
+ $day_end = get_day_end();
+
+ return get_notable_entities_from_metadata($day_start, $day_end, $meta_name, $meta_value,
+ $entity_type, $entity_subtype, $owner_guid, $limit, $offset, $order_by, $site_guid, $count);
+}
+
+/**
+ * Get entities for today from a relationship
+ *
+ * @param string $relationship The relationship eg "friends_of"
+ * @param int $relationship_guid The guid of the entity to use query
+ * @param bool $inverse_relationship Reverse the normal function of the query to say
+ * "give me all entities for whom $relationship_guid is a
+ * $relationship of"
+ * @param string $type Entity type
+ * @param string $subtype Entity subtype
+ * @param int $owner_guid Owner GUID
+ * @param string $order_by Optional Order by
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param boolean $count If true returns a count of entities (default false)
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any
+ *
+ * @return array|int|false An array of entities, or the number of entities, or false on failure
+ * @access private
+ * @deprecated 1.9
+ */
+function get_todays_entities_from_relationship($relationship, $relationship_guid,
+$inverse_relationship = false, $type = "", $subtype = "", $owner_guid = 0,
+$order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
+ elgg_deprecated_notice('get_todays_entities_from_relationship() has been deprecated', 1.9);
+
+ $day_start = get_day_start();
+ $day_end = get_day_end();
+
+ return get_notable_entities_from_relationship($day_start, $day_end, $relationship,
+ $relationship_guid, $inverse_relationship, $type, $subtype, $owner_guid, $order_by,
+ $limit, $offset, $count, $site_guid);
+}
+
+/**
+ * Returns a viewable list of entities for a given time period.
+ *
+ * @see elgg_view_entity_list
+ *
+ * @param int $start_time The start time as a unix timestamp.
+ * @param int $end_time The end time as a unix timestamp.
+ * @param string $type The type of entity (eg "user", "object" etc)
+ * @param string $subtype The arbitrary subtype of the entity
+ * @param int $owner_guid The GUID of the owning user
+ * @param int $limit The number of entities to return; 10 by default
+ * @param boolean $fullview Whether or not to display the full view (default: true)
+ * @param boolean $listtypetoggle Whether or not to allow gallery view
+ * @param boolean $navigation Display pagination? Default: true
+ *
+ * @return string A viewable list of entities
+ * @access private
+ * @deprecated 1.9
+ */
+function list_notable_entities($start_time, $end_time, $type= "", $subtype = "", $owner_guid = 0,
+$limit = 10, $fullview = true, $listtypetoggle = false, $navigation = true) {
+ elgg_deprecated_notice('list_notable_entities() has been deprecated', 1.9);
+
+ $offset = (int) get_input('offset');
+ $count = get_notable_entities($start_time, $end_time, $type, $subtype,
+ $owner_guid, "", $limit, $offset, true);
+
+ $entities = get_notable_entities($start_time, $end_time, $type, $subtype,
+ $owner_guid, "", $limit, $offset);
+
+ return elgg_view_entity_list($entities, $count, $offset, $limit,
+ $fullview, $listtypetoggle, $navigation);
+}
+
+/**
+ * Return a list of today's entities.
+ *
+ * @see list_notable_entities
+ *
+ * @param string $type The type of entity (eg "user", "object" etc)
+ * @param string $subtype The arbitrary subtype of the entity
+ * @param int $owner_guid The GUID of the owning user
+ * @param int $limit The number of entities to return; 10 by default
+ * @param boolean $fullview Whether or not to display the full view (default: true)
+ * @param boolean $listtypetoggle Whether or not to allow gallery view
+ * @param boolean $navigation Display pagination? Default: true
+ *
+ * @return string A viewable list of entities
+ * @access private
+ * @deprecated 1.9
+ */
+function list_todays_entities($type= "", $subtype = "", $owner_guid = 0, $limit = 10,
+$fullview = true, $listtypetoggle = false, $navigation = true) {
+ elgg_deprecated_notice('list_todays_entities() has been deprecated', 1.9);
+
+ $day_start = get_day_start();
+ $day_end = get_day_end();
+
+ return list_notable_entities($day_start, $day_end, $type, $subtype, $owner_guid, $limit,
+ $fullview, $listtypetoggle, $navigation);
+}
diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php
index 1aef48ef4..34111c69d 100644
--- a/engine/lib/elgglib.php
+++ b/engine/lib/elgglib.php
@@ -18,6 +18,7 @@ elgg_register_classes(dirname(dirname(__FILE__)) . '/classes');
*
* @return void
* @throws Exception
+ * @access private
*/
function _elgg_autoload($class) {
global $CONFIG;
@@ -33,21 +34,15 @@ function _elgg_autoload($class) {
*
* @param string $dir The dir to look in
*
- * @return true
+ * @return void
* @since 1.8.0
*/
function elgg_register_classes($dir) {
$classes = elgg_get_file_list($dir, array(), array(), array('.php'));
- if (!$classes) {
- return false;
- }
-
foreach ($classes as $class) {
elgg_register_class(basename($class, '.php'), $class);
}
-
- return true;
}
/**
@@ -98,10 +93,17 @@ function elgg_register_library($name, $location) {
* @return void
* @throws InvalidParameterException
* @since 1.8.0
+ * @todo return boolean in 1.9 to indicate whether the library has been loaded
*/
function elgg_load_library($name) {
global $CONFIG;
+ static $loaded_libraries = array();
+
+ if (in_array($name, $loaded_libraries)) {
+ return;
+ }
+
if (!isset($CONFIG->libraries)) {
$CONFIG->libraries = array();
}
@@ -112,9 +114,14 @@ function elgg_load_library($name) {
}
if (!include_once($CONFIG->libraries[$name])) {
- $error = elgg_echo('InvalidParameterException:LibraryNotRegistered', array($name));
+ $error = elgg_echo('InvalidParameterException:LibraryNotFound', array(
+ $name,
+ $CONFIG->libraries[$name])
+ );
throw new InvalidParameterException($error);
}
+
+ $loaded_libraries[] = $name;
}
/**
@@ -126,12 +133,11 @@ function elgg_load_library($name) {
* @param string $location URL to forward to browser to. Can be path relative to the network's URL.
* @param string $reason Short explanation for why we're forwarding
*
- * @return False False if headers have been sent. Terminates execution if forwarding.
+ * @return false False if headers have been sent. Terminates execution if forwarding.
+ * @throws SecurityException
*/
function forward($location = "", $reason = 'system') {
- global $CONFIG;
-
- if (!headers_sent()) {
+ if (!headers_sent($file, $line)) {
if ($location === REFERER) {
$location = $_SERVER['HTTP_REFERER'];
}
@@ -149,9 +155,9 @@ function forward($location = "", $reason = 'system') {
} else if ($location === '') {
exit;
}
+ } else {
+ throw new SecurityException(elgg_echo('SecurityException:ForwardFailedToRedirect', array($file, $line)));
}
-
- return false;
}
/**
@@ -173,12 +179,12 @@ function forward($location = "", $reason = 'system') {
* @param string $name An identifier for the JavaScript library
* @param string $url URL of the JavaScript file
* @param string $location Page location: head or footer. (default: head)
- * @param int $priority Priority of the CSS file (lower numbers load earlier)
+ * @param int $priority Priority of the JS file (lower numbers load earlier)
*
* @return bool
* @since 1.8.0
*/
-function elgg_register_js($name, $url, $location = 'head', $priority = 500) {
+function elgg_register_js($name, $url, $location = 'head', $priority = null) {
return elgg_register_external_file('js', $name, $url, $location, $priority);
}
@@ -202,6 +208,7 @@ function elgg_unregister_js($name) {
*
* @param string $name Identifier of the JavaScript resource
*
+ * @return void
* @since 1.8.0
*/
function elgg_load_js($name) {
@@ -230,7 +237,7 @@ function elgg_get_loaded_js($location = 'head') {
* @return bool
* @since 1.8.0
*/
-function elgg_register_css($name, $url, $priority = 500) {
+function elgg_register_css($name, $url, $priority = null) {
return elgg_register_external_file('css', $name, $url, 'head', $priority);
}
@@ -254,6 +261,7 @@ function elgg_unregister_css($name) {
*
* @param string $name Identifier of the CSS file
*
+ * @return void
* @since 1.8.0
*/
function elgg_load_css($name) {
@@ -292,32 +300,44 @@ function elgg_register_external_file($type, $name, $url, $location, $priority =
$url = elgg_format_url($url);
$url = elgg_normalize_url($url);
- if (!isset($CONFIG->externals)) {
- $CONFIG->externals = array();
- }
+ elgg_bootstrap_externals_data_structure($type);
+
+ $name = trim(strtolower($name));
- if (!isset($CONFIG->externals[$type])) {
- $CONFIG->externals[$type] = array();
+ // normalize bogus priorities, but allow empty, null, and false to be defaults.
+ if (!is_numeric($priority)) {
+ $priority = 500;
}
- $name = trim(strtolower($name));
+ // no negative priorities right now.
+ $priority = max((int)$priority, 0);
- if (isset($CONFIG->externals[$type][$name])) {
- // update a registered item
- $item = $CONFIG->externals[$type][$name];
+ $item = elgg_extract($name, $CONFIG->externals_map[$type]);
+
+ if ($item) {
+ // updating a registered item
+ // don't update loaded because it could already be set
+ $item->url = $url;
+ $item->location = $location;
+ // if loaded before registered, that means it hasn't been added to the list yet
+ if ($CONFIG->externals[$type]->contains($item)) {
+ $priority = $CONFIG->externals[$type]->move($item, $priority);
+ } else {
+ $priority = $CONFIG->externals[$type]->add($item, $priority);
+ }
} else {
$item = new stdClass();
$item->loaded = false;
- }
+ $item->url = $url;
+ $item->location = $location;
- $item->url = $url;
- $item->priority = max((int)$priority, 0);
- $item->location = $location;
+ $priority = $CONFIG->externals[$type]->add($item, $priority);
+ }
- $CONFIG->externals[$type][$name] = $item;
+ $CONFIG->externals_map[$type][$name] = $item;
- return true;
+ return $priority !== false;
}
/**
@@ -332,19 +352,14 @@ function elgg_register_external_file($type, $name, $url, $location, $priority =
function elgg_unregister_external_file($type, $name) {
global $CONFIG;
- if (!isset($CONFIG->externals)) {
- return false;
- }
-
- if (!isset($CONFIG->externals[$type])) {
- return false;
- }
+ elgg_bootstrap_externals_data_structure($type);
$name = trim(strtolower($name));
-
- if (array_key_exists($name, $CONFIG->externals[$type])) {
- unset($CONFIG->externals[$type][$name]);
- return true;
+ $item = elgg_extract($name, $CONFIG->externals_map[$type]);
+
+ if ($item) {
+ unset($CONFIG->externals_map[$type][$name]);
+ return $CONFIG->externals[$type]->remove($item);
}
return false;
@@ -354,34 +369,31 @@ function elgg_unregister_external_file($type, $name) {
* Load an external resource for use on this page
*
* @param string $type Type of file: js or css
- * @param string $name
+ * @param string $name The identifier for the file
*
+ * @return void
* @since 1.8.0
*/
function elgg_load_external_file($type, $name) {
global $CONFIG;
- if (!isset($CONFIG->externals)) {
- $CONFIG->externals = array();
- }
-
- if (!isset($CONFIG->externals[$type])) {
- $CONFIG->externals[$type] = array();
- }
+ elgg_bootstrap_externals_data_structure($type);
$name = trim(strtolower($name));
- if (isset($CONFIG->externals[$type][$name])) {
+ $item = elgg_extract($name, $CONFIG->externals_map[$type]);
+
+ if ($item) {
// update a registered item
- $CONFIG->externals[$type][$name]->loaded = true;
+ $item->loaded = true;
} else {
$item = new stdClass();
$item->loaded = true;
$item->url = '';
$item->location = '';
- $item->priority = 500;
- $CONFIG->externals[$type][$name] = $item;
+ $CONFIG->externals[$type]->add($item);
+ $CONFIG->externals_map[$type][$name] = $item;
}
}
@@ -397,13 +409,12 @@ function elgg_load_external_file($type, $name) {
function elgg_get_loaded_external_files($type, $location) {
global $CONFIG;
- if (isset($CONFIG->externals) && isset($CONFIG->externals[$type])) {
- $items = array_values($CONFIG->externals[$type]);
+ if (isset($CONFIG->externals) && $CONFIG->externals[$type] instanceof ElggPriorityList) {
+ $items = $CONFIG->externals[$type]->getElements();
- $callback = "return \$v->loaded == true && \$v->location == $location;";
+ $callback = "return \$v->loaded == true && \$v->location == '$location';";
$items = array_filter($items, create_function('$v', $callback));
if ($items) {
- usort($items, create_function('$a,$b','return $a->priority >= $b->priority;'));
array_walk($items, create_function('&$v,$k', '$v = $v->url;'));
}
return $items;
@@ -412,6 +423,32 @@ function elgg_get_loaded_external_files($type, $location) {
}
/**
+ * Bootstraps the externals data structure in $CONFIG.
+ *
+ * @param string $type The type of external, js or css.
+ * @access private
+ */
+function elgg_bootstrap_externals_data_structure($type) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->externals)) {
+ $CONFIG->externals = array();
+ }
+
+ if (!isset($CONFIG->externals[$type]) || !$CONFIG->externals[$type] instanceof ElggPriorityList) {
+ $CONFIG->externals[$type] = new ElggPriorityList();
+ }
+
+ if (!isset($CONFIG->externals_map)) {
+ $CONFIG->externals_map = array();
+ }
+
+ if (!isset($CONFIG->externals_map[$type])) {
+ $CONFIG->externals_map[$type] = array();
+ }
+}
+
+/**
* Returns a list of files in $directory.
*
* Only returns files. Does not recurse into subdirs.
@@ -499,7 +536,7 @@ function sanitise_filepath($path, $append_slash = TRUE) {
* @param string $register Types of message: "error", "success" (default: success)
* @param bool $count Count the number of messages (default: false)
*
- * @return true|false|array Either the array of messages, or a response regarding
+ * @return bool|array Either the array of messages, or a response regarding
* whether the message addition was successful.
* @todo Clean up. Separate registering messages and retrieving them.
*/
@@ -533,7 +570,7 @@ function system_messages($message = null, $register = "success", $count = false)
return sizeof($_SESSION['msg'][$register]);
} else {
$count = 0;
- foreach ($_SESSION['msg'] as $register => $submessages) {
+ foreach ($_SESSION['msg'] as $submessages) {
$count += sizeof($submessages);
}
return $count;
@@ -642,7 +679,7 @@ function elgg_register_event_handler($event, $object_type, $callback, $priority
global $CONFIG;
if (empty($event) || empty($object_type)) {
- return FALSE;
+ return false;
}
if (!isset($CONFIG->events)) {
@@ -655,8 +692,8 @@ function elgg_register_event_handler($event, $object_type, $callback, $priority
$CONFIG->events[$event][$object_type] = array();
}
- if (!is_callable($callback)) {
- return FALSE;
+ if (!is_callable($callback, true)) {
+ return false;
}
$priority = max((int) $priority, 0);
@@ -666,7 +703,7 @@ function elgg_register_event_handler($event, $object_type, $callback, $priority
}
$CONFIG->events[$event][$object_type][$priority] = $callback;
ksort($CONFIG->events[$event][$object_type]);
- return TRUE;
+ return true;
}
/**
@@ -681,9 +718,12 @@ function elgg_register_event_handler($event, $object_type, $callback, $priority
*/
function elgg_unregister_event_handler($event, $object_type, $callback) {
global $CONFIG;
- foreach ($CONFIG->events[$event][$object_type] as $key => $event_callback) {
- if ($event_callback == $callback) {
- unset($CONFIG->events[$event][$object_type][$key]);
+
+ if (isset($CONFIG->events[$event]) && isset($CONFIG->events[$event][$object_type])) {
+ foreach ($CONFIG->events[$event][$object_type] as $key => $event_callback) {
+ if ($event_callback == $callback) {
+ unset($CONFIG->events[$event][$object_type][$key]);
+ }
}
}
}
@@ -706,7 +746,7 @@ function elgg_unregister_event_handler($event, $object_type, $callback) {
* @tip When referring to events, the preferred syntax is "event, type".
*
* @internal Only rarely should events be changed, added, or removed in core.
- * When making changes to events, be sure to first create a ticket in trac.
+ * When making changes to events, be sure to first create a ticket on Github.
*
* @internal @tip Think of $object_type as the primary namespace element, and
* $event as the secondary namespace.
@@ -741,14 +781,14 @@ function elgg_trigger_event($event, $object_type, $object = null) {
foreach ($events as $callback_list) {
if (is_array($callback_list)) {
foreach ($callback_list as $callback) {
- if (call_user_func_array($callback, $args) === FALSE) {
- return FALSE;
+ if (is_callable($callback) && (call_user_func_array($callback, $args) === false)) {
+ return false;
}
}
}
}
- return TRUE;
+ return true;
}
/**
@@ -807,7 +847,7 @@ function elgg_trigger_event($event, $object_type, $object = null) {
*
* @param string $hook The name of the hook
* @param string $type The type of the hook
- * @param callback $callback The name of a valid function or an array with object and method
+ * @param callable $callback The name of a valid function or an array with object and method
* @param int $priority The priority - 500 is default, lower numbers called first
*
* @return bool
@@ -821,7 +861,7 @@ function elgg_register_plugin_hook_handler($hook, $type, $callback, $priority =
global $CONFIG;
if (empty($hook) || empty($type)) {
- return FALSE;
+ return false;
}
if (!isset($CONFIG->hooks)) {
@@ -834,8 +874,8 @@ function elgg_register_plugin_hook_handler($hook, $type, $callback, $priority =
$CONFIG->hooks[$hook][$type] = array();
}
- if (!is_callable($callback)) {
- return FALSE;
+ if (!is_callable($callback, true)) {
+ return false;
}
$priority = max((int) $priority, 0);
@@ -845,7 +885,7 @@ function elgg_register_plugin_hook_handler($hook, $type, $callback, $priority =
}
$CONFIG->hooks[$hook][$type][$priority] = $callback;
ksort($CONFIG->hooks[$hook][$type]);
- return TRUE;
+ return true;
}
/**
@@ -853,16 +893,19 @@ function elgg_register_plugin_hook_handler($hook, $type, $callback, $priority =
*
* @param string $hook The name of the hook
* @param string $entity_type The name of the type of entity (eg "user", "object" etc)
- * @param callback $callback The PHP callback to be removed
+ * @param callable $callback The PHP callback to be removed
*
* @return void
* @since 1.8.0
*/
function elgg_unregister_plugin_hook_handler($hook, $entity_type, $callback) {
global $CONFIG;
- foreach ($CONFIG->hooks[$hook][$entity_type] as $key => $hook_callback) {
- if ($hook_callback == $callback) {
- unset($CONFIG->hooks[$hook][$entity_type][$key]);
+
+ if (isset($CONFIG->hooks[$hook]) && isset($CONFIG->hooks[$hook][$entity_type])) {
+ foreach ($CONFIG->hooks[$hook][$entity_type] as $key => $hook_callback) {
+ if ($hook_callback == $callback) {
+ unset($CONFIG->hooks[$hook][$entity_type][$key]);
+ }
}
}
}
@@ -941,10 +984,12 @@ function elgg_trigger_plugin_hook($hook, $type, $params = null, $returnvalue = n
foreach ($hooks as $callback_list) {
if (is_array($callback_list)) {
foreach ($callback_list as $hookcallback) {
- $args = array($hook, $type, $returnvalue, $params);
- $temp_return_value = call_user_func_array($hookcallback, $args);
- if (!is_null($temp_return_value)) {
- $returnvalue = $temp_return_value;
+ if (is_callable($hookcallback)) {
+ $args = array($hook, $type, $returnvalue, $params);
+ $temp_return_value = call_user_func_array($hookcallback, $args);
+ if (!is_null($temp_return_value)) {
+ $returnvalue = $temp_return_value;
+ }
}
}
}
@@ -963,9 +1008,11 @@ function elgg_trigger_plugin_hook($hook, $type, $params = null, $returnvalue = n
* @param Exception $exception The exception being handled
*
* @return void
+ * @access private
*/
function _elgg_php_exception_handler($exception) {
- error_log("*** FATAL EXCEPTION *** : " . $exception);
+ $timestamp = time();
+ error_log("Exception #$timestamp: $exception");
// Wipe any existing output buffer
ob_end_clean();
@@ -981,7 +1028,17 @@ function _elgg_php_exception_handler($exception) {
$CONFIG->pagesetupdone = true;
elgg_set_viewtype('failsafe');
- $body = elgg_view("messages/exceptions/exception", array('object' => $exception));
+ if (elgg_is_admin_logged_in()) {
+ $body = elgg_view("messages/exceptions/admin_exception", array(
+ 'object' => $exception,
+ 'ts' => $timestamp
+ ));
+ } else {
+ $body = elgg_view("messages/exceptions/exception", array(
+ 'object' => $exception,
+ 'ts' => $timestamp
+ ));
+ }
echo elgg_view_page(elgg_echo('exception:title'), $body);
} catch (Exception $e) {
$timestamp = time();
@@ -1011,6 +1068,9 @@ function _elgg_php_exception_handler($exception) {
* @param array $vars An array that points to the active symbol table where error occurred
*
* @return true
+ * @throws Exception
+ * @access private
+ * @todo Replace error_log calls with elgg_log calls.
*/
function _elgg_php_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
$error = date("Y-m-d H:i:s (T)") . ": \"$errmsg\" in file $filename (line $linenum)";
@@ -1026,7 +1086,12 @@ function _elgg_php_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
case E_WARNING :
case E_USER_WARNING :
- error_log("PHP WARNING: $error");
+ case E_RECOVERABLE_ERROR: // (e.g. type hint violation)
+
+ // check if the error wasn't suppressed by the error control operator (@)
+ if (error_reporting()) {
+ error_log("PHP WARNING: $error");
+ }
break;
default:
@@ -1050,8 +1115,8 @@ function _elgg_php_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
*
* @note No messages will be displayed unless debugging has been enabled.
*
- * @param str $message User message
- * @param str $level NOTICE | WARNING | ERROR | DEBUG
+ * @param string $message User message
+ * @param string $level NOTICE | WARNING | ERROR | DEBUG
*
* @return bool
* @since 1.7.0
@@ -1113,9 +1178,11 @@ function elgg_dump($value, $to_screen = TRUE, $level = 'NOTICE') {
global $CONFIG;
// plugin can return false to stop the default logging method
- $params = array('level' => $level,
- 'msg' => $value,
- 'to_screen' => $to_screen);
+ $params = array(
+ 'level' => $level,
+ 'msg' => $value,
+ 'to_screen' => $to_screen,
+ );
if (!elgg_trigger_plugin_hook('debug', 'log', $params, true)) {
return;
}
@@ -1127,6 +1194,11 @@ function elgg_dump($value, $to_screen = TRUE, $level = 'NOTICE') {
$to_screen = FALSE;
}
+ // Do not want to write to JS or CSS pages
+ if (elgg_in_context('js') || elgg_in_context('css')) {
+ $to_screen = FALSE;
+ }
+
if ($to_screen == TRUE) {
echo '<pre>';
print_r($value);
@@ -1141,7 +1213,9 @@ function elgg_dump($value, $to_screen = TRUE, $level = 'NOTICE') {
*
* This function either displays or logs the deprecation message,
* depending upon the deprecation policies in {@link CODING.txt}.
- * Logged messages are sent with the level of 'WARNING'.
+ * Logged messages are sent with the level of 'WARNING'. Only admins
+ * get visual deprecation notices. When non-admins are logged in, the
+ * notices are sent to PHP's log through elgg_dump().
*
* A user-visual message will be displayed if $dep_version is greater
* than 1 minor releases lower than the current Elgg version, or at all
@@ -1152,23 +1226,27 @@ function elgg_dump($value, $to_screen = TRUE, $level = 'NOTICE') {
*
* @see CODING.txt
*
- * @param str $msg Message to log / display.
- * @param str $dep_version Human-readable *release* version: 1.7, 1.7.3
+ * @param string $msg Message to log / display.
+ * @param string $dep_version Human-readable *release* version: 1.7, 1.8, ...
+ * @param int $backtrace_level How many levels back to display the backtrace.
+ * Useful if calling from functions that are called
+ * from other places (like elgg_view()). Set to -1
+ * for a full backtrace.
*
* @return bool
* @since 1.7.0
*/
-function elgg_deprecated_notice($msg, $dep_version) {
+function elgg_deprecated_notice($msg, $dep_version, $backtrace_level = 1) {
// if it's a major release behind, visual and logged
// if it's a 1 minor release behind, visual and logged
// if it's for current minor release, logged.
- // bugfixes don't matter because you're not deprecating between them, RIGHT?
+ // bugfixes don't matter because we are not deprecating between them
if (!$dep_version) {
- return FALSE;
+ return false;
}
- $elgg_version = get_version(TRUE);
+ $elgg_version = get_version(true);
$elgg_version_arr = explode('.', $elgg_version);
$elgg_major_version = (int)$elgg_version_arr[0];
$elgg_minor_version = (int)$elgg_version_arr[1];
@@ -1176,29 +1254,46 @@ function elgg_deprecated_notice($msg, $dep_version) {
$dep_major_version = (int)$dep_version;
$dep_minor_version = 10 * ($dep_version - $dep_major_version);
- $visual = FALSE;
+ $visual = false;
if (($dep_major_version < $elgg_major_version) ||
($dep_minor_version < $elgg_minor_version)) {
- $visual = TRUE;
+ $visual = true;
}
$msg = "Deprecated in $dep_major_version.$dep_minor_version: $msg";
- if ($visual) {
+ if ($visual && elgg_is_admin_logged_in()) {
register_error($msg);
}
// Get a file and line number for the log. Never show this in the UI.
// Skip over the function that sent this notice and see who called the deprecated
// function itself.
+ $msg .= " Called from ";
+ $stack = array();
$backtrace = debug_backtrace();
- $caller = $backtrace[1];
- $msg .= " (Called from {$caller['file']}:{$caller['line']})";
+ // never show this call.
+ array_shift($backtrace);
+ $i = count($backtrace);
+
+ foreach ($backtrace as $trace) {
+ $stack[] = "[#$i] {$trace['file']}:{$trace['line']}";
+ $i--;
+
+ if ($backtrace_level > 0) {
+ if ($backtrace_level <= 1) {
+ break;
+ }
+ $backtrace_level--;
+ }
+ }
+
+ $msg .= implode("<br /> -> ", $stack);
elgg_log($msg, 'WARNING');
- return TRUE;
+ return true;
}
/**
@@ -1211,8 +1306,6 @@ function elgg_deprecated_notice($msg, $dep_version) {
* @return string The current page URL.
*/
function current_page_url() {
- global $CONFIG;
-
$url = parse_url(elgg_get_site_url());
$page = $url['scheme'] . "://";
@@ -1257,7 +1350,7 @@ function full_url() {
"" : (":" . $_SERVER["SERVER_PORT"]);
// This is here to prevent XSS in poorly written browsers used by 80% of the population.
- // {@trac [5813]}
+ // https://github.com/Elgg/Elgg/commit/0c947e80f512cb0a482b1864fd0a6965c8a0cd4a
$quotes = array('\'', '"');
$encoded = array('%27', '%22');
@@ -1273,7 +1366,7 @@ function full_url() {
* @param array $parts Associative array of URL components like parse_url() returns
* @param bool $html_encode HTML Encode the url?
*
- * @return str Full URL
+ * @return string Full URL
* @since 1.7.0
*/
function elgg_http_build_url(array $parts, $html_encode = TRUE) {
@@ -1304,10 +1397,10 @@ function elgg_http_build_url(array $parts, $html_encode = TRUE) {
* add tokens to the action. The form view automatically handles
* tokens.
*
- * @param str $url Full action URL
- * @param bool $html_encode HTML encode the url? (default: false)
+ * @param string $url Full action URL
+ * @param bool $html_encode HTML encode the url? (default: false)
*
- * @return str URL with action tokens
+ * @return string URL with action tokens
* @since 1.7.0
* @link http://docs.elgg.org/Tutorials/Actions
*/
@@ -1359,17 +1452,17 @@ function elgg_http_remove_url_query_element($url, $element) {
}
$url_array['query'] = http_build_query($query);
- $string = elgg_http_build_url($url_array);
+ $string = elgg_http_build_url($url_array, false);
return $string;
}
/**
* Adds an element or elements to a URL's query string.
*
- * @param str $url The URL
- * @param array $elements Key/value pairs to add to the URL
+ * @param string $url The URL
+ * @param array $elements Key/value pairs to add to the URL
*
- * @return str The new URL with the query strings added
+ * @return string The new URL with the query strings added
* @since 1.7.0
*/
function elgg_http_add_url_query_elements($url, array $elements) {
@@ -1406,8 +1499,6 @@ function elgg_http_add_url_query_elements($url, array $elements) {
* @since 1.8.0
*/
function elgg_http_url_is_identical($url1, $url2, $ignore_params = array('offset', 'limit')) {
- global $CONFIG;
-
// if the server portion is missing but it starts with / then add the url in.
// @todo use elgg_normalize_url()
if (elgg_substr($url1, 0, 1) == '/') {
@@ -1427,8 +1518,12 @@ function elgg_http_url_is_identical($url1, $url2, $ignore_params = array('offset
$url1_info = parse_url($url1);
$url2_info = parse_url($url2);
- $url1_info['path'] = trim($url1_info['path'], '/');
- $url2_info['path'] = trim($url2_info['path'], '/');
+ if (isset($url1_info['path'])) {
+ $url1_info['path'] = trim($url1_info['path'], '/');
+ }
+ if (isset($url2_info['path'])) {
+ $url2_info['path'] = trim($url2_info['path'], '/');
+ }
// compare basic bits
$parts = array('scheme', 'host', 'path');
@@ -1502,10 +1597,14 @@ function elgg_http_url_is_identical($url1, $url2, $ignore_params = array('offset
* @param bool $strict Return array key if it's set, even if empty. If false,
* return $default if the array key is unset or empty.
*
- * @return void
+ * @return mixed
* @since 1.8.0
*/
-function elgg_extract($key, array $array, $default = NULL, $strict = true) {
+function elgg_extract($key, array $array, $default = null, $strict = true) {
+ if (!is_array($array)) {
+ return $default;
+ }
+
if ($strict) {
return (isset($array[$key])) ? $array[$key] : $default;
} else {
@@ -1538,7 +1637,7 @@ $sort_type = SORT_LOCALE_STRING) {
$sort = array();
- foreach ($array as $k => $v) {
+ foreach ($array as $v) {
if (isset($v[$element])) {
$sort[] = strtolower($v[$element]);
} else {
@@ -1557,7 +1656,7 @@ $sort_type = SORT_LOCALE_STRING) {
*
* @param string $ini_get_arg The INI setting
*
- * @return true|false Depending on whether it's on or off
+ * @return bool Depending on whether it's on or off
*/
function ini_get_bool($ini_get_arg) {
$temp = strtolower(ini_get($ini_get_arg));
@@ -1573,7 +1672,7 @@ function ini_get_bool($ini_get_arg) {
*
* @tip Use this for arithmetic when determining if a file can be uploaded.
*
- * @param str $setting The php.ini setting
+ * @param string $setting The php.ini setting
*
* @return int
* @since 1.7.0
@@ -1588,8 +1687,10 @@ function elgg_get_ini_setting_in_bytes($setting) {
switch($last) {
case 'g':
$val *= 1024;
+ // fallthrough intentional
case 'm':
$val *= 1024;
+ // fallthrough intentional
case 'k':
$val *= 1024;
}
@@ -1623,10 +1724,11 @@ function is_not_null($string) {
* names by singular names.
*
* @param array $options The options array. $options['keys'] = 'values';
- * @param array $singulars A list of sinular words to pluralize by adding 's'.
+ * @param array $singulars A list of singular words to pluralize by adding 's'.
*
* @return array
* @since 1.7.0
+ * @access private
*/
function elgg_normalise_plural_options_array($options, $singulars) {
foreach ($singulars as $singular) {
@@ -1660,17 +1762,27 @@ function elgg_normalise_plural_options_array($options, $singulars) {
* useful. Servers will hold pages until processing is done before sending
* them out to the browser.
*
+ * @see http://www.php.net/register-shutdown-function
+ *
* @return void
* @see register_shutdown_hook()
+ * @access private
*/
function _elgg_shutdown_hook() {
global $START_MICROTIME;
- elgg_trigger_event('shutdown', 'system');
+ try {
+ elgg_trigger_event('shutdown', 'system');
- $time = (float)(microtime(TRUE) - $START_MICROTIME);
- // demoted to NOTICE from DEBUG so javascript is not corrupted
- elgg_log("Page {$_SERVER['REQUEST_URI']} generated in $time seconds", 'NOTICE');
+ $time = (float)(microtime(TRUE) - $START_MICROTIME);
+ // demoted to NOTICE from DEBUG so javascript is not corrupted
+ elgg_log("Page {$_SERVER['REQUEST_URI']} generated in $time seconds", 'NOTICE');
+ } catch (Exception $e) {
+ $message = 'Error: ' . get_class($e) . ' thrown within the shutdown handler. ';
+ $message .= "Message: '{$e->getMessage()}' in file {$e->getFile()} (line {$e->getLine()})";
+ error_log($message);
+ error_log("Exception trace stack: {$e->getTraceAsString()}");
+ }
}
/**
@@ -1681,25 +1793,12 @@ function _elgg_shutdown_hook() {
*
* @param array $page The page array
*
- * @return void
+ * @return bool
* @elgg_pagehandler js
+ * @access private
*/
function elgg_js_page_handler($page) {
- if (is_array($page) && sizeof($page)) {
- $js = implode('/', $page);
- $js = substr($js, 0, strpos($js, '.'));
- $return = elgg_view('js/' . $js);
-
- header('Content-type: text/javascript');
-
- // @todo should js be cached when simple cache turned off
- //header('Expires: ' . date('r', time() + 864000));
- //header("Pragma: public");
- //header("Cache-Control: public");
- //header("Content-Length: " . strlen($return));
-
- echo $return;
- }
+ return elgg_cacheable_view_page_handler($page, 'js');
}
/**
@@ -1709,8 +1808,9 @@ function elgg_js_page_handler($page) {
*
* @param array $page The page array
*
- * @return void
+ * @return bool
* @elgg_pagehandler ajax
+ * @access private
*/
function elgg_ajax_page_handler($page) {
if (is_array($page) && sizeof($page)) {
@@ -1718,6 +1818,12 @@ function elgg_ajax_page_handler($page) {
unset($page[0]);
$view = implode('/', $page);
+ $allowed_views = elgg_get_config('allowed_ajax_views');
+ if (!array_key_exists($view, $allowed_views)) {
+ header('HTTP/1.1 403 Forbidden');
+ exit;
+ }
+
// pull out GET parameters through filter
$vars = array();
foreach ($_GET as $name => $value) {
@@ -1729,9 +1835,9 @@ function elgg_ajax_page_handler($page) {
}
echo elgg_view($view, $vars);
+ return true;
}
-
- return true;
+ return false;
}
/**
@@ -1741,26 +1847,71 @@ function elgg_ajax_page_handler($page) {
*
* @param array $page The page array
*
- * @return void
+ * @return bool
* @elgg_pagehandler css
+ * @access private
*/
function elgg_css_page_handler($page) {
if (!isset($page[0])) {
// default css
$page[0] = 'elgg';
}
+
+ return elgg_cacheable_view_page_handler($page, 'css');
+}
- $css = substr($page[0], 0, strpos($page[0], '.'));
- $return = elgg_view("css/$css");
+/**
+ * Serves a JS or CSS view with headers for caching.
+ *
+ * /<css||js>/name/of/view.<last_cache>.<css||js>
+ *
+ * @param array $page The page array
+ * @param string $type The type: js or css
+ *
+ * @return bool
+ * @access private
+ */
+function elgg_cacheable_view_page_handler($page, $type) {
- header("Content-type: text/css", true);
+ switch ($type) {
+ case 'js':
+ $content_type = 'text/javascript';
+ break;
- // @todo should css be cached when simple cache is turned off
- //header('Expires: ' . date('r', time() + 86400000), true);
- //header("Pragma: public", true);
- //header("Cache-Control: public", true);
+ case 'css':
+ $content_type = 'text/css';
+ break;
- echo $return;
+ default:
+ return false;
+ break;
+ }
+
+ if ($page) {
+ // the view file names can have multiple dots
+ // eg: views/default/js/calendars/jquery.fullcalendar.min.php
+ // translates to the url /js/calendars/jquery.fullcalendar.min.<ts>.js
+ // and the view js/calendars/jquery.fullcalendar.min
+ // we ignore the last two dots for the ts and the ext.
+ // Additionally, the timestamp is optional.
+ $page = implode('/', $page);
+ $regex = '|(.+?)\.([\d]+\.)?\w+$|';
+ preg_match($regex, $page, $matches);
+ $view = $matches[1];
+ $return = elgg_view("$type/$view");
+
+ header("Content-type: $content_type");
+
+ // @todo should js be cached when simple cache turned off
+ //header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', strtotime("+10 days")), true);
+ //header("Pragma: public");
+ //header("Cache-Control: public");
+ //header("Content-Length: " . strlen($return));
+
+ echo $return;
+ return true;
+ }
+ return false;
}
/**
@@ -1772,6 +1923,7 @@ function elgg_css_page_handler($page) {
* @param string $order_by An order by clause
* @access private
* @return string
+ * @access private
*/
function elgg_sql_reverse_order_by_clause($order_by) {
$order_by = strtolower($order_by);
@@ -1793,9 +1945,11 @@ function elgg_sql_reverse_order_by_clause($order_by) {
*
* Used as a callback for ElggBatch.
*
+ * @todo why aren't these static methods on ElggBatch?
+ *
* @param object $object The object to enable
- * @access private
* @return bool
+ * @access private
*/
function elgg_batch_enable_callback($object) {
// our db functions return the number of rows affected...
@@ -1808,8 +1962,8 @@ function elgg_batch_enable_callback($object) {
* Used as a callback for ElggBatch.
*
* @param object $object The object to disable
- * @access private
* @return bool
+ * @access private
*/
function elgg_batch_disable_callback($object) {
// our db functions return the number of rows affected...
@@ -1822,8 +1976,8 @@ function elgg_batch_disable_callback($object) {
* Used as a callback for ElggBatch.
*
* @param object $object The object to disable
- * @access private
* @return bool
+ * @access private
*/
function elgg_batch_delete_callback($object) {
// our db functions return the number of rows affected...
@@ -1837,6 +1991,7 @@ function elgg_batch_delete_callback($object) {
* @param array $options Options array
* @param string $type Options type: metadata or annotations
* @return bool
+ * @access private
*/
function elgg_is_valid_options_for_batch_operation($options, $type) {
if (!$options || !is_array($options)) {
@@ -1846,7 +2001,7 @@ function elgg_is_valid_options_for_batch_operation($options, $type) {
// at least one of these is required.
$required = array(
// generic restraints
- 'guid', 'guids', 'limit'
+ 'guid', 'guids'
);
switch ($type) {
@@ -1890,21 +2045,56 @@ function elgg_is_valid_options_for_batch_operation($options, $type) {
*
* @link http://docs.elgg.org/Tutorials/WalledGarden
* @elgg_plugin_hook index system
- * @return boolean
+ *
+ * @param string $hook The name of the hook
+ * @param string $type The type of hook
+ * @param bool $value Has a plugin already rendered an index page?
+ * @param array $params Array of parameters (should be empty)
+ * @return bool
+ * @access private
*/
-function elgg_walled_garden_index() {
- elgg_register_css('elgg.walled_garden', '/css/walled_garden.css');
+function elgg_walled_garden_index($hook, $type, $value, $params) {
+ if ($value) {
+ // do not create a second index page so return
+ return;
+ }
+
elgg_load_css('elgg.walled_garden');
+ elgg_load_js('elgg.walled_garden');
- $login = elgg_view('core/account/login_walled_garden');
+ $content = elgg_view('core/walled_garden/login');
- echo elgg_view_page('', $login, 'walled_garden');
+ $params = array(
+ 'content' => $content,
+ 'class' => 'elgg-walledgarden-double',
+ 'id' => 'elgg-walledgarden-login',
+ );
+ $body = elgg_view_layout('walled_garden', $params);
+ echo elgg_view_page('', $body, 'walled_garden');
// return true to prevent other plugins from adding a front page
return true;
}
/**
+ * Serve walled garden sections
+ *
+ * @param array $page Array of URL segments
+ * @return string
+ * @access private
+ */
+function _elgg_walled_garden_ajax_handler($page) {
+ $view = $page[0];
+ $params = array(
+ 'content' => elgg_view("core/walled_garden/$view"),
+ 'class' => 'elgg-walledgarden-single hidden',
+ 'id' => str_replace('_', '-', "elgg-walledgarden-$view"),
+ );
+ echo elgg_view_layout('walled_garden', $params);
+ return true;
+}
+
+/**
* Checks the status of the Walled Garden and forwards to a login page
* if required.
*
@@ -1916,10 +2106,16 @@ function elgg_walled_garden_index() {
* @elgg_event_handler init system
* @link http://docs.elgg.org/Tutorials/WalledGarden
* @return void
+ * @access private
*/
function elgg_walled_garden() {
global $CONFIG;
+ elgg_register_css('elgg.walled_garden', '/css/walled_garden.css');
+ elgg_register_js('elgg.walled_garden', '/js/walled_garden.js');
+
+ elgg_register_page_handler('walled_garden', '_elgg_walled_garden_ajax_handler');
+
// check for external page view
if (isset($CONFIG->site) && $CONFIG->site instanceof ElggSite) {
$CONFIG->site->checkWalledGarden();
@@ -1927,12 +2123,61 @@ function elgg_walled_garden() {
}
/**
+ * Remove public access for walled gardens
+ *
+ * @param string $hook
+ * @param string $type
+ * @param array $accesses
+ * @return array
+ * @access private
+ */
+function _elgg_walled_garden_remove_public_access($hook, $type, $accesses) {
+ if (isset($accesses[ACCESS_PUBLIC])) {
+ unset($accesses[ACCESS_PUBLIC]);
+ }
+ return $accesses;
+}
+
+/**
+ * Boots the engine
+ *
+ * 1. sets error handlers
+ * 2. connects to database
+ * 3. verifies the installation suceeded
+ * 4. loads application configuration
+ * 5. loads i18n data
+ * 6. loads site configuration
+ *
+ * @access private
+ */
+function _elgg_engine_boot() {
+ // Register the error handlers
+ set_error_handler('_elgg_php_error_handler');
+ set_exception_handler('_elgg_php_exception_handler');
+
+ setup_db_connections();
+
+ verify_installation();
+
+ _elgg_load_application_config();
+
+ _elgg_load_site_config();
+
+ _elgg_session_boot();
+
+ _elgg_load_cache();
+
+ _elgg_load_translations();
+}
+
+/**
* Elgg's main init.
*
* Handles core actions for comments, the JS pagehandler, and the shutdown function.
*
* @elgg_event_handler init system
* @return void
+ * @access private
*/
function elgg_init() {
global $CONFIG;
@@ -1944,11 +2189,17 @@ function elgg_init() {
elgg_register_page_handler('css', 'elgg_css_page_handler');
elgg_register_page_handler('ajax', 'elgg_ajax_page_handler');
- elgg_register_js('elgg.autocomplete', 'js/lib/autocomplete.js');
- elgg_register_js('elgg.userpicker', 'js/lib/userpicker.js');
- elgg_register_js('elgg.friendspicker', 'js/lib/friends_picker.js');
+ elgg_register_js('elgg.autocomplete', 'js/lib/ui.autocomplete.js');
+ elgg_register_js('jquery.ui.autocomplete.html', 'vendors/jquery/jquery.ui.autocomplete.html.js');
+ elgg_register_js('elgg.userpicker', 'js/lib/ui.userpicker.js');
+ elgg_register_js('elgg.friendspicker', 'js/lib/ui.friends_picker.js');
elgg_register_js('jquery.easing', 'vendors/jquery/jquery.easing.1.3.packed.js');
+ elgg_register_js('elgg.avatar_cropper', 'js/lib/ui.avatar_cropper.js');
+ elgg_register_js('jquery.imgareaselect', 'vendors/jquery/jquery.imgareaselect-0.9.8/scripts/jquery.imgareaselect.min.js');
+ elgg_register_js('elgg.ui.river', 'js/lib/ui.river.js');
+ elgg_register_css('jquery.imgareaselect', 'vendors/jquery/jquery.imgareaselect-0.9.8/css/imgareaselect-deprecated.css');
+
// Trigger the shutdown:system event upon PHP shutdown.
register_shutdown_function('_elgg_shutdown_hook');
@@ -1956,8 +2207,9 @@ function elgg_init() {
elgg_register_menu_item('topbar', array(
'name' => 'elgg_logo',
'href' => 'http://www.elgg.org/',
- 'text' => "<img src=\"$logo_url\" alt=\"Elgg logo\" />",
+ 'text' => "<img src=\"$logo_url\" alt=\"Elgg logo\" width=\"38\" height=\"20\" />",
'priority' => 1,
+ 'link_class' => 'elgg-topbar-logo',
));
// Sets a blacklist of words in the current language.
@@ -1981,7 +2233,8 @@ function elgg_init() {
* @param array $params empty
*
* @elgg_plugin_hook unit_tests system
- * @return void
+ * @return array
+ * @access private
*/
function elgg_api_test($hook, $type, $value, $params) {
global $CONFIG;
@@ -1992,7 +2245,10 @@ function elgg_api_test($hook, $type, $value, $params) {
}
/**#@+
- * Controlls access levels on ElggEntity entities, metadata, and annotations.
+ * Controls access levels on ElggEntity entities, metadata, and annotations.
+ *
+ * @warning ACCESS_DEFAULT is a place holder for the input/access view. Do not
+ * use it when saving an entity.
*
* @var int
*/
@@ -2026,7 +2282,7 @@ define('ELGG_ENTITIES_NO_VALUE', 0);
* referring page.
*
* @see forward
- * @var unknown_type
+ * @var int -1
*/
define('REFERRER', -1);
@@ -2041,6 +2297,7 @@ define('REFERRER', -1);
define('REFERER', -1);
elgg_register_event_handler('init', 'system', 'elgg_init');
+elgg_register_event_handler('boot', 'system', '_elgg_engine_boot', 1);
elgg_register_plugin_hook_handler('unit_test', 'system', 'elgg_api_test');
elgg_register_event_handler('init', 'system', 'add_custom_menu_items', 1000);
diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index 742630cc7..4fcf1c657 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -17,13 +17,50 @@ global $ENTITY_CACHE;
$ENTITY_CACHE = array();
/**
- * Cache subtypes and related class names once loaded.
+ * GUIDs of entities banned from the entity cache (during this request)
*
- * @global array $SUBTYPE_CACHE
+ * @global array $ENTITY_CACHE_DISABLED_GUIDS
+ * @access private
+ */
+global $ENTITY_CACHE_DISABLED_GUIDS;
+$ENTITY_CACHE_DISABLED_GUIDS = array();
+
+/**
+ * Cache subtypes and related class names.
+ *
+ * @global array|null $SUBTYPE_CACHE array once populated from DB, initially null
* @access private
*/
global $SUBTYPE_CACHE;
-$SUBTYPE_CACHE = NULL;
+$SUBTYPE_CACHE = null;
+
+/**
+ * Remove this entity from the entity cache and make sure it is not re-added
+ *
+ * @param int $guid The entity guid
+ *
+ * @access private
+ * @todo this is a workaround until #5604 can be implemented
+ */
+function _elgg_disable_caching_for_entity($guid) {
+ global $ENTITY_CACHE_DISABLED_GUIDS;
+
+ _elgg_invalidate_cache_for_entity($guid);
+ $ENTITY_CACHE_DISABLED_GUIDS[$guid] = true;
+}
+
+/**
+ * Allow this entity to be stored in the entity cache
+ *
+ * @param int $guid The entity guid
+ *
+ * @access private
+ */
+function _elgg_enable_caching_for_entity($guid) {
+ global $ENTITY_CACHE_DISABLED_GUIDS;
+
+ unset($ENTITY_CACHE_DISABLED_GUIDS[$guid]);
+}
/**
* Invalidate this class's entry in the cache.
@@ -33,12 +70,14 @@ $SUBTYPE_CACHE = NULL;
* @return void
* @access private
*/
-function invalidate_cache_for_entity($guid) {
+function _elgg_invalidate_cache_for_entity($guid) {
global $ENTITY_CACHE;
$guid = (int)$guid;
unset($ENTITY_CACHE[$guid]);
+
+ elgg_get_metadata_cache()->clear($guid);
}
/**
@@ -49,60 +88,59 @@ function invalidate_cache_for_entity($guid) {
* @param ElggEntity $entity Entity to cache
*
* @return void
- * @see retrieve_cached_entity()
- * @see invalidate_cache_for_entity()
+ * @see _elgg_retrieve_cached_entity()
+ * @see _elgg_invalidate_cache_for_entity()
* @access private
+ * @todo Use an ElggCache object
*/
-function cache_entity(ElggEntity $entity) {
- global $ENTITY_CACHE;
+function _elgg_cache_entity(ElggEntity $entity) {
+ global $ENTITY_CACHE, $ENTITY_CACHE_DISABLED_GUIDS;
- $ENTITY_CACHE[$entity->guid] = $entity;
-}
+ // Don't cache non-plugin entities while access control is off, otherwise they could be
+ // exposed to users who shouldn't see them when control is re-enabled.
+ if (!($entity instanceof ElggPlugin) && elgg_get_ignore_access()) {
+ return;
+ }
-/**
- * Retrieve a entity from the cache.
- *
- * @param int $guid The guid
- *
- * @return void
- * @see cache_entity()
- * @see invalidate_cache_for_entity()
- * @access private
- */
-function retrieve_cached_entity($guid) {
- global $ENTITY_CACHE;
+ $guid = $entity->getGUID();
+ if (isset($ENTITY_CACHE_DISABLED_GUIDS[$guid])) {
+ return;
+ }
- $guid = (int)$guid;
+ // Don't store too many or we'll have memory problems
+ // @todo Pick a less arbitrary limit
+ if (count($ENTITY_CACHE) > 256) {
+ $random_guid = array_rand($ENTITY_CACHE);
- if (isset($ENTITY_CACHE[$guid])) {
- if ($ENTITY_CACHE[$guid]->isFullyLoaded()) {
- return $ENTITY_CACHE[$guid];
- }
+ unset($ENTITY_CACHE[$random_guid]);
+
+ // Purge separate metadata cache. Original idea was to do in entity destructor, but that would
+ // have caused a bunch of unnecessary purges at every shutdown. Doing it this way we have no way
+ // to know that the expunged entity will be GCed (might be another reference living), but that's
+ // OK; the metadata will reload if necessary.
+ elgg_get_metadata_cache()->clear($random_guid);
}
- return false;
+ $ENTITY_CACHE[$guid] = $entity;
}
/**
- * As retrieve_cached_entity, but returns the result as a stdClass
- * (compatible with load functions that expect a database row.)
+ * Retrieve a entity from the cache.
*
* @param int $guid The guid
*
- * @return mixed
- * @todo unused
+ * @return ElggEntity|bool false if entity not cached, or not fully loaded
+ * @see _elgg_cache_entity()
+ * @see _elgg_invalidate_cache_for_entity()
* @access private
*/
-function retrieve_cached_entity_row($guid) {
- $obj = retrieve_cached_entity($guid);
- if ($obj) {
- $tmp = new stdClass;
+function _elgg_retrieve_cached_entity($guid) {
+ global $ENTITY_CACHE;
- foreach ($obj as $k => $v) {
- $tmp->$k = $v;
+ if (isset($ENTITY_CACHE[$guid])) {
+ if ($ENTITY_CACHE[$guid]->isFullyLoaded()) {
+ return $ENTITY_CACHE[$guid];
}
-
- return $tmp;
}
return false;
@@ -124,8 +162,6 @@ function retrieve_cached_entity_row($guid) {
* @internal Subtypes are stored in the entity_subtypes table. There is a foreign
* key in the entities table.
*
- * @todo Move to a nicer place?
- *
* @param string $type Type
* @param string $subtype Subtype
*
@@ -135,75 +171,99 @@ function retrieve_cached_entity_row($guid) {
* @access private
*/
function get_subtype_id($type, $subtype) {
- global $CONFIG, $SUBTYPE_CACHE;
+ global $SUBTYPE_CACHE;
- $type = sanitise_string($type);
- $subtype = sanitise_string($subtype);
-
- if ($subtype == "") {
- return FALSE;
+ if (!$subtype) {
+ return false;
}
- // Todo: cache here? Or is looping less efficient that going to the db each time?
- $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes
- where type='$type' and subtype='$subtype'");
-
- if ($result) {
- if (!$SUBTYPE_CACHE) {
- $SUBTYPE_CACHE = array();
- }
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
- $SUBTYPE_CACHE[$result->id] = $result;
+ // use the cache before hitting database
+ $result = _elgg_retrieve_cached_subtype($type, $subtype);
+ if ($result !== null) {
return $result->id;
}
- return FALSE;
+ return false;
}
/**
* Return string name for a given subtype ID.
*
- * @todo Move to a nicer place?
- *
* @param int $subtype_id Subtype ID
*
- * @return string Subtype name
+ * @return string|false Subtype name, false if subtype not found
* @link http://docs.elgg.org/DataModel/Entities/Subtypes
* @see get_subtype_from_id()
* @access private
*/
function get_subtype_from_id($subtype_id) {
- global $CONFIG, $SUBTYPE_CACHE;
-
- $subtype_id = (int)$subtype_id;
+ global $SUBTYPE_CACHE;
if (!$subtype_id) {
return false;
}
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
+
if (isset($SUBTYPE_CACHE[$subtype_id])) {
return $SUBTYPE_CACHE[$subtype_id]->subtype;
}
- $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes where id=$subtype_id");
- if ($result) {
- if (!$SUBTYPE_CACHE) {
- $SUBTYPE_CACHE = array();
- }
+ return false;
+}
- $SUBTYPE_CACHE[$subtype_id] = $result;
- return $result->subtype;
+/**
+ * Retrieve subtype from the cache.
+ *
+ * @param string $type
+ * @param string $subtype
+ * @return stdClass|null
+ *
+ * @access private
+ */
+function _elgg_retrieve_cached_subtype($type, $subtype) {
+ global $SUBTYPE_CACHE;
+
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
}
- return false;
+ foreach ($SUBTYPE_CACHE as $obj) {
+ if ($obj->type === $type && $obj->subtype === $subtype) {
+ return $obj;
+ }
+ }
+ return null;
+}
+
+/**
+ * Fetch all suptypes from DB to local cache.
+ *
+ * @access private
+ */
+function _elgg_populate_subtype_cache() {
+ global $CONFIG, $SUBTYPE_CACHE;
+
+ $results = get_data("SELECT * FROM {$CONFIG->dbprefix}entity_subtypes");
+
+ $SUBTYPE_CACHE = array();
+ foreach ($results as $row) {
+ $SUBTYPE_CACHE[$row->id] = $row;
+ }
}
/**
- * Return a classname for a registered type and subtype.
+ * Return the class name for a registered type and subtype.
*
* Entities can be registered to always be loaded as a certain class
- * with {@link register_entity_subtype()}. This function returns
- * the class name if found, and NULL if not.
+ * with add_subtype() or update_subtype(). This function returns the class
+ * name if found and NULL if not.
*
* @param string $type The type
* @param string $subtype The subtype
@@ -214,29 +274,23 @@ function get_subtype_from_id($subtype_id) {
* @access private
*/
function get_subtype_class($type, $subtype) {
- global $CONFIG, $SUBTYPE_CACHE;
-
- $type = sanitise_string($type);
- $subtype = sanitise_string($subtype);
-
- // Todo: cache here? Or is looping less efficient that going to the db each time?
- $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes
- where type='$type' and subtype='$subtype'");
+ global $SUBTYPE_CACHE;
- if ($result) {
- if (!$SUBTYPE_CACHE) {
- $SUBTYPE_CACHE = array();
- }
-
- $SUBTYPE_CACHE[$result->id] = $result;
- return $result->class;
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
+
+ // use the cache before going to the database
+ $obj = _elgg_retrieve_cached_subtype($type, $subtype);
+ if ($obj) {
+ return $obj->class;
}
- return NULL;
+ return null;
}
/**
- * Returns the classname for a subtype id.
+ * Returns the class name for a subtype id.
*
* @param int $subtype_id The subtype id
*
@@ -246,29 +300,21 @@ function get_subtype_class($type, $subtype) {
* @access private
*/
function get_subtype_class_from_id($subtype_id) {
- global $CONFIG, $SUBTYPE_CACHE;
-
- $subtype_id = (int)$subtype_id;
+ global $SUBTYPE_CACHE;
if (!$subtype_id) {
- return false;
+ return null;
}
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
+
if (isset($SUBTYPE_CACHE[$subtype_id])) {
return $SUBTYPE_CACHE[$subtype_id]->class;
}
- $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes where id=$subtype_id");
-
- if ($result) {
- if (!$SUBTYPE_CACHE) {
- $SUBTYPE_CACHE = array();
- }
- $SUBTYPE_CACHE[$subtype_id] = $result;
- return $result->class;
- }
-
- return NULL;
+ return null;
}
/**
@@ -279,6 +325,9 @@ function get_subtype_class_from_id($subtype_id) {
* it will be loaded as that class automatically when retrieved from the database with
* {@link get_entity()}.
*
+ * @warning This function cannot be used to change the class for a type-subtype pair.
+ * Use update_subtype() for that.
+ *
* @param string $type The type you're subtyping (site, user, object, or group)
* @param string $subtype The subtype
* @param string $class Optional class name for the object
@@ -291,21 +340,32 @@ function get_subtype_class_from_id($subtype_id) {
* @see get_entity()
*/
function add_subtype($type, $subtype, $class = "") {
- global $CONFIG;
- $type = sanitise_string($type);
- $subtype = sanitise_string($subtype);
- $class = sanitise_string($class);
+ global $CONFIG, $SUBTYPE_CACHE;
- // Short circuit if no subtype is given
- if ($subtype == "") {
+ if (!$subtype) {
return 0;
}
$id = get_subtype_id($type, $subtype);
- if ($id == 0) {
- return insert_data("insert into {$CONFIG->dbprefix}entity_subtypes"
- . " (type, subtype, class) values ('$type','$subtype','$class')");
+ if (!$id) {
+ // In cache we store non-SQL-escaped strings because that's what's returned by query
+ $cache_obj = (object) array(
+ 'type' => $type,
+ 'subtype' => $subtype,
+ 'class' => $class,
+ );
+
+ $type = sanitise_string($type);
+ $subtype = sanitise_string($subtype);
+ $class = sanitise_string($class);
+
+ $id = insert_data("INSERT INTO {$CONFIG->dbprefix}entity_subtypes"
+ . " (type, subtype, class) VALUES ('$type', '$subtype', '$class')");
+
+ // add entry to cache
+ $cache_obj->id = $id;
+ $SUBTYPE_CACHE[$id] = $cache_obj;
}
return $id;
@@ -314,6 +374,10 @@ function add_subtype($type, $subtype, $class = "") {
/**
* Removes a registered ElggEntity type, subtype, and classname.
*
+ * @warning You do not want to use this function. If you want to unregister
+ * a class for a subtype, use update_subtype(). Using this function will
+ * permanently orphan all the objects created with the specified subtype.
+ *
* @param string $type Type
* @param string $subtype Subtype
*
@@ -332,7 +396,7 @@ function remove_subtype($type, $subtype) {
}
/**
- * Update a registered ElggEntity type, subtype, and classname
+ * Update a registered ElggEntity type, subtype, and class name
*
* @param string $type Type
* @param string $subtype Subtype
@@ -341,18 +405,33 @@ function remove_subtype($type, $subtype) {
* @return bool
*/
function update_subtype($type, $subtype, $class = '') {
- global $CONFIG;
+ global $CONFIG, $SUBTYPE_CACHE;
- if (!$id = get_subtype_id($type, $subtype)) {
- return FALSE;
+ $id = get_subtype_id($type, $subtype);
+ if (!$id) {
+ return false;
+ }
+
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
}
+
+ $unescaped_class = $class;
+
$type = sanitise_string($type);
$subtype = sanitise_string($subtype);
-
- return update_data("UPDATE {$CONFIG->dbprefix}entity_subtypes
+ $class = sanitise_string($class);
+
+ $success = update_data("UPDATE {$CONFIG->dbprefix}entity_subtypes
SET type = '$type', subtype = '$subtype', class = '$class'
WHERE id = $id
");
+
+ if ($success && isset($SUBTYPE_CACHE[$id])) {
+ $SUBTYPE_CACHE[$id]->class = $unescaped_class;
+ }
+
+ return $success;
}
/**
@@ -370,7 +449,7 @@ function update_subtype($type, $subtype, $class = '') {
* @param int $time_created The time creation timestamp
*
* @return bool
- * @link http://docs.elgg.org/DataModel/Entities
+ * @throws InvalidParameterException
* @access private
*/
function update_entity($guid, $owner_guid, $access_id, $container_guid = null, $time_created = null) {
@@ -393,6 +472,10 @@ function update_entity($guid, $owner_guid, $access_id, $container_guid = null, $
$time_created = (int) $time_created;
}
+ if ($access_id == ACCESS_DEFAULT) {
+ throw new InvalidParameterException('ACCESS_DEFAULT is not a valid access level. See its documentation in elgglib.h');
+ }
+
if ($entity && $entity->canEdit()) {
if (elgg_trigger_event('update', $entity->type, $entity)) {
$ret = update_data("UPDATE {$CONFIG->dbprefix}entities
@@ -410,7 +493,7 @@ function update_entity($guid, $owner_guid, $access_id, $container_guid = null, $
$newentity_cache = new ElggMemcache('new_entity_cache');
}
if ($newentity_cache) {
- $new_entity = $newentity_cache->delete($guid);
+ $newentity_cache->delete($guid);
}
// Handle cases where there was no error BUT no rows were updated!
@@ -452,8 +535,10 @@ function can_write_to_container($user_guid = 0, $container_guid = 0, $type = 'al
$container_guid = elgg_get_page_owner_guid();
}
+ $return = false;
+
if (!$container_guid) {
- $return = TRUE;
+ $return = true;
}
$container = get_entity($container_guid);
@@ -461,16 +546,15 @@ function can_write_to_container($user_guid = 0, $container_guid = 0, $type = 'al
if ($container) {
// If the user can edit the container, they can also write to it
if ($container->canEdit($user_guid)) {
- $return = TRUE;
+ $return = true;
}
- // Basics, see if the user is a member of the group.
+ // If still not approved, see if the user is a member of the group
// @todo this should be moved to the groups plugin/library
- if ($user && $container instanceof ElggGroup) {
- if (!$container->isMember($user)) {
- $return = FALSE;
- } else {
- $return = TRUE;
+ if (!$return && $user && $container instanceof ElggGroup) {
+ /* @var ElggGroup $container */
+ if ($container->isMember($user)) {
+ $return = true;
}
}
}
@@ -507,8 +591,8 @@ function can_write_to_container($user_guid = 0, $container_guid = 0, $type = 'al
*
* @return int|false The new entity's GUID, or false on failure
* @throws InvalidParameterException
- * @access private
* @link http://docs.elgg.org/DataModel/Entities
+ * @access private
*/
function create_entity($type, $subtype, $owner_guid, $access_id, $site_guid = 0,
$container_guid = 0) {
@@ -518,7 +602,6 @@ $container_guid = 0) {
$type = sanitise_string($type);
$subtype_id = add_subtype($type, $subtype);
$owner_guid = (int)$owner_guid;
- $access_id = (int)$access_id;
$time = time();
if ($site_guid == 0) {
$site_guid = $CONFIG->site_guid;
@@ -527,13 +610,17 @@ $container_guid = 0) {
if ($container_guid == 0) {
$container_guid = $owner_guid;
}
+ $access_id = (int)$access_id;
+ if ($access_id == ACCESS_DEFAULT) {
+ throw new InvalidParameterException('ACCESS_DEFAULT is not a valid access level. See its documentation in elgglib.h');
+ }
- $user = elgg_get_logged_in_user_entity();
- if (!can_write_to_container($user->guid, $owner_guid, $type, $subtype)) {
+ $user_guid = elgg_get_logged_in_user_guid();
+ if (!can_write_to_container($user_guid, $owner_guid, $type, $subtype)) {
return false;
}
if ($owner_guid != $container_guid) {
- if (!can_write_to_container($user->guid, $container_guid, $type, $subtype)) {
+ if (!can_write_to_container($user_guid, $container_guid, $type, $subtype)) {
return false;
}
}
@@ -584,12 +671,14 @@ function get_entity_as_row($guid) {
*
* @param stdClass $row The row of the entry in the entities table.
*
- * @return object|false
+ * @return ElggEntity|false
* @link http://docs.elgg.org/DataModel/Entities
* @see get_entity_as_row()
* @see add_subtype()
* @see get_entity()
* @access private
+ *
+ * @throws ClassException|InstallationException
*/
function entity_row_to_elggstar($row) {
if (!($row instanceof stdClass)) {
@@ -667,26 +756,59 @@ function entity_row_to_elggstar($row) {
* @link http://docs.elgg.org/DataModel/Entities
*/
function get_entity($guid) {
- static $newentity_cache;
- $new_entity = false;
+ // This should not be a static local var. Notice that cache writing occurs in a completely
+ // different instance outside this function.
+ // @todo We need a single Memcache instance with a shared pool of namespace wrappers. This function would pull an instance from the pool.
+ static $shared_cache;
+
+ // We could also use: if (!(int) $guid) { return FALSE },
+ // but that evaluates to a false positive for $guid = TRUE.
+ // This is a bit slower, but more thorough.
+ if (!is_numeric($guid) || $guid === 0 || $guid === '0') {
+ return false;
+ }
+
+ // Check local cache first
+ $new_entity = _elgg_retrieve_cached_entity($guid);
+ if ($new_entity) {
+ return $new_entity;
+ }
- if (!is_numeric($guid)) {
- return FALSE;
+ // Check shared memory cache, if available
+ if (null === $shared_cache) {
+ if (is_memcache_available()) {
+ $shared_cache = new ElggMemcache('new_entity_cache');
+ } else {
+ $shared_cache = false;
+ }
}
- if ((!$newentity_cache) && (is_memcache_available())) {
- $newentity_cache = new ElggMemcache('new_entity_cache');
+ // until ACLs in memcache, DB query is required to determine access
+ $entity_row = get_entity_as_row($guid);
+ if (!$entity_row) {
+ return false;
}
- if ($newentity_cache) {
- $new_entity = $newentity_cache->load($guid);
+ if ($shared_cache) {
+ $cached_entity = $shared_cache->load($guid);
+ // @todo store ACLs in memcache https://github.com/elgg/elgg/issues/3018#issuecomment-13662617
+ if ($cached_entity) {
+ // @todo use ACL and cached entity access_id to determine if user can see it
+ return $cached_entity;
+ }
}
- if ($new_entity) {
- return $new_entity;
+ // don't let incomplete entities cause fatal exceptions
+ try {
+ $new_entity = entity_row_to_elggstar($entity_row);
+ } catch (IncompleteEntityException $e) {
+ return false;
}
- return entity_row_to_elggstar(get_entity_as_row($guid));
+ if ($new_entity) {
+ _elgg_cache_entity($new_entity);
+ }
+ return $new_entity;
}
/**
@@ -736,11 +858,12 @@ function elgg_entity_exists($guid) {
* Joined with subtypes by AND. See below)
*
* subtypes => NULL|STR entity subtype (SQL: subtype IN ('subtype1', 'subtype2))
+ * Use ELGG_ENTITIES_NO_VALUE for no subtype.
*
* type_subtype_pairs => NULL|ARR (array('type' => 'subtype'))
* (type = '$type' AND subtype = '$subtype') pairs
*
- * entity_guids => NULL|ARR Array of entity guids
+ * guids => NULL|ARR Array of entity guids
*
* owner_guids => NULL|ARR Array of owner guids
*
@@ -772,7 +895,7 @@ function elgg_entity_exists($guid) {
*
* callback => string A callback function to pass each row through
*
- * @return mixed int if count is true, an array of entity objects, or false on failure
+ * @return mixed If count, int. If not count, array. false on errors.
* @since 1.7.0
* @see elgg_get_entities_from_metadata()
* @see elgg_get_entities_from_relationship()
@@ -810,6 +933,8 @@ function elgg_get_entities(array $options = array()) {
'joins' => array(),
'callback' => 'entity_row_to_elggstar',
+
+ '__ElggBatch' => null,
);
$options = array_merge($defaults, $options);
@@ -846,9 +971,6 @@ function elgg_get_entities(array $options = array()) {
$wheres[] = elgg_get_entity_time_where_sql('e', $options['created_time_upper'],
$options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']);
- // remove identical where clauses
- $wheres = array_unique($wheres);
-
// see if any functions failed
// remove empty strings on successful functions
foreach ($wheres as $i => $where) {
@@ -859,6 +981,9 @@ function elgg_get_entities(array $options = array()) {
}
}
+ // remove identical where clauses
+ $wheres = array_unique($wheres);
+
// evaluate join clauses
if (!is_array($options['joins'])) {
$options['joins'] = array($options['joins']);
@@ -912,21 +1037,46 @@ function elgg_get_entities(array $options = array()) {
}
if (!$options['count']) {
- if ($options['group_by'] = sanitise_string($options['group_by'])) {
+ if ($options['group_by']) {
$query .= " GROUP BY {$options['group_by']}";
}
- if ($options['order_by'] = sanitise_string($options['order_by'])) {
+ if ($options['order_by']) {
$query .= " ORDER BY {$options['order_by']}";
}
if ($options['limit']) {
- $limit = sanitise_int($options['limit']);
- $offset = sanitise_int($options['offset']);
+ $limit = sanitise_int($options['limit'], false);
+ $offset = sanitise_int($options['offset'], false);
$query .= " LIMIT $offset, $limit";
}
- $dt = get_data($query, $options['callback']);
+ if ($options['callback'] === 'entity_row_to_elggstar') {
+ $dt = _elgg_fetch_entities_from_sql($query, $options['__ElggBatch']);
+ } else {
+ $dt = get_data($query, $options['callback']);
+ }
+
+ if ($dt) {
+ // populate entity and metadata caches
+ $guids = array();
+ foreach ($dt as $item) {
+ // A custom callback could result in items that aren't ElggEntity's, so check for them
+ if ($item instanceof ElggEntity) {
+ _elgg_cache_entity($item);
+ // plugins usually have only settings
+ if (!$item instanceof ElggPlugin) {
+ $guids[] = $item->guid;
+ }
+ }
+ }
+ // @todo Without this, recursive delete fails. See #4568
+ reset($dt);
+
+ if ($guids) {
+ elgg_get_metadata_cache()->populateFromEntities($guids);
+ }
+ }
return $dt;
} else {
$total = get_data_row($query);
@@ -935,6 +1085,104 @@ function elgg_get_entities(array $options = array()) {
}
/**
+ * Return entities from an SQL query generated by elgg_get_entities.
+ *
+ * @param string $sql
+ * @param ElggBatch $batch
+ * @return ElggEntity[]
+ *
+ * @access private
+ * @throws LogicException
+ */
+function _elgg_fetch_entities_from_sql($sql, ElggBatch $batch = null) {
+ static $plugin_subtype;
+ if (null === $plugin_subtype) {
+ $plugin_subtype = get_subtype_id('object', 'plugin');
+ }
+
+ // Keys are types, values are columns that, if present, suggest that the secondary
+ // table is already JOINed
+ $types_to_optimize = array(
+ 'object' => 'title',
+ 'user' => 'password',
+ 'group' => 'name',
+ );
+
+ $rows = get_data($sql);
+
+ // guids to look up in each type
+ $lookup_types = array();
+ // maps GUIDs to the $rows key
+ $guid_to_key = array();
+
+ if (isset($rows[0]->type, $rows[0]->subtype)
+ && $rows[0]->type === 'object'
+ && $rows[0]->subtype == $plugin_subtype) {
+ // Likely the entire resultset is plugins, which have already been optimized
+ // to JOIN the secondary table. In this case we allow retrieving from cache,
+ // but abandon the extra queries.
+ $types_to_optimize = array();
+ }
+
+ // First pass: use cache where possible, gather GUIDs that we're optimizing
+ foreach ($rows as $i => $row) {
+ if (empty($row->guid) || empty($row->type)) {
+ throw new LogicException('Entity row missing guid or type');
+ }
+ if ($entity = _elgg_retrieve_cached_entity($row->guid)) {
+ $rows[$i] = $entity;
+ continue;
+ }
+ if (isset($types_to_optimize[$row->type])) {
+ // check if row already looks JOINed.
+ if (isset($row->{$types_to_optimize[$row->type]})) {
+ // Row probably already contains JOINed secondary table. Don't make another query just
+ // to pull data that's already there
+ continue;
+ }
+ $lookup_types[$row->type][] = $row->guid;
+ $guid_to_key[$row->guid] = $i;
+ }
+ }
+ // Do secondary queries and merge rows
+ if ($lookup_types) {
+ $dbprefix = elgg_get_config('dbprefix');
+
+ foreach ($lookup_types as $type => $guids) {
+ $set = "(" . implode(',', $guids) . ")";
+ $sql = "SELECT * FROM {$dbprefix}{$type}s_entity WHERE guid IN $set";
+ $secondary_rows = get_data($sql);
+ if ($secondary_rows) {
+ foreach ($secondary_rows as $secondary_row) {
+ $key = $guid_to_key[$secondary_row->guid];
+ // cast to arrays to merge then cast back
+ $rows[$key] = (object)array_merge((array)$rows[$key], (array)$secondary_row);
+ }
+ }
+ }
+ }
+ // Second pass to finish conversion
+ foreach ($rows as $i => $row) {
+ if ($row instanceof ElggEntity) {
+ continue;
+ } else {
+ try {
+ $rows[$i] = entity_row_to_elggstar($row);
+ } catch (IncompleteEntityException $e) {
+ // don't let incomplete entities throw fatal errors
+ unset($rows[$i]);
+
+ // report incompletes to the batch process that spawned this query
+ if ($batch) {
+ $batch->reportIncompleteEntity($row);
+ }
+ }
+ }
+ }
+ return $rows;
+}
+
+/**
* Returns SQL where clause for type and subtype on main entity table
*
* @param string $table Entity table prefix as defined in SELECT...FROM entities $table
@@ -958,8 +1206,8 @@ function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pair
return '';
}
- // these are the only valid types for entities in elgg as defined in the DB.
- $valid_types = array('object', 'user', 'group', 'site');
+ // these are the only valid types for entities in elgg
+ $valid_types = elgg_get_config('entity_types');
// pairs override
$wheres = array();
@@ -985,7 +1233,7 @@ function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pair
foreach ($types as $type) {
if (!in_array($type, $valid_types)) {
$valid_types_count--;
- unset ($types[array_search($type, $types)]);
+ unset($types[array_search($type, $types)]);
} else {
// do the checking (and decrementing) in the subtype section.
$valid_subtypes_count += count($subtypes);
@@ -1003,13 +1251,24 @@ function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pair
$subtype_ids = array();
if ($subtypes) {
foreach ($subtypes as $subtype) {
- // check that the subtype is valid (with ELGG_ENTITIES_NO_VALUE being a valid subtype)
- if (ELGG_ENTITIES_NO_VALUE === $subtype || $subtype_id = get_subtype_id($type, $subtype)) {
- $subtype_ids[] = (ELGG_ENTITIES_NO_VALUE === $subtype) ? ELGG_ENTITIES_NO_VALUE : $subtype_id;
- } else {
- $valid_subtypes_count--;
- elgg_log("Type-subtype '$type:$subtype' does not exist!", 'NOTICE');
+ // check that the subtype is valid
+ if (!$subtype && ELGG_ENTITIES_NO_VALUE === $subtype) {
+ // subtype value is 0
+ $subtype_ids[] = ELGG_ENTITIES_NO_VALUE;
+ } elseif (!$subtype) {
+ // subtype is ignored.
+ // this handles ELGG_ENTITIES_ANY_VALUE, '', and anything falsy that isn't 0
continue;
+ } else {
+ $subtype_id = get_subtype_id($type, $subtype);
+
+ if ($subtype_id) {
+ $subtype_ids[] = $subtype_id;
+ } else {
+ $valid_subtypes_count--;
+ elgg_log("Type-subtype '$type:$subtype' does not exist!", 'NOTICE');
+ continue;
+ }
}
}
@@ -1037,7 +1296,7 @@ function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pair
foreach ($pairs as $paired_type => $paired_subtypes) {
if (!in_array($paired_type, $valid_types)) {
$valid_pairs_count--;
- unset ($pairs[array_search($paired_type, $pairs)]);
+ unset($pairs[array_search($paired_type, $pairs)]);
} else {
if ($paired_subtypes && !is_array($paired_subtypes)) {
$pairs[$paired_type] = array($paired_subtypes);
@@ -1100,7 +1359,7 @@ function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pair
* best to provide in table.column format.
* @param NULL|array $guids Array of GUIDs.
*
- * @return false|str
+ * @return false|string
* @since 1.8.0
* @access private
*/
@@ -1118,8 +1377,12 @@ function elgg_get_guid_based_where_sql($column, $guids) {
$guids_sanitized = array();
foreach ($guids as $guid) {
- if (($guid != sanitise_int($guid))) {
- return FALSE;
+ if ($guid !== ELGG_ENTITIES_NO_VALUE) {
+ $guid = sanitise_int($guid);
+
+ if (!$guid) {
+ return false;
+ }
}
$guids_sanitized[] = $guid;
}
@@ -1145,7 +1408,7 @@ function elgg_get_guid_based_where_sql($column, $guids) {
* @param NULL|int $time_updated_upper Time updated upper limit
* @param NULL|int $time_updated_lower Time updated lower limit
*
- * @return FALSE|str FALSE on fail, string on success.
+ * @return FALSE|string FALSE on fail, string on success.
* @since 1.7.0
* @access private
*/
@@ -1190,10 +1453,10 @@ $time_created_lower = NULL, $time_updated_upper = NULL, $time_updated_lower = NU
* @internal This also provides the views for elgg_view_annotation().
*
* @param array $options Any options from $getter options plus:
- * full_view => BOOL Display full view entities
- * list_type_toggle => BOOL Display gallery / list switch
- * pagination => BOOL Display pagination links
- * gallery => BOOL display in gallery view
+ * full_view => BOOL Display full view entities
+ * list_type => STR 'list' or 'gallery'
+ * list_type_toggle => BOOL Display gallery / list switch
+ * pagination => BOOL Display pagination links
*
* @param mixed $getter The entity getter function to use to fetch the entities
* @param mixed $viewer The function to use to view the entity list.
@@ -1210,13 +1473,14 @@ function elgg_list_entities(array $options = array(), $getter = 'elgg_get_entiti
global $autofeed;
$autofeed = true;
+ $offset_key = isset($options['offset_key']) ? $options['offset_key'] : 'offset';
+
$defaults = array(
- 'offset' => (int) max(get_input('offset', 0), 0),
+ 'offset' => (int) max(get_input($offset_key, 0), 0),
'limit' => (int) max(get_input('limit', 10), 0),
'full_view' => TRUE,
'list_type_toggle' => FALSE,
'pagination' => TRUE,
- 'gallery' => FALSE,
);
$options = array_merge($defaults, $options);
@@ -1242,13 +1506,15 @@ function elgg_list_entities(array $options = array(), $getter = 'elgg_get_entiti
*
* @tip Use this to generate a list of archives by month for when entities were added or updated.
*
+ * @todo document how to pass in array for $subtype
+ *
* @warning Months are returned in the form YYYYMM.
*
* @param string $type The type of entity
* @param string $subtype The subtype of entity
- * @param int $container_guid The container GUID that the entinties belong to
+ * @param int $container_guid The container GUID that the entities belong to
* @param int $site_guid The site GUID
- * @param str $order_by Order_by SQL order by clause
+ * @param string $order_by Order_by SQL order by clause
*
* @return array|false Either an array months as YYYYMM, or false on failure
*/
@@ -1355,9 +1621,9 @@ $order_by = 'time_created') {
* @param bool $recursive Recursively disable all entities owned or contained by $guid?
*
* @return bool
- * @access private
* @see access_show_hidden_entities()
* @link http://docs.elgg.org/Entities
+ * @access private
*/
function disable_entity($guid, $reason = "", $recursive = true) {
global $CONFIG;
@@ -1373,34 +1639,34 @@ function disable_entity($guid, $reason = "", $recursive = true) {
}
if ($recursive) {
- // Temporary token overriding access controls
- // @todo Do this better.
- static $__RECURSIVE_DELETE_TOKEN;
- // Make it slightly harder to guess
- $__RECURSIVE_DELETE_TOKEN = md5(elgg_get_logged_in_user_guid());
-
- $sub_entities = get_data("SELECT * from {$CONFIG->dbprefix}entities
- WHERE container_guid=$guid
- or owner_guid=$guid
- or site_guid=$guid", 'entity_row_to_elggstar');
+ $hidden = access_get_show_hidden_status();
+ access_show_hidden_entities(true);
+ $ia = elgg_set_ignore_access(true);
+
+ $sub_entities = get_data("SELECT * FROM {$CONFIG->dbprefix}entities
+ WHERE (
+ container_guid = $guid
+ OR owner_guid = $guid
+ OR site_guid = $guid
+ ) AND enabled='yes'", 'entity_row_to_elggstar');
if ($sub_entities) {
foreach ($sub_entities as $e) {
+ add_entity_relationship($e->guid, 'disabled_with', $entity->guid);
$e->disable($reason);
}
}
-
- $__RECURSIVE_DELETE_TOKEN = null;
+ access_show_hidden_entities($hidden);
+ elgg_set_ignore_access($ia);
}
$entity->disableMetadata();
$entity->disableAnnotations();
- // relationships can't be disabled. hope they join to the entities table.
- //$entity->disableRelationships();
+ _elgg_invalidate_cache_for_entity($guid);
$res = update_data("UPDATE {$CONFIG->dbprefix}entities
- set enabled='no'
- where guid={$guid}");
+ SET enabled = 'no'
+ WHERE guid = $guid");
return $res;
}
@@ -1412,43 +1678,55 @@ function disable_entity($guid, $reason = "", $recursive = true) {
/**
* Enable an entity.
*
- * @warning In order to enable an entity using ElggEntity::enable(),
- * you must first use {@link access_show_hidden_entities()}.
+ * @warning In order to enable an entity, you must first use
+ * {@link access_show_hidden_entities()}.
*
- * @param int $guid GUID of entity to enable
+ * @param int $guid GUID of entity to enable
+ * @param bool $recursive Recursively enable all entities disabled with the entity?
*
* @return bool
*/
-function enable_entity($guid) {
+function enable_entity($guid, $recursive = true) {
global $CONFIG;
$guid = (int)$guid;
// Override access only visible entities
- $access_status = access_get_show_hidden_status();
+ $old_access_status = access_get_show_hidden_status();
access_show_hidden_entities(true);
+ $result = false;
if ($entity = get_entity($guid)) {
if (elgg_trigger_event('enable', $entity->type, $entity)) {
if ($entity->canEdit()) {
- access_show_hidden_entities($access_status);
-
$result = update_data("UPDATE {$CONFIG->dbprefix}entities
- set enabled='yes'
- where guid={$guid}");
+ SET enabled = 'yes'
+ WHERE guid = $guid");
$entity->deleteMetadata('disable_reason');
$entity->enableMetadata();
$entity->enableAnnotations();
- return $result;
+ if ($recursive) {
+ $disabled_with_it = elgg_get_entities_from_relationship(array(
+ 'relationship' => 'disabled_with',
+ 'relationship_guid' => $entity->guid,
+ 'inverse_relationship' => true,
+ 'limit' => 0,
+ ));
+
+ foreach ($disabled_with_it as $e) {
+ $e->enable();
+ remove_entity_relationship($e->guid, 'disabled_with', $entity->guid);
+ }
+ }
}
}
}
- access_show_hidden_entities($access_status);
- return false;
+ access_show_hidden_entities($old_access_status);
+ return $result;
}
/**
@@ -1469,8 +1747,8 @@ function enable_entity($guid) {
* @param bool $recursive If true (default) then all entities which are
* owned or contained by $guid will also be deleted.
*
- * @access private
* @return bool
+ * @access private
*/
function delete_entity($guid, $recursive = true) {
global $CONFIG, $ENTITY_CACHE;
@@ -1482,7 +1760,16 @@ function delete_entity($guid, $recursive = true) {
// delete cache
if (isset($ENTITY_CACHE[$guid])) {
- invalidate_cache_for_entity($guid);
+ _elgg_invalidate_cache_for_entity($guid);
+ }
+
+ // If memcache is available then delete this entry from the cache
+ static $newentity_cache;
+ if ((!$newentity_cache) && (is_memcache_available())) {
+ $newentity_cache = new ElggMemcache('new_entity_cache');
+ }
+ if ($newentity_cache) {
+ $newentity_cache->delete($guid);
}
// Delete contained owned and otherwise releated objects (depth first)
@@ -1495,20 +1782,35 @@ function delete_entity($guid, $recursive = true) {
$entity_disable_override = access_get_show_hidden_status();
access_show_hidden_entities(true);
- $sub_entities = get_data("SELECT * from {$CONFIG->dbprefix}entities
- WHERE container_guid=$guid
- or owner_guid=$guid
- or site_guid=$guid", 'entity_row_to_elggstar');
- if ($sub_entities) {
- foreach ($sub_entities as $e) {
- $e->delete(true);
- }
+ $ia = elgg_set_ignore_access(true);
+
+ // @todo there was logic in the original code that ignored
+ // entities with owner or container guids of themselves.
+ // this should probably be prevented in ElggEntity instead of checked for here
+ $options = array(
+ 'wheres' => array(
+ "((container_guid = $guid OR owner_guid = $guid OR site_guid = $guid)"
+ . " AND guid != $guid)"
+ ),
+ 'limit' => 0
+ );
+
+ $batch = new ElggBatch('elgg_get_entities', $options);
+ $batch->setIncrementOffset(false);
+
+ foreach ($batch as $e) {
+ $e->delete(true);
}
access_show_hidden_entities($entity_disable_override);
$__RECURSIVE_DELETE_TOKEN = null;
+ elgg_set_ignore_access($ia);
}
+ $entity_disable_override = access_get_show_hidden_status();
+ access_show_hidden_entities(true);
+ $ia = elgg_set_ignore_access(true);
+
// Now delete the entity itself
$entity->deleteMetadata();
$entity->deleteOwnedMetadata();
@@ -1516,8 +1818,11 @@ function delete_entity($guid, $recursive = true) {
$entity->deleteOwnedAnnotations();
$entity->deleteRelationships();
- remove_from_river_by_subject($guid);
- remove_from_river_by_object($guid);
+ access_show_hidden_entities($entity_disable_override);
+ elgg_set_ignore_access($ia);
+
+ elgg_delete_river(array('subject_guid' => $guid));
+ elgg_delete_river(array('object_guid' => $guid));
remove_all_private_settings($guid);
$res = delete_data("DELETE from {$CONFIG->dbprefix}entities where guid={$guid}");
@@ -1545,7 +1850,7 @@ function delete_entity($guid, $recursive = true) {
}
}
- return $res;
+ return (bool)$res;
}
}
}
@@ -1561,7 +1866,7 @@ function delete_entity($guid, $recursive = true) {
* @param string $returnvalue Return value from previous hook
* @param array $params The parameters, passed 'guid' and 'varname'
*
- * @return null
+ * @return ElggMetadata|null
* @elgg_plugin_hook_handler volatile metadata
* @todo investigate more.
* @access private
@@ -1605,6 +1910,9 @@ function volatile_data_export_plugin_hook($hook, $entity_type, $returnvalue, $pa
*
* @elgg_event_handler export all
* @return mixed
+ * @access private
+ *
+ * @throws InvalidParameterException|InvalidClassException
*/
function export_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) {
// Sanity check values
@@ -1646,6 +1954,9 @@ function export_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) {
*
* @return ElggEntity the unsaved entity which should be populated by items.
* @todo Remove this.
+ * @access private
+ *
+ * @throws ClassException|InstallationException|ImportException
*/
function oddentity_to_elggentity(ODDEntity $element) {
$class = $element->getAttribute('class');
@@ -1657,7 +1968,7 @@ function oddentity_to_elggentity(ODDEntity $element) {
if (!$tmp) {
// Construct new class with owner from session
$classname = get_subtype_class($class, $subclass);
- if ($classname != "") {
+ if ($classname) {
if (class_exists($classname)) {
$tmp = new $classname();
@@ -1716,12 +2027,14 @@ function oddentity_to_elggentity(ODDEntity $element) {
* @return mixed
* @elgg_plugin_hook_handler import all
* @todo document
+ * @access private
*
+ * @throws ImportException
*/
function import_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) {
$element = $params['element'];
- $tmp = NULL;
+ $tmp = null;
if ($element instanceof ODDEntity) {
$tmp = oddentity_to_elggentity($element);
@@ -1729,7 +2042,7 @@ function import_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) {
if ($tmp) {
// Make sure its saved
if (!$tmp->save()) {
- elgg_echo('ImportException:ProblemSaving', array($element->getAttribute('uuid')));
+ $msg = elgg_echo('ImportException:ProblemSaving', array($element->getAttribute('uuid')));
throw new ImportException($msg);
}
@@ -1763,8 +2076,6 @@ function import_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) {
* @link http://docs.elgg.org/Entities/AccessControl
*/
function can_edit_entity($entity_guid, $user_guid = 0) {
- global $CONFIG;
-
$user_guid = (int)$user_guid;
$user = get_entity($user_guid);
if (!$user) {
@@ -1817,14 +2128,19 @@ function can_edit_entity_metadata($entity_guid, $user_guid = 0, $metadata = null
$return = null;
- if ($metadata->owner_guid == 0) {
+ if ($metadata && ($metadata->owner_guid == 0)) {
$return = true;
}
if (is_null($return)) {
$return = can_edit_entity($entity_guid, $user_guid);
}
- $user = get_entity($user_guid);
+ if ($user_guid) {
+ $user = get_entity($user_guid);
+ } else {
+ $user = elgg_get_logged_in_user_entity();
+ }
+
$params = array('entity' => $entity, 'user' => $user, 'metadata' => $metadata);
$return = elgg_trigger_plugin_hook('permissions_check:metadata', $entity->type, $params, $return);
return $return;
@@ -1883,7 +2199,7 @@ function get_entity_url($entity_guid) {
* @param string $entity_subtype The entity subtype
* @param string $function_name The function to register
*
- * @return true|false Depending on success
+ * @return bool Depending on success
* @see get_entity_url()
* @see ElggEntity::getURL()
* @since 1.8.0
@@ -1891,7 +2207,7 @@ function get_entity_url($entity_guid) {
function elgg_register_entity_url_handler($entity_type, $entity_subtype, $function_name) {
global $CONFIG;
- if (!is_callable($function_name)) {
+ if (!is_callable($function_name, true)) {
return false;
}
@@ -1919,7 +2235,7 @@ function elgg_register_entity_url_handler($entity_type, $entity_subtype, $functi
* @param string $type The type of entity (object, site, user, group)
* @param string $subtype The subtype to register (may be blank)
*
- * @return true|false Depending on success
+ * @return bool Depending on success
* @see get_registered_entity_types()
* @link http://docs.elgg.org/Search
* @link http://docs.elgg.org/Tutorials/Search
@@ -1928,7 +2244,7 @@ function elgg_register_entity_type($type, $subtype = null) {
global $CONFIG;
$type = strtolower($type);
- if (!in_array($type, array('object', 'site', 'group', 'user'))) {
+ if (!in_array($type, $CONFIG->entity_types)) {
return FALSE;
}
@@ -1956,14 +2272,14 @@ function elgg_register_entity_type($type, $subtype = null) {
* @param string $type The type of entity (object, site, user, group)
* @param string $subtype The subtype to register (may be blank)
*
- * @return true|false Depending on success
+ * @return bool Depending on success
* @see elgg_register_entity_type()
*/
function unregister_entity_type($type, $subtype) {
global $CONFIG;
$type = strtolower($type);
- if (!in_array($type, array('object', 'site', 'group', 'user'))) {
+ if (!in_array($type, $CONFIG->entity_types)) {
return FALSE;
}
@@ -2023,7 +2339,7 @@ function get_registered_entity_types($type = null) {
* @param string $type The type of entity (object, site, user, group)
* @param string $subtype The subtype (may be blank)
*
- * @return true|false Depending on whether or not the type has been registered
+ * @return bool Depending on whether or not the type has been registered
*/
function is_registered_entity_type($type, $subtype = null) {
global $CONFIG;
@@ -2051,15 +2367,18 @@ function is_registered_entity_type($type, $subtype = null) {
*
* @param array $page Page elements from pain page handler
*
- * @return void
+ * @return bool
* @elgg_page_handler view
+ * @access private
*/
function entities_page_handler($page) {
if (isset($page[0])) {
global $CONFIG;
set_input('guid', $page[0]);
include($CONFIG->path . "pages/entities/index.php");
+ return true;
}
+ return false;
}
/**
@@ -2120,34 +2439,16 @@ function elgg_list_registered_entities(array $options = array()) {
}
}
- $count = elgg_get_entities(array_merge(array('count' => TRUE), $options));
- $entities = elgg_get_entities($options);
-
- return elgg_view_entity_list($entities, $count, $options['offset'],
- $options['limit'], $options['full_view'], $options['list_type_toggle'], $options['pagination']);
-}
-
-/**
- * Check the recursive delete permissions token.
- *
- * If an entity is deleted recursively, a permissions override is required to allow
- * contained or owned entities to be removed.
- *
- * @access private
- * @return bool
- * @elgg_plugin_hook_handler permissions_check all
- * @elgg_plugin_hook_handler permissions_check:metadata all
- */
-function recursive_delete_permissions_check() {
- static $__RECURSIVE_DELETE_TOKEN;
-
- if ((elgg_is_logged_in()) && ($__RECURSIVE_DELETE_TOKEN)
- && (strcmp($__RECURSIVE_DELETE_TOKEN, md5(elgg_get_logged_in_user_guid())))) {
- return true;
+ if (!empty($options['type_subtype_pairs'])) {
+ $count = elgg_get_entities(array_merge(array('count' => TRUE), $options));
+ $entities = elgg_get_entities($options);
+ } else {
+ $count = 0;
+ $entities = array();
}
- // consult next function
- return NULL;
+ $options['count'] = $count;
+ return elgg_view_entity_list($entities, $options);
}
/**
@@ -2168,6 +2469,7 @@ function elgg_instanceof($entity, $type = NULL, $subtype = NULL, $class = NULL)
$return = ($entity instanceof ElggEntity);
if ($type) {
+ /* @var ElggEntity $entity */
$return = $return && ($entity->getType() == $type);
}
@@ -2185,8 +2487,6 @@ function elgg_instanceof($entity, $type = NULL, $subtype = NULL, $class = NULL)
/**
* Update the last_action column in the entities table for $guid.
*
- * This determines the sort order of 1.8's default river.
- *
* @warning This is different to time_updated. Time_updated is automatically set,
* while last_action is only set when explicitly called.
*
@@ -2194,7 +2494,8 @@ function elgg_instanceof($entity, $type = NULL, $subtype = NULL, $class = NULL)
* @param int $posted Timestamp of last action
*
* @return bool
- **/
+ * @access private
+ */
function update_entity_last_action($guid, $posted = NULL) {
global $CONFIG;
$guid = (int)$guid;
@@ -2223,27 +2524,36 @@ function update_entity_last_action($guid, $posted = NULL) {
*
* @return void
* @elgg_plugin_hook_handler gc system
+ * @access private
*/
function entities_gc() {
global $CONFIG;
- $tables = array ('sites_entity', 'objects_entity', 'groups_entity', 'users_entity');
+ $tables = array(
+ 'site' => 'sites_entity',
+ 'object' => 'objects_entity',
+ 'group' => 'groups_entity',
+ 'user' => 'users_entity'
+ );
- foreach ($tables as $table) {
- delete_data("DELETE from {$CONFIG->dbprefix}{$table}
- where guid NOT IN (SELECT guid from {$CONFIG->dbprefix}entities)");
+ foreach ($tables as $type => $table) {
+ delete_data("DELETE FROM {$CONFIG->dbprefix}{$table}
+ WHERE guid NOT IN (SELECT guid FROM {$CONFIG->dbprefix}entities)");
+ delete_data("DELETE FROM {$CONFIG->dbprefix}entities
+ WHERE type = '$type' AND guid NOT IN (SELECT guid FROM {$CONFIG->dbprefix}{$table})");
}
}
/**
* Runs unit tests for the entity objects.
*
- * @param sting $hook unit_test
+ * @param string $hook unit_test
* @param string $type system
* @param mixed $value Array of tests
* @param mixed $params Params
*
* @return array
+ * @access private
*/
function entities_test($hook, $type, $value, $params) {
global $CONFIG;
@@ -2256,17 +2566,13 @@ function entities_test($hook, $type, $value, $params) {
*
* @return void
* @elgg_event_handler init system
+ * @access private
*/
function entities_init() {
elgg_register_page_handler('view', 'entities_page_handler');
elgg_register_plugin_hook_handler('unit_test', 'system', 'entities_test');
- // Allow a permission override for recursive entity deletion
- // @todo Can this be done better?
- elgg_register_plugin_hook_handler('permissions_check', 'all', 'recursive_delete_permissions_check');
- elgg_register_plugin_hook_handler('permissions_check:metadata', 'all', 'recursive_delete_permissions_check');
-
elgg_register_plugin_hook_handler('gc', 'system', 'entities_gc');
}
@@ -2281,3 +2587,4 @@ elgg_register_plugin_hook_handler('volatile', 'metadata', 'volatile_data_export_
/** Register init system event **/
elgg_register_event_handler('init', 'system', 'entities_init');
+
diff --git a/engine/lib/export.php b/engine/lib/export.php
index f81bee2fe..ecc894e63 100644
--- a/engine/lib/export.php
+++ b/engine/lib/export.php
@@ -11,7 +11,7 @@
*
* @param mixed $object The object either an ElggEntity, ElggRelationship or ElggExtender
*
- * @return the UUID or false
+ * @return string|false the UUID or false
*/
function get_uuid_from_object($object) {
if ($object instanceof ElggEntity) {
@@ -40,8 +40,6 @@ function get_uuid_from_object($object) {
* @return string
*/
function guid_to_uuid($guid) {
- global $CONFIG;
-
return elgg_get_site_url() . "export/opendd/$guid/";
}
@@ -53,8 +51,6 @@ function guid_to_uuid($guid) {
* @return bool
*/
function is_uuid_this_domain($uuid) {
- global $CONFIG;
-
if (strpos($uuid, elgg_get_site_url()) === 0) {
return true;
}
@@ -67,7 +63,7 @@ function is_uuid_this_domain($uuid) {
*
* @param string $uuid A unique ID
*
- * @return mixed
+ * @return ElggEntity|false
*/
function get_entity_from_uuid($uuid) {
$uuid = sanitise_string($uuid);
@@ -111,23 +107,25 @@ $IMPORTED_OBJECT_COUNTER = 0;
* @param ODD $odd The odd element to process
*
* @return bool
+ * @access private
*/
function _process_element(ODD $odd) {
global $IMPORTED_DATA, $IMPORTED_OBJECT_COUNTER;
// See if anyone handles this element, return true if it is.
+ $to_be_serialised = null;
if ($odd) {
$handled = elgg_trigger_plugin_hook("import", "all", array("element" => $odd), $to_be_serialised);
- }
- // If not, then see if any of its sub elements are handled
- if ($handled) {
- // Increment validation counter
- $IMPORTED_OBJECT_COUNTER ++;
- // Return the constructed object
- $IMPORTED_DATA[] = $handled;
+ // If not, then see if any of its sub elements are handled
+ if ($handled) {
+ // Increment validation counter
+ $IMPORTED_OBJECT_COUNTER ++;
+ // Return the constructed object
+ $IMPORTED_DATA[] = $handled;
- return true;
+ return true;
+ }
}
return false;
@@ -140,6 +138,7 @@ function _process_element(ODD $odd) {
*
* @return array
* @throws ExportException
+ * @access private
*/
function exportAsArray($guid) {
$guid = (int)$guid;
@@ -165,8 +164,9 @@ function exportAsArray($guid) {
*
* @param int $guid The GUID.
*
- * @return xml
+ * @return string XML
* @see ElggEntity for an example of its usage.
+ * @access private
*/
function export($guid) {
$odd = new ODDDocument(exportAsArray($guid));
@@ -181,7 +181,8 @@ function export($guid) {
* @param string $xml XML string
*
* @return bool
- * @throws Exception if there was a problem importing the data.
+ * @throws ImportException if there was a problem importing the data.
+ * @access private
*/
function import($xml) {
global $IMPORTED_DATA, $IMPORTED_OBJECT_COUNTER;
@@ -210,6 +211,7 @@ function import($xml) {
* Register the OpenDD import action
*
* @return void
+ * @access private
*/
function export_init() {
global $CONFIG;
diff --git a/engine/lib/extender.php b/engine/lib/extender.php
index a017c9eec..8323bd3ce 100644
--- a/engine/lib/extender.php
+++ b/engine/lib/extender.php
@@ -44,6 +44,7 @@ function detect_extender_valuetype($value, $value_type = "") {
* @param ODDMetaData $element The OpenDD element
*
* @return bool
+ * @access private
*/
function oddmetadata_to_elggextender(ElggEntity $entity, ODDMetaData $element) {
// Get the type of extender (metadata, type, attribute etc)
@@ -85,6 +86,7 @@ function oddmetadata_to_elggextender(ElggEntity $entity, ODDMetaData $element) {
* @return null
* @elgg_plugin_hook_handler volatile metadata
* @todo investigate more.
+ * @throws ImportException
* @access private
*/
function import_extender_plugin_hook($hook, $entity_type, $returnvalue, $params) {
@@ -93,6 +95,7 @@ function import_extender_plugin_hook($hook, $entity_type, $returnvalue, $params)
$tmp = NULL;
if ($element instanceof ODDMetaData) {
+ /* @var ODDMetaData $element */
// Recall entity
$entity_uuid = $element->getAttribute('entity_uuid');
$entity = get_entity_from_uuid($entity_uuid);
@@ -104,6 +107,7 @@ function import_extender_plugin_hook($hook, $entity_type, $returnvalue, $params)
// Save
if (!$entity->save()) {
+ $attr_name = $element->getAttribute('name');
$msg = elgg_echo('ImportException:ProblemUpdatingMeta', array($attr_name, $entity_uuid));
throw new ImportException($msg);
}
@@ -119,61 +123,68 @@ function import_extender_plugin_hook($hook, $entity_type, $returnvalue, $params)
* @param string $type 'metadata' or 'annotation'
* @param int $user_guid The GUID of the user
*
- * @return true|false
+ * @return bool
*/
function can_edit_extender($extender_id, $type, $user_guid = 0) {
- if (!elgg_is_logged_in()) {
- return false;
+ // @todo Since Elgg 1.0, Elgg has returned false from can_edit_extender()
+ // if no user was logged in. This breaks the access override. This is a
+ // temporary work around. This function needs to be rewritten in Elgg 1.9
+ if (!elgg_check_access_overrides($user_guid)) {
+ if (!elgg_is_logged_in()) {
+ return false;
+ }
}
$user_guid = (int)$user_guid;
- $user = get_entity($user_guid);
+ $user = get_user($user_guid);
if (!$user) {
$user = elgg_get_logged_in_user_entity();
+ $user_guid = elgg_get_logged_in_user_guid();
}
- $functionname = "get_{$type}";
+ $functionname = "elgg_get_{$type}_from_id";
if (is_callable($functionname)) {
- $extender = $functionname($extender_id);
+ $extender = call_user_func($functionname, $extender_id);
} else {
return false;
}
- if (!is_a($extender, "ElggExtender")) {
+ if (!($extender instanceof ElggExtender)) {
return false;
}
+ /* @var ElggExtender $extender */
// If the owner is the specified user, great! They can edit.
- if ($extender->getOwnerGUID() == $user->getGUID()) {
+ if ($extender->getOwnerGUID() == $user_guid) {
return true;
}
// If the user can edit the entity this is attached to, great! They can edit.
- if (can_edit_entity($extender->entity_guid, $user->getGUID())) {
+ if (can_edit_entity($extender->entity_guid, $user_guid)) {
return true;
}
- // Trigger plugin hooks
- $params = array('entity' => $entity, 'user' => $user);
+ // Trigger plugin hook - note that $user may be null
+ $params = array('entity' => $extender->getEntity(), 'user' => $user);
return elgg_trigger_plugin_hook('permissions_check', $type, $params, false);
}
/**
* Sets the URL handler for a particular extender type and name.
* It is recommended that you do not call this directly, instead use
- * one of the wrapper functions in the subtype files.
+ * one of the wrapper functions such as elgg_register_annotation_url_handler().
*
- * @param string $function_name The function to register
- * @param string $extender_type Extender type
+ * @param string $extender_type Extender type ('annotation', 'metadata')
* @param string $extender_name The name of the extender
+ * @param string $function_name The function to register
*
- * @return true|false Depending on success
+ * @return bool
*/
function elgg_register_extender_url_handler($extender_type, $extender_name, $function_name) {
global $CONFIG;
- if (!is_callable($function_name)) {
+ if (!is_callable($function_name, true)) {
return false;
}
@@ -226,7 +237,7 @@ function get_extender_url(ElggExtender $extender) {
if ($url == "") {
$nameid = $extender->id;
if ($type == 'volatile') {
- $nameid == $extender->name;
+ $nameid = $extender->name;
}
$url = "export/$view/$guid/$type/$nameid/";
}
diff --git a/engine/lib/filestore.php b/engine/lib/filestore.php
index 1e257c8b0..a3c7ba439 100644
--- a/engine/lib/filestore.php
+++ b/engine/lib/filestore.php
@@ -18,7 +18,7 @@
*/
function get_dir_size($dir, $totalsize = 0) {
$handle = @opendir($dir);
- while ($file = @readdir ($handle)) {
+ while ($file = @readdir($handle)) {
if (eregi("^\.{1,2}$", $file)) {
continue;
}
@@ -149,6 +149,12 @@ $x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0, $upscale = FALSE) {
return FALSE;
}
+ // color transparencies white (default is black)
+ imagefilledrectangle(
+ $new_image, 0, 0, $params['newwidth'], $params['newheight'],
+ imagecolorallocate($new_image, 255, 255, 255)
+ );
+
$rtn_code = imagecopyresampled( $new_image,
$original_image,
0,
@@ -302,8 +308,6 @@ function get_image_resize_parameters($width, $height, $options) {
function file_delete($guid) {
if ($file = get_entity($guid)) {
if ($file->canEdit()) {
- $container = get_entity($file->container_guid);
-
$thumbnail = $file->thumbnail;
$smallthumb = $file->smallthumb;
$largethumb = $file->largethumb;
@@ -377,7 +381,7 @@ function file_get_general_file_type($mimetype) {
/**
* Delete a directory and all its contents
*
- * @param str $directory Directory to delete
+ * @param string $directory Directory to delete
*
* @return bool
*/
@@ -465,6 +469,7 @@ function set_default_filestore(ElggFilestore $filestore) {
* ElggFile.
*
* @return void
+ * @access private
*/
function filestore_run_once() {
// Register a class
@@ -473,16 +478,19 @@ function filestore_run_once() {
/**
* Initialise the file modules.
- * Listens to system boot and registers any appropriate file types and classes
+ * Listens to system init and configures the default filestore
*
* @return void
+ * @access private
*/
function filestore_init() {
global $CONFIG;
// Now register a default filestore
- set_default_filestore(new ElggDiskFilestore($CONFIG->dataroot));
-
+ if (isset($CONFIG->dataroot)) {
+ set_default_filestore(new ElggDiskFilestore($CONFIG->dataroot));
+ }
+
// Now run this stuff, but only once
run_function_once("filestore_run_once");
}
@@ -490,12 +498,13 @@ function filestore_init() {
/**
* Unit tests for files
*
- * @param sting $hook unit_test
+ * @param string $hook unit_test
* @param string $type system
* @param mixed $value Array of tests
* @param mixed $params Params
*
* @return array
+ * @access private
*/
function filestore_test($hook, $type, $value, $params) {
global $CONFIG;
diff --git a/engine/lib/group.php b/engine/lib/group.php
index d78274961..6ded8a825 100644
--- a/engine/lib/group.php
+++ b/engine/lib/group.php
@@ -14,6 +14,7 @@
* @param int $guid GUID for a group
*
* @return array|false
+ * @access private
*/
function get_group_entity_as_row($guid) {
global $CONFIG;
@@ -32,6 +33,7 @@ function get_group_entity_as_row($guid) {
* @param string $description Description
*
* @return bool
+ * @access private
*/
function create_group_entity($guid, $name, $description) {
global $CONFIG;
@@ -168,7 +170,7 @@ function get_group_members($group_guid, $limit = 10, $offset = 0, $site_guid = 0
'relationship' => 'member',
'relationship_guid' => $group_guid,
'inverse_relationship' => TRUE,
- 'types' => 'user',
+ 'type' => 'user',
'limit' => $limit,
'offset' => $offset,
'count' => $count,
@@ -238,49 +240,52 @@ function leave_group($group_guid, $user_guid) {
*/
function get_users_membership($user_guid) {
$options = array(
+ 'type' => 'group',
'relationship' => 'member',
'relationship_guid' => $user_guid,
- 'inverse_relationship' => FALSE
+ 'inverse_relationship' => false,
+ 'limit' => false,
);
return elgg_get_entities_from_relationship($options);
}
/**
- * Checks access to a group.
+ * May the current user access item(s) on this page? If the page owner is a group,
+ * membership, visibility, and logged in status are taken into account.
*
* @param boolean $forward If set to true (default), will forward the page;
* if set to false, will return true or false.
*
- * @return true|false If $forward is set to false.
+ * @return bool If $forward is set to false.
*/
function group_gatekeeper($forward = true) {
- $allowed = true;
- $url = '';
-
- if ($group = elgg_get_page_owner_entity()) {
- if ($group instanceof ElggGroup) {
- $url = $group->getURL();
- if (
- ((!elgg_is_logged_in()) && (!$group->isPublicMembership())) ||
- ((!$group->isMember(elgg_get_logged_in_user_entity()) && (!$group->isPublicMembership())))
- ) {
- $allowed = false;
- }
- // Admin override
- if (elgg_is_admin_logged_in()) {
- $allowed = true;
- }
- }
+ $page_owner_guid = elgg_get_page_owner_guid();
+ if (!$page_owner_guid) {
+ return true;
+ }
+ $visibility = ElggGroupItemVisibility::factory($page_owner_guid);
+
+ if (!$visibility->shouldHideItems) {
+ return true;
}
+ if ($forward) {
+ // only forward to group if user can see it
+ $group = get_entity($page_owner_guid);
+ $forward_url = $group ? $group->getURL() : '';
+
+ if (!elgg_is_logged_in()) {
+ $_SESSION['last_forward_from'] = current_page_url();
+ $forward_reason = 'login';
+ } else {
+ $forward_reason = 'member';
+ }
- if ($forward && $allowed == false) {
- register_error(elgg_echo('membershiprequired'));
- forward($url, 'member');
- exit;
+ register_error(elgg_echo($visibility->reasonHidden));
+ forward($forward_url, $forward_reason);
}
- return $allowed;
+ return false;
}
/**
@@ -293,6 +298,7 @@ function group_gatekeeper($forward = true) {
* @param bool $default_on True if this option should be active by default
*
* @return void
+ * @since 1.5.0
*/
function add_group_tool_option($name, $label, $default_on = true) {
global $CONFIG;
@@ -318,6 +324,7 @@ function add_group_tool_option($name, $label, $default_on = true) {
* @param string $name Name of the group tool option
*
* @return void
+ * @since 1.7.5
*/
function remove_group_tool_option($name) {
global $CONFIG;
diff --git a/engine/lib/input.php b/engine/lib/input.php
index 25416b868..80b0b8766 100644
--- a/engine/lib/input.php
+++ b/engine/lib/input.php
@@ -8,46 +8,51 @@
*/
/**
- * Get some input from variables passed on the GET or POST line.
+ * Get some input from variables passed submitted through GET or POST.
+ *
+ * If using any data obtained from get_input() in a web page, please be aware that
+ * it is a possible vector for a reflected XSS attack. If you are expecting an
+ * integer, cast it to an int. If it is a string, escape quotes.
*
* Note: this function does not handle nested arrays (ex: form input of param[m][n])
* because of the filtering done in htmlawed from the filter_tags call.
+ * @todo Is this ^ still true?
*
- * @param string $variable The variable we want to return.
+ * @param string $variable The variable name we want.
* @param mixed $default A default value for the variable if it is not found.
- * @param bool $filter_result If true then the result is filtered for bad tags.
+ * @param bool $filter_result If true, then the result is filtered for bad tags.
*
- * @return string
+ * @return mixed
*/
function get_input($variable, $default = NULL, $filter_result = TRUE) {
global $CONFIG;
+ $result = $default;
+
+ elgg_push_context('input');
+
if (isset($CONFIG->input[$variable])) {
- $var = $CONFIG->input[$variable];
+ $result = $CONFIG->input[$variable];
if ($filter_result) {
- $var = filter_tags($var);
+ $result = filter_tags($result);
}
-
- return $var;
- }
-
- if (isset($_REQUEST[$variable])) {
+ } elseif (isset($_REQUEST[$variable])) {
if (is_array($_REQUEST[$variable])) {
- $var = $_REQUEST[$variable];
+ $result = $_REQUEST[$variable];
} else {
- $var = trim($_REQUEST[$variable]);
+ $result = trim($_REQUEST[$variable]);
}
if ($filter_result) {
- $var = filter_tags($var);
+ $result = filter_tags($result);
}
-
- return $var;
}
- return $default;
+ elgg_pop_context();
+
+ return $result;
}
/**
@@ -55,8 +60,8 @@ function get_input($variable, $default = NULL, $filter_result = TRUE) {
*
* Note: this function does not handle nested arrays (ex: form input of param[m][n])
*
- * @param string $variable The name of the variable
- * @param string $value The value of the variable
+ * @param string $variable The name of the variable
+ * @param string|string[] $value The value of the variable
*
* @return void
*/
@@ -183,8 +188,8 @@ function elgg_get_sticky_value($form_name, $variable = '', $default = NULL, $fil
/**
* Get all the values in a sticky form in an array
*
- * @param string $form_name The name of the form
- * @param bool $filter_result Filter for bad input if true
+ * @param string $form_name The name of the form
+ * @param bool $filter_result Filter for bad input if true
*
* @return array
* @since 1.8.0
@@ -221,23 +226,28 @@ function elgg_clear_sticky_value($form_name, $variable) {
/**
* Page handler for autocomplete endpoint.
*
+ * @todo split this into functions/objects, this is way too big
+ *
* /livesearch?q=<query>
*
* Other options include:
- * match_on string all|array(groups|users|friends|subtype)
+ * match_on string all or array(groups|users|friends)
* match_owner int 0/1
* limit int default is 10
*
+ * @param array $page
* @return string JSON string is returned and then exit
+ * @access private
*/
function input_livesearch_page_handler($page) {
global $CONFIG;
+
// only return results to logged in users.
if (!$user = elgg_get_logged_in_user_entity()) {
exit;
}
- if (!$q = get_input('q')) {
+ if (!$q = get_input('term', get_input('q'))) {
exit;
}
@@ -247,57 +257,72 @@ function input_livesearch_page_handler($page) {
$q = str_replace(array('_', '%'), array('\_', '\%'), $q);
$match_on = get_input('match_on', 'all');
- if ($match_on == 'all' || $match_on[0] == 'all') {
- $match_on = array('users', 'groups');
- }
if (!is_array($match_on)) {
$match_on = array($match_on);
}
+ // all = users and groups
+ if (in_array('all', $match_on)) {
+ $match_on = array('users', 'groups');
+ }
+
if (get_input('match_owner', false)) {
- $owner_guid = $user->getGUID();
$owner_where = 'AND e.owner_guid = ' . $user->getGUID();
} else {
- $owner_guid = null;
$owner_where = '';
}
- $limit = get_input('limit', 10);
+ $limit = sanitise_int(get_input('limit', 10));
// grab a list of entities and send them in json.
$results = array();
- foreach ($match_on as $type) {
- switch ($type) {
- case 'all':
- // only need to pull up title from objects.
-
- $options = array('owner_guid' => $owner_guid, 'limit' => $limit);
- if (!$entities = elgg_get_entities($options) AND is_array($entities)) {
- $results = array_merge($results, $entities);
- }
- break;
-
+ foreach ($match_on as $match_type) {
+ switch ($match_type) {
case 'users':
$query = "SELECT * FROM {$CONFIG->dbprefix}users_entity as ue, {$CONFIG->dbprefix}entities as e
WHERE e.guid = ue.guid
AND e.enabled = 'yes'
AND ue.banned = 'no'
- AND (ue.name LIKE '$q%' OR ue.username LIKE '$q%')
+ AND (ue.name LIKE '$q%' OR ue.name LIKE '% $q%' OR ue.username LIKE '$q%')
LIMIT $limit
";
if ($entities = get_data($query)) {
foreach ($entities as $entity) {
- $json = json_encode(array(
+ // @todo use elgg_get_entities (don't query in a loop!)
+ $entity = get_entity($entity->guid);
+ /* @var ElggUser $entity */
+ if (!$entity) {
+ continue;
+ }
+
+ if (in_array('groups', $match_on)) {
+ $value = $entity->guid;
+ } else {
+ $value = $entity->username;
+ }
+
+ $output = elgg_view_list_item($entity, array(
+ 'use_hover' => false,
+ 'class' => 'elgg-autocomplete-item',
+ ));
+
+ $icon = elgg_view_entity_icon($entity, 'tiny', array(
+ 'use_hover' => false,
+ ));
+
+ $result = array(
'type' => 'user',
'name' => $entity->name,
'desc' => $entity->username,
- 'icon' => '<img class="livesearch_icon" src="' .
- get_entity($entity->guid)->getIconURL('tiny') . '" />',
- 'guid' => $entity->guid
- ));
- $results[$entity->name . rand(1, 100)] = $json;
+ 'guid' => $entity->guid,
+ 'label' => $output,
+ 'value' => $value,
+ 'icon' => $icon,
+ 'url' => $entity->getURL(),
+ );
+ $results[$entity->name . rand(1, 100)] = $result;
}
}
break;
@@ -311,27 +336,44 @@ function input_livesearch_page_handler($page) {
WHERE e.guid = ge.guid
AND e.enabled = 'yes'
$owner_where
- AND (ge.name LIKE '$q%' OR ge.description LIKE '%$q%')
+ AND (ge.name LIKE '$q%' OR ge.name LIKE '% $q%' OR ge.description LIKE '% $q%')
LIMIT $limit
";
if ($entities = get_data($query)) {
foreach ($entities as $entity) {
- $json = json_encode(array(
+ // @todo use elgg_get_entities (don't query in a loop!)
+ $entity = get_entity($entity->guid);
+ /* @var ElggGroup $entity */
+ if (!$entity) {
+ continue;
+ }
+
+ $output = elgg_view_list_item($entity, array(
+ 'use_hover' => false,
+ 'class' => 'elgg-autocomplete-item',
+ ));
+
+ $icon = elgg_view_entity_icon($entity, 'tiny', array(
+ 'use_hover' => false,
+ ));
+
+ $result = array(
'type' => 'group',
'name' => $entity->name,
'desc' => strip_tags($entity->description),
- 'icon' => '<img class="livesearch_icon" src="'
- . get_entity($entity->guid)->getIcon('tiny') . '" />',
- 'guid' => $entity->guid
- ));
-
- $results[$entity->name . rand(1, 100)] = $json;
+ 'guid' => $entity->guid,
+ 'label' => $output,
+ 'value' => $entity->guid,
+ 'icon' => $icon,
+ 'url' => $entity->getURL(),
+ );
+
+ $results[$entity->name . rand(1, 100)] = $result;
}
}
break;
case 'friends':
- $access = get_access_sql_suffix();
$query = "SELECT * FROM
{$CONFIG->dbprefix}users_entity as ue,
{$CONFIG->dbprefix}entity_relationships as er,
@@ -342,36 +384,54 @@ function input_livesearch_page_handler($page) {
AND e.guid = ue.guid
AND e.enabled = 'yes'
AND ue.banned = 'no'
- AND (ue.name LIKE '$q%' OR ue.username LIKE '$q%')
+ AND (ue.name LIKE '$q%' OR ue.name LIKE '% $q%' OR ue.username LIKE '$q%')
LIMIT $limit
";
if ($entities = get_data($query)) {
foreach ($entities as $entity) {
- $json = json_encode(array(
+ // @todo use elgg_get_entities (don't query in a loop!)
+ $entity = get_entity($entity->guid);
+ /* @var ElggUser $entity */
+ if (!$entity) {
+ continue;
+ }
+
+ $output = elgg_view_list_item($entity, array(
+ 'use_hover' => false,
+ 'class' => 'elgg-autocomplete-item',
+ ));
+
+ $icon = elgg_view_entity_icon($entity, 'tiny', array(
+ 'use_hover' => false,
+ ));
+
+ $result = array(
'type' => 'user',
'name' => $entity->name,
'desc' => $entity->username,
- 'icon' => '<img class="livesearch_icon" src="'
- . get_entity($entity->guid)->getIcon('tiny') . '" />',
- 'guid' => $entity->guid
- ));
- $results[$entity->name . rand(1, 100)] = $json;
+ 'guid' => $entity->guid,
+ 'label' => $output,
+ 'value' => $entity->username,
+ 'icon' => $icon,
+ 'url' => $entity->getURL(),
+ );
+ $results[$entity->name . rand(1, 100)] = $result;
}
}
break;
default:
- // arbitrary subtype.
- //@todo you cannot specify a subtype without a type.
- // did this ever work?
- elgg_get_entities(array('subtype' => $type, 'owner_guid' => $owner_guid));
+ header("HTTP/1.0 400 Bad Request", true);
+ echo "livesearch: unknown match_on of $match_type";
+ exit;
break;
}
}
ksort($results);
- echo implode($results, "\n");
+ header("Content-Type: application/json");
+ echo json_encode(array_values($results));
exit;
}
@@ -379,6 +439,7 @@ function input_livesearch_page_handler($page) {
* Register input functions and sanitize input
*
* @return void
+ * @access private
*/
function input_init() {
// register an endpoint for live search / autocomplete.
diff --git a/engine/lib/languages.php b/engine/lib/languages.php
index 7607ea3bf..61ba91ddb 100644
--- a/engine/lib/languages.php
+++ b/engine/lib/languages.php
@@ -8,6 +8,65 @@
*/
/**
+ * Given a message key, returns an appropriately translated full-text string
+ *
+ * @param string $message_key The short message code
+ * @param array $args An array of arguments to pass through vsprintf().
+ * @param string $language Optionally, the standard language code
+ * (defaults to site/user default, then English)
+ *
+ * @return string Either the translated string, the English string,
+ * or the original language string.
+ */
+function elgg_echo($message_key, $args = array(), $language = "") {
+ global $CONFIG;
+
+ static $CURRENT_LANGUAGE;
+
+ // old param order is deprecated
+ if (!is_array($args)) {
+ elgg_deprecated_notice(
+ 'As of Elgg 1.8, the 2nd arg to elgg_echo() is an array of string replacements and the 3rd arg is the language.',
+ 1.8
+ );
+
+ $language = $args;
+ $args = array();
+ }
+
+ if (!isset($CONFIG->translations)) {
+ // this means we probably had an exception before translations were initialized
+ register_translations(dirname(dirname(dirname(__FILE__))) . "/languages/");
+ }
+
+ if (!$CURRENT_LANGUAGE) {
+ $CURRENT_LANGUAGE = get_language();
+ }
+ if (!$language) {
+ $language = $CURRENT_LANGUAGE;
+ }
+
+ if (isset($CONFIG->translations[$language][$message_key])) {
+ $string = $CONFIG->translations[$language][$message_key];
+ } else if (isset($CONFIG->translations["en"][$message_key])) {
+ $string = $CONFIG->translations["en"][$message_key];
+ $lang = $CONFIG->translations["en"][$language];
+ elgg_log(sprintf('Missing %s translation for "%s" language key', $lang, $message_key), 'NOTICE');
+ } else {
+ $string = $message_key;
+ elgg_log(sprintf('Missing English translation for "%s" language key', $message_key), 'NOTICE');
+ }
+
+ // only pass through if we have arguments to allow backward compatibility
+ // with manual sprintf() calls.
+ if ($args) {
+ $string = vsprintf($string, $args);
+ }
+
+ return $string;
+}
+
+/**
* Add a translation.
*
* Translations are arrays in the Zend Translation array format, eg:
@@ -18,7 +77,7 @@
* @param string $country_code Standard country code (eg 'en', 'nl', 'es')
* @param array $language_array Formatted array of strings
*
- * @return true|false Depending on success
+ * @return bool Depending on success
*/
function add_translation($country_code, $language_array) {
global $CONFIG;
@@ -45,8 +104,6 @@ function add_translation($country_code, $language_array) {
* @return string The language code for the site/user or "en" if not set
*/
function get_current_language() {
- global $CONFIG;
-
$language = get_language();
if (!$language) {
@@ -83,55 +140,36 @@ function get_language() {
}
/**
- * Given a message shortcode, returns an appropriately translated full-text string
- *
- * @param string $message_key The short message code
- * @param array $args An array of arguments to pass through vsprintf().
- * @param string $language Optionally, the standard language code
- * (defaults to site/user default, then English)
- *
- * @return string Either the translated string, the English string,
- * or the original language string.
+ * @access private
*/
-function elgg_echo($message_key, $args = array(), $language = "") {
+function _elgg_load_translations() {
global $CONFIG;
- static $CURRENT_LANGUAGE;
-
- // old param order is deprecated
- if (!is_array($args)) {
- elgg_deprecated_notice(
- 'As of Elgg 1.8, the 2nd arg to elgg_echo() is an array of string replacements and the 3rd arg is the language.',
- 1.8
- );
-
- $language = $args;
- $args = array();
- }
+ if ($CONFIG->system_cache_enabled) {
+ $loaded = true;
+ $languages = array_unique(array('en', get_current_language()));
+ foreach ($languages as $language) {
+ $data = elgg_load_system_cache("$language.lang");
+ if ($data) {
+ add_translation($language, unserialize($data));
+ } else {
+ $loaded = false;
+ }
+ }
- if (!$CURRENT_LANGUAGE) {
- $CURRENT_LANGUAGE = get_language();
- }
- if (!$language) {
- $language = $CURRENT_LANGUAGE;
+ if ($loaded) {
+ $CONFIG->i18n_loaded_from_cache = true;
+ // this is here to force
+ $CONFIG->language_paths[dirname(dirname(dirname(__FILE__))) . "/languages/"] = true;
+ return;
+ }
}
- if (isset($CONFIG->translations[$language][$message_key])) {
- $string = $CONFIG->translations[$language][$message_key];
- } else if (isset($CONFIG->translations["en"][$message_key])) {
- $string = $CONFIG->translations["en"][$message_key];
- } else {
- $string = $message_key;
- }
+ // load core translations from languages directory
+ register_translations(dirname(dirname(dirname(__FILE__))) . "/languages/");
+}
- // only pass through if we have arguments to allow backward compatibility
- // with manual sprintf() calls.
- if ($args) {
- $string = vsprintf($string, $args);
- }
- return $string;
-}
/**
* When given a full path, finds translation files and loads them
@@ -140,7 +178,7 @@ function elgg_echo($message_key, $args = array(), $language = "") {
* @param bool $load_all If true all languages are loaded, if
* false only the current language + en are loaded
*
- * @return void
+ * @return bool success
*/
function register_translations($path, $load_all = false) {
global $CONFIG;
@@ -192,23 +230,37 @@ function register_translations($path, $load_all = false) {
/**
* Reload all translations from all registered paths.
*
- * This is only called by functions which need to know all possible translations, namely the
- * statistic gathering ones.
+ * This is only called by functions which need to know all possible translations.
*
* @todo Better on demand loading based on language_paths array
*
- * @return bool
+ * @return void
*/
function reload_all_translations() {
global $CONFIG;
static $LANG_RELOAD_ALL_RUN;
if ($LANG_RELOAD_ALL_RUN) {
- return null;
+ return;
}
- foreach ($CONFIG->language_paths as $path => $dummy) {
- register_translations($path, true);
+ if ($CONFIG->i18n_loaded_from_cache) {
+ $cache = elgg_get_system_cache();
+ $cache_dir = $cache->getVariable("cache_path");
+ $filenames = elgg_get_file_list($cache_dir, array(), array(), array(".lang"));
+ foreach ($filenames as $filename) {
+ if (preg_match('/([a-z]+)\.[^.]+$/', $filename, $matches)) {
+ $language = $matches[1];
+ $data = elgg_load_system_cache("$language.lang");
+ if ($data) {
+ add_translation($language, unserialize($data));
+ }
+ }
+ }
+ } else {
+ foreach ($CONFIG->language_paths as $path => $dummy) {
+ register_translations($path, true);
+ }
}
$LANG_RELOAD_ALL_RUN = true;
@@ -300,5 +352,3 @@ function get_missing_language_keys($language) {
return false;
}
-
-register_translations(dirname(dirname(dirname(__FILE__))) . "/languages/");
diff --git a/engine/lib/location.php b/engine/lib/location.php
index 7e2c38fc8..1534c7d7b 100644
--- a/engine/lib/location.php
+++ b/engine/lib/location.php
@@ -74,7 +74,7 @@ function elgg_geocode_location($location) {
*
* @see ElggEntity::setLatLong()
*
- * @return array
+ * @return mixed If count, int. If not count, array. false on errors.
* @since 1.8.0
*/
function elgg_get_entities_from_location(array $options = array()) {
@@ -101,7 +101,7 @@ function elgg_get_entities_from_location(array $options = array()) {
$long_min = $long - $long_distance;
$long_max = $long + $long_distance;
- $where = array();
+ $wheres = array();
$wheres[] = "lat_name.string='geo:lat'";
$wheres[] = "lat_value.string >= $lat_min";
$wheres[] = "lat_value.string <= $lat_max";
@@ -139,7 +139,7 @@ function elgg_get_entities_from_location(array $options = array()) {
/**
* Returns a viewable list of entities from location
*
- * @param array $options
+ * @param array $options Options array
*
* @see elgg_list_entities()
* @see elgg_get_entities_from_location()
diff --git a/engine/lib/mb_wrapper.php b/engine/lib/mb_wrapper.php
index c2f5503e0..68fa69005 100644
--- a/engine/lib/mb_wrapper.php
+++ b/engine/lib/mb_wrapper.php
@@ -11,7 +11,7 @@ if (is_callable('mb_internal_encoding')) {
* NOTE: This differs from parse_str() by returning the results
* instead of placing them in the local scope!
*
- * @param str $str The string
+ * @param string $str The string
*
* @return array
* @since 1.7.0
diff --git a/engine/lib/memcache.php b/engine/lib/memcache.php
index f79fba4a9..79b87e850 100644
--- a/engine/lib/memcache.php
+++ b/engine/lib/memcache.php
@@ -35,3 +35,23 @@ function is_memcache_available() {
return $memcache_available;
}
+
+/**
+ * Invalidate an entity in memcache
+ *
+ * @param int $entity_guid The GUID of the entity to invalidate
+ *
+ * @return void
+ * @access private
+ */
+function _elgg_invalidate_memcache_for_entity($entity_guid) {
+ static $newentity_cache;
+
+ if ((!$newentity_cache) && (is_memcache_available())) {
+ $newentity_cache = new ElggMemcache('new_entity_cache');
+ }
+
+ if ($newentity_cache) {
+ $newentity_cache->delete($entity_guid);
+ }
+} \ No newline at end of file
diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php
index a6b1bb43a..fdb1b85f6 100644
--- a/engine/lib/metadata.php
+++ b/engine/lib/metadata.php
@@ -12,7 +12,8 @@
*
* @param stdClass $row An object from the database
*
- * @return stdClass or ElggMetadata
+ * @return stdClass|ElggMetadata
+ * @access private
*/
function row_to_elggmetadata($row) {
if (!($row instanceof stdClass)) {
@@ -29,7 +30,7 @@ function row_to_elggmetadata($row) {
*
* @param int $id The id of the metadata object being retrieved.
*
- * @return false|ElggMetadata
+ * @return ElggMetadata|false FALSE if not found
*/
function elgg_get_metadata_from_id($id) {
return elgg_get_metastring_based_object_from_id($id, 'metadata');
@@ -63,7 +64,7 @@ function elgg_delete_metadata_by_id($id) {
* @param int $access_id Default is ACCESS_PRIVATE
* @param bool $allow_multiple Allow multiple values for one key. Default is FALSE
*
- * @return int/bool id of metadata or FALSE if failure
+ * @return int|false id of metadata or FALSE if failure
*/
function create_metadata($entity_guid, $name, $value, $value_type = '', $owner_guid = 0,
$access_id = ACCESS_PRIVATE, $allow_multiple = false) {
@@ -89,8 +90,6 @@ function create_metadata($entity_guid, $name, $value, $value_type = '', $owner_g
$access_id = (int)$access_id;
- $id = false;
-
$query = "SELECT * from {$CONFIG->dbprefix}metadata"
. " WHERE entity_guid = $entity_guid and name_id=" . add_metastring($name) . " limit 1";
@@ -105,34 +104,33 @@ function create_metadata($entity_guid, $name, $value, $value_type = '', $owner_g
} else {
// Support boolean types
if (is_bool($value)) {
- if ($value) {
- $value = 1;
- } else {
- $value = 0;
- }
+ $value = (int) $value;
}
// Add the metastrings
- $value = add_metastring($value);
- if (!$value) {
+ $value_id = add_metastring($value);
+ if (!$value_id) {
return false;
}
- $name = add_metastring($name);
- if (!$name) {
+ $name_id = add_metastring($name);
+ if (!$name_id) {
return false;
}
// If ok then add it
$query = "INSERT into {$CONFIG->dbprefix}metadata"
. " (entity_guid, name_id, value_id, value_type, owner_guid, time_created, access_id)"
- . " VALUES ($entity_guid, '$name','$value','$value_type', $owner_guid, $time, $access_id)";
+ . " VALUES ($entity_guid, '$name_id','$value_id','$value_type', $owner_guid, $time, $access_id)";
$id = insert_data($query);
if ($id !== false) {
$obj = elgg_get_metadata_from_id($id);
if (elgg_trigger_event('create', 'metadata', $obj)) {
+
+ elgg_get_metadata_cache()->save($entity_guid, $name, $value, $allow_multiple);
+
return $id;
} else {
elgg_delete_metadata_by_id($id);
@@ -174,6 +172,7 @@ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_i
}
if ($metabyname_memcache) {
+ // @todo fix memcache (name_id is not a property of ElggMetadata)
$metabyname_memcache->delete("{$md->entity_guid}:{$md->name_id}");
}
@@ -186,41 +185,37 @@ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_i
$access_id = (int)$access_id;
- $access = get_access_sql_suffix();
-
// Support boolean types (as integers)
if (is_bool($value)) {
- if ($value) {
- $value = 1;
- } else {
- $value = 0;
- }
+ $value = (int) $value;
}
// Add the metastring
- $value = add_metastring($value);
- if (!$value) {
+ $value_id = add_metastring($value);
+ if (!$value_id) {
return false;
}
- $name = add_metastring($name);
- if (!$name) {
+ $name_id = add_metastring($name);
+ if (!$name_id) {
return false;
}
// If ok then add it
$query = "UPDATE {$CONFIG->dbprefix}metadata"
- . " set name_id='$name', value_id='$value', value_type='$value_type', access_id=$access_id,"
+ . " set name_id='$name_id', value_id='$value_id', value_type='$value_type', access_id=$access_id,"
. " owner_guid=$owner_guid where id=$id";
$result = update_data($query);
if ($result !== false) {
+
+ elgg_get_metadata_cache()->save($md->entity_guid, $name, $value);
+
+ // @todo this event tells you the metadata has been updated, but does not
+ // let you do anything about it. What is needed is a plugin hook before
+ // the update that passes old and new values.
$obj = elgg_get_metadata_from_id($id);
- if (elgg_trigger_event('update', 'metadata', $obj)) {
- return true;
- } else {
- elgg_delete_metadata_by_id($id);
- }
+ elgg_trigger_event('update', 'metadata', $obj);
}
return $result;
@@ -234,7 +229,7 @@ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_i
* associative arrays and there is no guarantee on the ordering in the array.
*
* @param int $entity_guid The entity to attach the metadata to
- * @param string $name_and_values Associative array - a value can be a string, number, bool
+ * @param array $name_and_values Associative array - a value can be a string, number, bool
* @param string $value_type 'text', 'integer', or '' for automatic detection
* @param int $owner_guid GUID of entity that owns the metadata
* @param int $access_id Default is ACCESS_PRIVATE
@@ -269,26 +264,31 @@ $access_id = ACCESS_PRIVATE, $allow_multiple = false) {
*
* @param array $options Array in format:
*
- * metadata_names => NULL|ARR metadata names
- *
- * metadata_values => NULL|ARR metadata values
- *
-* metadata_ids => NULL|ARR metadata ids
- *
- * metadata_case_sensitive => BOOL Overall Case sensitive
- *
- * metadata_owner_guids => NULL|ARR guids for metadata owners
- *
- * metadata_created_time_lower => INT Lower limit for created time.
- *
- * metadata_created_time_upper => INT Upper limit for created time.
- *
- * metadata_calculation => STR Perform the MySQL function on the metadata values returned.
- *
- * @return mixed
+ * metadata_names => NULL|ARR metadata names
+ * metadata_values => NULL|ARR metadata values
+ * metadata_ids => NULL|ARR metadata ids
+ * metadata_case_sensitive => BOOL Overall Case sensitive
+ * metadata_owner_guids => NULL|ARR guids for metadata owners
+ * metadata_created_time_lower => INT Lower limit for created time.
+ * metadata_created_time_upper => INT Upper limit for created time.
+ * metadata_calculation => STR Perform the MySQL function on the metadata values returned.
+ * The "metadata_calculation" option causes this function to
+ * return the result of performing a mathematical calculation on
+ * all metadata that match the query instead of returning
+ * ElggMetadata objects.
+ *
+ * @return ElggMetadata[]|mixed
* @since 1.8.0
*/
function elgg_get_metadata(array $options = array()) {
+
+ // @todo remove support for count shortcut - see #4393
+ // support shortcut of 'count' => true for 'metadata_calculation' => 'count'
+ if (isset($options['count']) && $options['count']) {
+ $options['metadata_calculation'] = 'count';
+ unset($options['count']);
+ }
+
$options['metastring_type'] = 'metadata';
return elgg_get_metastring_based_objects($options);
}
@@ -297,20 +297,25 @@ function elgg_get_metadata(array $options = array()) {
* Deletes metadata based on $options.
*
* @warning Unlike elgg_get_metadata() this will not accept an empty options array!
- * This requires some constraints: metadata_owner_guid(s),
- * metadata_name(s), metadata_value(s), or limit must be set.
+ * This requires at least one constraint: metadata_owner_guid(s),
+ * metadata_name(s), metadata_value(s), or guid(s) must be set.
*
- * @param array $options An options array. {@See elgg_get_metadata()}
- * @return mixed
- * @since 1.8
+ * @param array $options An options array. {@see elgg_get_metadata()}
+ * @return bool|null true on success, false on failure, null if no metadata to delete.
+ * @since 1.8.0
*/
function elgg_delete_metadata(array $options) {
if (!elgg_is_valid_options_for_batch_operation($options, 'metadata')) {
return false;
}
-
$options['metastring_type'] = 'metadata';
- return elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback');
+ $result = elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback', false);
+
+ // This moved last in case an object's constructor sets metadata. Currently the batch
+ // delete process has to create the entity to delete its metadata. See #5214
+ elgg_get_metadata_cache()->invalidateByOptions('delete', $options);
+
+ return $result;
}
/**
@@ -319,16 +324,22 @@ function elgg_delete_metadata(array $options) {
* @warning Unlike elgg_get_metadata() this will not accept an empty options array!
*
* @param array $options An options array. {@See elgg_get_metadata()}
- * @return mixed
- * @since 1.8
+ * @return bool|null true on success, false on failure, null if no metadata disabled.
+ * @since 1.8.0
*/
function elgg_disable_metadata(array $options) {
if (!elgg_is_valid_options_for_batch_operation($options, 'metadata')) {
return false;
}
- $options['metastrings_type'] = 'metadata';
- return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback');
+ elgg_get_metadata_cache()->invalidateByOptions('disable', $options);
+
+ // if we can see hidden (disabled) we need to use the offset
+ // otherwise we risk an infinite loop if there are more than 50
+ $inc_offset = access_get_show_hidden_status();
+
+ $options['metastring_type'] = 'metadata';
+ return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', $inc_offset);
}
/**
@@ -336,15 +347,20 @@ function elgg_disable_metadata(array $options) {
*
* @warning Unlike elgg_get_metadata() this will not accept an empty options array!
*
+ * @warning In order to enable metadata, you must first use
+ * {@link access_show_hidden_entities()}.
+ *
* @param array $options An options array. {@See elgg_get_metadata()}
- * @return mixed
- * @since 1.8
+ * @return bool|null true on success, false on failure, null if no metadata enabled.
+ * @since 1.8.0
*/
function elgg_enable_metadata(array $options) {
if (!$options || !is_array($options)) {
return false;
}
+ elgg_get_metadata_cache()->invalidateByOptions('enable', $options);
+
$options['metastring_type'] = 'metadata';
return elgg_batch_metastring_based_objects($options, 'elgg_batch_enable_callback');
}
@@ -358,15 +374,25 @@ function elgg_enable_metadata(array $options) {
* options available to elgg_get_entities(). Supports
* the singular option shortcut.
*
- * NB: Using metadata_names and metadata_values results in a
+ * @note Using metadata_names and metadata_values results in a
* "names IN (...) AND values IN (...)" clause. This is subtly
* differently than default multiple metadata_name_value_pairs, which use
* "(name = value) AND (name = value)" clauses.
*
* When in doubt, use name_value_pairs.
*
+ * To ask for entities that do not have a metadata value, use a custom
+ * where clause like this:
+ *
+ * $options['wheres'][] = "NOT EXISTS (
+ * SELECT 1 FROM {$dbprefix}metadata md
+ * WHERE md.entity_guid = e.guid
+ * AND md.name_id = $name_metastring_id
+ * AND md.value_id = $value_metastring_id)";
+ *
+ * Note the metadata name and value has been denormalized in the above example.
+ *
* @see elgg_get_entities
- * @see elgg_get_entities_from_annotations
*
* @param array $options Array in format:
*
@@ -380,9 +406,11 @@ function elgg_enable_metadata(array $options) {
* 'operand' => '=',
* 'case_sensitive' => TRUE
* )
- * Currently if multiple values are sent via
+ * Currently if multiple values are sent via
* an array (value => array('value1', 'value2')
* the pair's operand will be forced to "IN".
+ * If passing "IN" as the operand and a string as the value,
+ * the value must be a properly quoted and escaped string.
*
* metadata_name_value_pairs_operator => NULL|STR The operator to use for combining
* (name = value) OPERATOR (name = value); default AND
@@ -398,20 +426,20 @@ function elgg_enable_metadata(array $options) {
*
* metadata_owner_guids => NULL|ARR guids for metadata owners
*
- * @return array
+ * @return ElggEntity[]|mixed If count, int. If not count, array. false on errors.
* @since 1.7.0
*/
function elgg_get_entities_from_metadata(array $options = array()) {
$defaults = array(
- 'metadata_names' => ELGG_ENTITIES_ANY_VALUE,
- 'metadata_values' => ELGG_ENTITIES_ANY_VALUE,
- 'metadata_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE,
+ 'metadata_names' => ELGG_ENTITIES_ANY_VALUE,
+ 'metadata_values' => ELGG_ENTITIES_ANY_VALUE,
+ 'metadata_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE,
- 'metadata_name_value_pairs_operator'=> 'AND',
- 'metadata_case_sensitive' => TRUE,
- 'order_by_metadata' => array(),
+ 'metadata_name_value_pairs_operator' => 'AND',
+ 'metadata_case_sensitive' => TRUE,
+ 'order_by_metadata' => array(),
- 'metadata_owner_guids' => ELGG_ENTITIES_ANY_VALUE,
+ 'metadata_owner_guids' => ELGG_ENTITIES_ANY_VALUE,
);
$options = array_merge($defaults, $options);
@@ -436,19 +464,20 @@ function elgg_get_entities_from_metadata(array $options = array()) {
* This function is reused for annotations because the tables are
* exactly the same.
*
- * @param string $e_table Entities table name
- * @param string $n_table Normalized metastrings table name (Where entities,
+ * @param string $e_table Entities table name
+ * @param string $n_table Normalized metastrings table name (Where entities,
* values, and names are joined. annotations / metadata)
- * @param arr|null $names Array of names
- * @param arr|null $values Array of values
- * @param arr|null $pairs Array of names / values / operands
- * @param and|or $pair_operator Operator to use to join the where clauses for pairs
- * @param bool $case_sensitive Case sensitive metadata names?
- * @param arr|null $order_by_metadata Array of names / direction
- * @param arr|null $owner_guids Array of owner GUIDs
- *
- * @return FALSE|array False on fail, array('joins', 'wheres')
+ * @param array|null $names Array of names
+ * @param array|null $values Array of values
+ * @param array|null $pairs Array of names / values / operands
+ * @param string $pair_operator ("AND" or "OR") Operator to use to join the where clauses for pairs
+ * @param bool $case_sensitive Case sensitive metadata names?
+ * @param array|null $order_by_metadata Array of names / direction
+ * @param array|null $owner_guids Array of owner GUIDs
+ *
+ * @return false|array False on fail, array('joins', 'wheres')
* @since 1.7.0
+ * @access private
*/
function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $values = NULL,
$pairs = NULL, $pair_operator = 'AND', $case_sensitive = TRUE, $order_by_metadata = NULL,
@@ -593,6 +622,8 @@ $owner_guids = NULL) {
// if the operand is IN don't quote it because quoting should be done already.
if (is_numeric($pair['value'])) {
$value = sanitise_string($pair['value']);
+ } else if (is_bool($pair['value'])) {
+ $value = (int) $pair['value'];
} else if (is_array($pair['value'])) {
$values_array = array();
@@ -633,7 +664,7 @@ $owner_guids = NULL) {
$i++;
}
- if ($where = implode (" $pair_operator ", $pair_wheres)) {
+ if ($where = implode(" $pair_operator ", $pair_wheres)) {
$wheres[] = "($where)";
}
}
@@ -717,6 +748,9 @@ function elgg_list_entities_from_metadata($options) {
* @param mixed $params Params
*
* @return array
+ * @access private
+ *
+ * @throws InvalidParameterException
*/
function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params) {
// Sanity check values
@@ -728,15 +762,13 @@ function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params)
throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonArrayReturnValue'));
}
- $guid = (int)$params['guid'];
- $name = $params['name'];
-
$result = elgg_get_metadata(array(
- 'guid' => $guid,
- 'limit' => 0
+ 'guid' => (int)$params['guid'],
+ 'limit' => 0,
));
if ($result) {
+ /* @var ElggMetadata[] $result */
foreach ($result as $r) {
$returnvalue[] = $r->export();
}
@@ -747,7 +779,7 @@ function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params)
/**
* Takes in a comma-separated string and returns an array of tags
- * which have been trimmed and set to lower case
+ * which have been trimmed
*
* @param string $string Comma-separated tag string
*
@@ -756,17 +788,12 @@ function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params)
function string_to_tag_array($string) {
if (is_string($string)) {
$ar = explode(",", $string);
- // trim blank spaces
$ar = array_map('trim', $ar);
- // make lower case : [Marcus Povey 20090605 - Using mb wrapper function
- // using UTF8 safe function where available]
- $ar = array_map('elgg_strtolower', $ar);
- // Remove null values
$ar = array_filter($ar, 'is_not_null');
+ $ar = array_map('strip_tags', $ar);
return $ar;
}
return false;
-
}
/**
@@ -870,8 +897,8 @@ function metadata_update($event, $object_type, $object) {
/**
* Register a metadata url handler.
*
- * @param string $function_name The function.
* @param string $extender_name The name, default 'all'.
+ * @param string $function The function name.
*
* @return bool
*/
@@ -879,6 +906,50 @@ function elgg_register_metadata_url_handler($extender_name, $function) {
return elgg_register_extender_url_handler('metadata', $extender_name, $function);
}
+/**
+ * Get the global metadata cache instance
+ *
+ * @return ElggVolatileMetadataCache
+ *
+ * @access private
+ */
+function elgg_get_metadata_cache() {
+ global $CONFIG;
+ if (empty($CONFIG->local_metadata_cache)) {
+ $CONFIG->local_metadata_cache = new ElggVolatileMetadataCache();
+ }
+ return $CONFIG->local_metadata_cache;
+}
+
+/**
+ * Invalidate the metadata cache based on options passed to various *_metadata functions
+ *
+ * @param string $action Action performed on metadata. "delete", "disable", or "enable"
+ * @param array $options Options passed to elgg_(delete|disable|enable)_metadata
+ * @return void
+ */
+function elgg_invalidate_metadata_cache($action, array $options) {
+ // remove as little as possible, optimizing for common cases
+ $cache = elgg_get_metadata_cache();
+ if (empty($options['guid'])) {
+ // safest to clear everything unless we want to make this even more complex :(
+ $cache->flush();
+ } else {
+ if (empty($options['metadata_name'])) {
+ // safest to clear the whole entity
+ $cache->clear($options['guid']);
+ } else {
+ switch ($action) {
+ case 'delete':
+ $cache->markEmpty($options['guid'], $options['metadata_name']);
+ break;
+ default:
+ $cache->markUnknown($options['guid'], $options['metadata_name']);
+ }
+ }
+ }
+}
+
/** Register the hook */
elgg_register_plugin_hook_handler("export", "all", "export_metadata_plugin_hook", 2);
@@ -897,9 +968,11 @@ elgg_register_plugin_hook_handler('unit_test', 'system', 'metadata_test');
* @param mixed $params Params
*
* @return array
+ * @access private
*/
function metadata_test($hook, $type, $value, $params) {
global $CONFIG;
$value[] = $CONFIG->path . 'engine/tests/api/metadata.php';
+ $value[] = $CONFIG->path . 'engine/tests/api/metadata_cache.php';
return $value;
-} \ No newline at end of file
+}
diff --git a/engine/lib/metastrings.php b/engine/lib/metastrings.php
index 47712d3fa..57d876c06 100644
--- a/engine/lib/metastrings.php
+++ b/engine/lib/metastrings.php
@@ -67,7 +67,7 @@ function get_metastring_id($string, $case_sensitive = TRUE) {
}
$row = FALSE;
- $metaStrings = get_data($query, "entity_row_to_elggstar");
+ $metaStrings = get_data($query);
if (is_array($metaStrings)) {
if (sizeof($metaStrings) > 1) {
$ids = array();
@@ -75,7 +75,7 @@ function get_metastring_id($string, $case_sensitive = TRUE) {
$ids[] = $metaString->id;
}
return $ids;
- } else if ($metaStrings) {
+ } else if (isset($metaStrings[0])) {
$row = $metaStrings[0];
}
}
@@ -161,6 +161,7 @@ function add_metastring($string, $case_sensitive = true) {
* Delete any orphaned entries in metastrings. This is run by the garbage collector.
*
* @return bool
+ * @access private
*/
function delete_orphaned_metastrings() {
global $CONFIG;
@@ -211,23 +212,29 @@ function delete_orphaned_metastrings() {
*
* @param array $options Array in format:
*
- * metastring_names => NULL|ARR metastring names
+ * metastring_names => NULL|ARR metastring names
*
- * metastring_values => NULL|ARR metastring values
+ * metastring_values => NULL|ARR metastring values
*
- * metastring_ids => NULL|ARR metastring ids
+ * metastring_ids => NULL|ARR metastring ids
*
- * metastring_case_sensitive => BOOL Overall Case sensitive
+ * metastring_case_sensitive => BOOL Overall Case sensitive
*
- * metastring_owner_guids => NULL|ARR guids for metadata owners
+ * metastring_owner_guids => NULL|ARR Guids for metadata owners
*
- * metastring_created_time_lower => INT Lower limit for created time.
+ * metastring_created_time_lower => INT Lower limit for created time.
*
- * metastring_created_time_upper => INT Upper limit for created time.
+ * metastring_created_time_upper => INT Upper limit for created time.
*
- * metastring_calculation => STR Perform the MySQL function on the metastring values returned.
+ * metastring_calculation => STR Perform the MySQL function on the metastring values
+ * returned.
+ * This differs from egef_annotation_calculation in that
+ * it returns only the calculation of all annotation values.
+ * You can sum, avg, count, etc. egef_annotation_calculation()
+ * returns ElggEntities ordered by a calculation on their
+ * annotation values.
*
- * metastring_type => STR metadata or annotation(s)
+ * metastring_type => STR metadata or annotation(s)
*
* @return mixed
* @access private
@@ -319,7 +326,7 @@ function elgg_get_metastring_based_objects($options) {
'metastring_owner_guid', 'metastring_id',
'select', 'where', 'join'
);
-
+
$options = elgg_normalise_plural_options_array($options, $singulars);
if (!$options) {
@@ -354,9 +361,6 @@ function elgg_get_metastring_based_objects($options) {
$wheres[] = elgg_get_guid_based_where_sql('n_table.owner_guid',
$options['metastring_owner_guids']);
- // remove identical where clauses
- $wheres = array_unique($wheres);
-
// see if any functions failed
// remove empty strings on successful functions
foreach ($wheres as $i => $where) {
@@ -367,20 +371,39 @@ function elgg_get_metastring_based_objects($options) {
}
}
+ // remove identical where clauses
+ $wheres = array_unique($wheres);
+
// evaluate join clauses
if (!is_array($options['joins'])) {
$options['joins'] = array($options['joins']);
}
$joins = $options['joins'];
-
$joins[] = "JOIN {$db_prefix}entities e ON n_table.entity_guid = e.guid";
- $joins[] = "JOIN {$db_prefix}metastrings n on n_table.name_id = n.id";
- $joins[] = "JOIN {$db_prefix}metastrings v on n_table.value_id = v.id";
+ // evaluate selects
+ if (!is_array($options['selects'])) {
+ $options['selects'] = array($options['selects']);
+ }
- // remove identical join clauses
- $joins = array_unique($joins);
+ $selects = $options['selects'];
+
+ // For performance reasons we don't want the joins required for metadata / annotations
+ // unless we're going through one of their callbacks.
+ // this means we expect the functions passing different callbacks to pass their required joins.
+ // If we're doing a calculation
+ $custom_callback = ($options['callback'] == 'row_to_elggmetadata'
+ || $options['callback'] == 'row_to_elggannotation');
+ $is_calculation = $options['metastring_calculation'] ? true : false;
+
+ if ($custom_callback || $is_calculation) {
+ $joins[] = "JOIN {$db_prefix}metastrings n on n_table.name_id = n.id";
+ $joins[] = "JOIN {$db_prefix}metastrings v on n_table.value_id = v.id";
+
+ $selects[] = 'n.string as name';
+ $selects[] = 'v.string as value';
+ }
foreach ($joins as $i => $join) {
if ($join === FALSE) {
@@ -398,20 +421,31 @@ function elgg_get_metastring_based_objects($options) {
if ($metastring_clauses) {
$wheres = array_merge($wheres, $metastring_clauses['wheres']);
$joins = array_merge($joins, $metastring_clauses['joins']);
+ } else {
+ $wheres[] = get_access_sql_suffix('n_table');
}
- // check for calculations
- if ($options['count']) {
- $options['metastring_calculation'] = 'count';
- }
+ if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) {
+ $selects = array_unique($selects);
+ // evalutate selects
+ $select_str = '';
+ if ($selects) {
+ foreach ($selects as $select) {
+ $select_str .= ", $select";
+ }
+ }
- if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE) {
- $query = "SELECT DISTINCT n_table.*, n.string as name,
- v.string as value FROM {$db_prefix}$type n_table";
+ $query = "SELECT DISTINCT n_table.*{$select_str} FROM {$db_prefix}$type n_table";
+ } elseif ($options['count']) {
+ // count is over the entities
+ $query = "SELECT count(DISTINCT e.guid) as calculation FROM {$db_prefix}$type n_table";
} else {
$query = "SELECT {$options['metastring_calculation']}(v.string) as calculation FROM {$db_prefix}$type n_table";
}
+ // remove identical join clauses
+ $joins = array_unique($joins);
+
// add joins
foreach ($joins as $j) {
$query .= " $j ";
@@ -433,7 +467,7 @@ function elgg_get_metastring_based_objects($options) {
$defaults['order_by']);
}
- if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE) {
+ if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) {
if (isset($options['group_by'])) {
$options['group_by'] = sanitise_string($options['group_by']);
$query .= " GROUP BY {$options['group_by']}";
@@ -446,7 +480,7 @@ function elgg_get_metastring_based_objects($options) {
if ($options['limit']) {
$limit = sanitise_int($options['limit']);
- $offset = sanitise_int($options['offset']);
+ $offset = sanitise_int($options['offset'], false);
$query .= " LIMIT $offset, $limit";
}
@@ -471,6 +505,7 @@ function elgg_get_metastring_based_objects($options) {
* @param bool $case_sensitive Should name and values be case sensitive?
*
* @return array
+ * @access private
*/
function elgg_get_metastring_sql($table, $names = null, $values = null,
$pairs = null, $ids = null, $case_sensitive = false) {
@@ -480,21 +515,16 @@ function elgg_get_metastring_sql($table, $names = null, $values = null,
&& !$ids
&& (!$pairs && $pairs !== 0)) {
- return '';
+ return array();
}
$db_prefix = elgg_get_config('dbprefix');
- // join counter for incremental joins.
- $i = 1;
-
// binary forces byte-to-byte comparision of strings, making
// it case- and diacritical-mark- sensitive.
// only supported on values.
$binary = ($case_sensitive) ? ' BINARY ' : '';
- $access = get_access_sql_suffix($table);
-
$return = array (
'joins' => array (),
'wheres' => array()
@@ -559,13 +589,15 @@ function elgg_get_metastring_sql($table, $names = null, $values = null,
}
if ($names_where && $values_where) {
- $wheres[] = "($names_where AND $values_where AND $access)";
+ $wheres[] = "($names_where AND $values_where)";
} elseif ($names_where) {
- $wheres[] = "($names_where AND $access)";
+ $wheres[] = $names_where;
} elseif ($values_where) {
- $wheres[] = "($values_where AND $access)";
+ $wheres[] = $values_where;
}
+ $wheres[] = get_access_sql_suffix($table);
+
if ($where = implode(' AND ', $wheres)) {
$return['wheres'][] = "($where)";
}
@@ -574,13 +606,12 @@ function elgg_get_metastring_sql($table, $names = null, $values = null,
}
/**
- * Normalizes metadata / annotation option names to their
- * corresponding metastrings name.
+ * Normalizes metadata / annotation option names to their corresponding metastrings name.
*
* @param array $options An options array
- * @since 1.8
- * @access private
+ * @since 1.8.0
* @return array
+ * @access private
*/
function elgg_normalize_metastrings_options(array $options = array()) {
@@ -596,10 +627,10 @@ function elgg_normalize_metastrings_options(array $options = array()) {
// map the metadata_* options to metastring_* options
$map = array(
- 'names' => 'metastring_names',
- 'values' => 'metastring_values',
- 'case_sensitive' => 'metastring_case_sensitive',
- 'owner_guids' => 'metastring_owner_guids',
+ 'names' => 'metastring_names',
+ 'values' => 'metastring_values',
+ 'case_sensitive' => 'metastring_case_sensitive',
+ 'owner_guids' => 'metastring_owner_guids',
'created_time_lower' => 'metastring_created_time_lower',
'created_time_upper' => 'metastring_created_time_upper',
'calculation' => 'metastring_calculation',
@@ -629,10 +660,11 @@ function elgg_normalize_metastrings_options(array $options = array()) {
*
* @param int $id The object's ID
* @param string $enabled Value to set to: yes or no
- * @param string $type The type of table to use: metadata or anntations
+ * @param string $type The type of table to use: metadata or annotations
*
* @return bool
- * @since 1.8
+ * @throws InvalidParameterException
+ * @since 1.8.0
* @access private
*/
function elgg_set_metastring_based_object_enabled_by_id($id, $enabled, $type) {
@@ -682,21 +714,23 @@ function elgg_set_metastring_based_object_enabled_by_id($id, $enabled, $type) {
* @warning Unlike elgg_get_metastring_based_objects() this will not accept an
* empty options array!
*
- * @param array $options An options array. {@See elgg_get_metastring_based_objects()}
- * @param string $callback The callback to pass each result through
- * @return mixed
+ * @warning This returns null on no ops.
+ *
+ * @param array $options An options array. {@See elgg_get_metastring_based_objects()}
+ * @param string $callback The callback to pass each result through
+ * @param bool $inc_offset Increment the offset? Pass false for callbacks that delete / disable
+ *
+ * @return bool|null true on success, false on failure, null if no objects are found.
+ * @since 1.8.0
* @access private
- * @since 1.8
*/
-function elgg_batch_metastring_based_objects(array $options, $callback) {
+function elgg_batch_metastring_based_objects(array $options, $callback, $inc_offset = true) {
if (!$options || !is_array($options)) {
return false;
}
- $batch = new ElggBatch('elgg_get_metastring_based_objects', $options, $callback);
- $r = $batch->callbackResult;
-
- return $r;
+ $batch = new ElggBatch('elgg_get_metastring_based_objects', $options, $callback, 50, $inc_offset);
+ return $batch->callbackResult;
}
/**
@@ -704,9 +738,9 @@ function elgg_batch_metastring_based_objects(array $options, $callback) {
*
* @param int $id The metastring-based object's ID
* @param string $type The type: annotation or metadata
- * @return mixed
+ * @return ElggMetadata|ElggAnnotation
*
- * @since 1.8
+ * @since 1.8.0
* @access private
*/
function elgg_get_metastring_based_object_from_id($id, $type) {
@@ -736,7 +770,7 @@ function elgg_get_metastring_based_object_from_id($id, $type) {
* @param string $type The object's metastring type: annotation or metadata
* @return bool
*
- * @since 1.8
+ * @since 1.8.0
* @access private
*/
function elgg_delete_metastring_based_object_by_id($id, $type) {
@@ -770,12 +804,13 @@ function elgg_delete_metastring_based_object_by_id($id, $type) {
}
if ($metabyname_memcache) {
+ // @todo why name_id? is that even populated?
$metabyname_memcache->delete("{$obj->entity_guid}:{$obj->name_id}");
}
}
if (($obj->canEdit()) && (elgg_trigger_event('delete', $type, $obj))) {
- return delete_data("DELETE from $table where id=$id");
+ return (bool)delete_data("DELETE from $table where id=$id");
}
}
@@ -794,6 +829,7 @@ function elgg_delete_metastring_based_object_by_id($id, $type) {
*
* @return array
* @since 1.7.0
+ * @access private
*/
function elgg_entities_get_metastrings_options($type, $options) {
$valid_types = array('metadata', 'annotation');
@@ -858,6 +894,7 @@ elgg_register_plugin_hook_handler('unit_test', 'system', 'metastrings_test');
* @param mixed $params Params
*
* @return array
+ * @access private
*/
function metastrings_test($hook, $type, $value, $params) {
global $CONFIG;
diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php
index 953bbe59a..ab9cc05e8 100644
--- a/engine/lib/navigation.php
+++ b/engine/lib/navigation.php
@@ -20,20 +20,20 @@
* Menus
* Elgg uses a single interface to manage its menus. Menu items are added with
* {@link elgg_register_menu_item()}. This is generally used for menus that
- * appear only once per page. For context-sensitive menus (such as the hover
+ * appear only once per page. For dynamic menus (such as the hover
* menu for user's avatar), a plugin hook is emitted when the menu is being
* created. The hook is 'register', 'menu:<menu_name>'. For more details on this,
* @see elgg_view_menu().
*
* Menus supported by the Elgg core
* Standard menus:
- * site Site navihgation shown on every page.
+ * site Site navigation shown on every page.
* page Page menu usually shown in a sidebar. Uses Elgg's context.
* topbar Topbar menu shown on every page. The default has two sections.
* footer Like the topbar but in the footer.
* extras Links about content on the page. The RSS link is added to this.
*
- * Context-sensitive (also called just-in-time menus):
+ * Dynamic menus (also called just-in-time menus):
* user_hover Avatar hover menu. The user entity is passed as a parameter.
* entity The set of links shown in the summary of an entity.
* river Links shown on river items.
@@ -51,7 +51,10 @@
*
* @warning Generally you should not use this in response to the plugin hook:
* 'register', 'menu:<menu_name>'. If you do, you may end up with many incorrect
- * links on a context-sensitive menu.
+ * links on a dynamic menu.
+ *
+ * @warning A menu item's name must be unique per menu. If more than one menu
+ * item with the same name are registered, the last menu item takes priority.
*
* @see elgg_view_menu() for the plugin hooks available for modifying a menu as
* it is being rendered.
@@ -61,14 +64,25 @@
* @param mixed $menu_item A ElggMenuItem object or an array of options in format:
* name => STR Menu item identifier (required)
* text => STR Menu item display text (required)
- * href => STR Menu item URL (required) (false for non-links)
+ * href => STR Menu item URL (required) (false for non-links.
+ * @warning If you disable the href the <a> tag will
+ * not appear, so the link_class will not apply. If you
+ * put <a> tags in manually through the 'text' option
+ * the default CSS selector .elgg-menu-$menu > li > a
+ * may affect formatting. Wrap in a <span> if it does.)
* contexts => ARR Page context strings
* section => STR Menu section identifier
* title => STR Menu item tooltip
* selected => BOOL Is this menu item currently selected
* parent_name => STR Identifier of the parent menu item
+ * link_class => STR A class or classes for the <a> tag
+ * item_class => STR A class or classes for the <li> tag
*
- * Custom options can be added as key value pairs.
+ * Additional options that the view output/url takes can be
+ * passed in the array. If the 'confirm' key is passed, the
+ * menu link uses the 'output/confirmlink' view. Custom
+ * options can be added by using the 'data' key with the
+ * value being an associative array.
*
* @return bool
* @since 1.8.0
@@ -112,6 +126,7 @@ function elgg_unregister_menu_item($menu_name, $item_name) {
}
foreach ($CONFIG->menus[$menu_name] as $index => $menu_object) {
+ /* @var ElggMenuItem $menu_object */
if ($menu_object->getName() == $item_name) {
unset($CONFIG->menus[$menu_name][$index]);
return true;
@@ -137,7 +152,8 @@ function elgg_is_menu_item_registered($menu_name, $item_name) {
return false;
}
- foreach ($CONFIG->menus[$menu_name] as $index => $menu_object) {
+ foreach ($CONFIG->menus[$menu_name] as $menu_object) {
+ /* @var ElggMenuItem $menu_object */
if ($menu_object->getName() == $item_name) {
return true;
}
@@ -147,6 +163,44 @@ function elgg_is_menu_item_registered($menu_name, $item_name) {
}
/**
+ * Convenience function for registering a button to title menu
+ *
+ * The URL must be $handler/$name/$guid where $guid is the guid of the page owner.
+ * The label of the button is "$handler:$name" so that must be defined in a
+ * language file.
+ *
+ * This is used primarily to support adding an add content button
+ *
+ * @param string $handler The handler to use or null to autodetect from context
+ * @param string $name Name of the button
+ * @return void
+ * @since 1.8.0
+ */
+function elgg_register_title_button($handler = null, $name = 'add') {
+ if (elgg_is_logged_in()) {
+
+ if (!$handler) {
+ $handler = elgg_get_context();
+ }
+
+ $owner = elgg_get_page_owner_entity();
+ if (!$owner) {
+ // no owns the page so this is probably an all site list page
+ $owner = elgg_get_logged_in_user_entity();
+ }
+ if ($owner && $owner->canWriteToContainer()) {
+ $guid = $owner->getGUID();
+ elgg_register_menu_item('title', array(
+ 'name' => $name,
+ 'href' => "$handler/$name/$guid",
+ 'text' => elgg_echo("$handler:$name"),
+ 'link_class' => 'elgg-button elgg-button-action',
+ ));
+ }
+ }
+}
+
+/**
* Adds a breadcrumb to the breadcrumbs stack.
*
* @param string $title The title to display
@@ -159,12 +213,12 @@ function elgg_is_menu_item_registered($menu_name, $item_name) {
*/
function elgg_push_breadcrumb($title, $link = NULL) {
global $CONFIG;
- if (!is_array($CONFIG->breadcrumbs)) {
+ if (!isset($CONFIG->breadcrumbs)) {
$CONFIG->breadcrumbs = array();
}
// avoid key collisions.
- $CONFIG->breadcrumbs[] = array('title' => $title, 'link' => $link);
+ $CONFIG->breadcrumbs[] = array('title' => elgg_get_excerpt($title, 100), 'link' => $link);
}
/**
@@ -178,7 +232,7 @@ function elgg_pop_breadcrumb() {
global $CONFIG;
if (is_array($CONFIG->breadcrumbs)) {
- array_pop($CONFIG->breadcrumbs);
+ return array_pop($CONFIG->breadcrumbs);
}
return FALSE;
@@ -194,7 +248,11 @@ function elgg_pop_breadcrumb() {
function elgg_get_breadcrumbs() {
global $CONFIG;
- return (is_array($CONFIG->breadcrumbs)) ? $CONFIG->breadcrumbs : array();
+ if (isset($CONFIG->breadcrumbs) && is_array($CONFIG->breadcrumbs)) {
+ return $CONFIG->breadcrumbs;
+ }
+
+ return array();
}
/**
@@ -207,6 +265,7 @@ function elgg_get_breadcrumbs() {
* @param array $return Menu array
* @param array $params
* @return array
+ * @access private
*/
function elgg_site_menu_setup($hook, $type, $return, $params) {
@@ -237,7 +296,9 @@ function elgg_site_menu_setup($hook, $type, $return, $params) {
}
$return['default'] = $featured;
- $return['more'] = $registered;
+ if (count($registered) > 0) {
+ $return['more'] = $registered;
+ }
} else {
// no featured menu items set
$max_display_items = 5;
@@ -246,7 +307,38 @@ function elgg_site_menu_setup($hook, $type, $return, $params) {
// if only one item on more menu, stick it with the rest
$num_menu_items = count($return['default']);
if ($num_menu_items > ($max_display_items + 1)) {
- $return['more'] = array_splice($return['default'], $max_display_items);
+ $return['more'] = array_splice($return['default'], $max_display_items);
+ }
+ }
+
+ // check if we have anything selected
+ $selected = false;
+ foreach ($return as $section) {
+ foreach ($section as $item) {
+ if ($item->getSelected()) {
+ $selected = true;
+ break 2;
+ }
+ }
+ }
+
+ if (!$selected) {
+ // nothing selected, match name to context or match url
+ $current_url = current_page_url();
+ foreach ($return as $section_name => $section) {
+ foreach ($section as $key => $item) {
+ // only highlight internal links
+ if (strpos($item->getHref(), elgg_get_site_url()) === 0) {
+ if ($item->getName() == elgg_get_context()) {
+ $return[$section_name][$key]->setSelected(true);
+ break 2;
+ }
+ if ($item->getHref() == $current_url) {
+ $return[$section_name][$key]->setSelected(true);
+ break 2;
+ }
+ }
+ }
}
}
@@ -255,10 +347,12 @@ function elgg_site_menu_setup($hook, $type, $return, $params) {
/**
* Add the comment and like links to river actions menu
+ * @access private
*/
function elgg_river_menu_setup($hook, $type, $return, $params) {
if (elgg_is_logged_in()) {
$item = $params['item'];
+ /* @var ElggRiverItem $item */
$object = $item->getObjectEntity();
// comments and non-objects cannot be commented on or liked
if (!elgg_in_context('widgets') && $item->annotation_id == 0) {
@@ -269,12 +363,24 @@ function elgg_river_menu_setup($hook, $type, $return, $params) {
'href' => "#comments-add-$object->guid",
'text' => elgg_view_icon('speech-bubble'),
'title' => elgg_echo('comment:this'),
- 'class' => "elgg-toggler",
+ 'rel' => 'toggle',
'priority' => 50,
);
$return[] = ElggMenuItem::factory($options);
}
}
+
+ if (elgg_is_admin_logged_in()) {
+ $options = array(
+ 'name' => 'delete',
+ 'href' => elgg_add_action_tokens_to_url("action/river/delete?id=$item->id"),
+ 'text' => elgg_view_icon('delete'),
+ 'title' => elgg_echo('delete'),
+ 'confirm' => elgg_echo('deleteconfirm'),
+ 'priority' => 200,
+ );
+ $return[] = ElggMenuItem::factory($options);
+ }
}
return $return;
@@ -282,6 +388,7 @@ function elgg_river_menu_setup($hook, $type, $return, $params) {
/**
* Entity menu is list of links and info on any entity
+ * @access private
*/
function elgg_entity_menu_setup($hook, $type, $return, $params) {
if (elgg_in_context('widgets')) {
@@ -289,6 +396,7 @@ function elgg_entity_menu_setup($hook, $type, $return, $params) {
}
$entity = $params['entity'];
+ /* @var ElggEntity $entity */
$handler = elgg_extract('handler', $params, false);
// access
@@ -328,12 +436,92 @@ function elgg_entity_menu_setup($hook, $type, $return, $params) {
}
/**
+ * Widget menu is a set of widget controls
+ * @access private
+ */
+function elgg_widget_menu_setup($hook, $type, $return, $params) {
+
+ $widget = $params['entity'];
+ /* @var ElggWidget $widget */
+ $show_edit = elgg_extract('show_edit', $params, true);
+
+ $collapse = array(
+ 'name' => 'collapse',
+ 'text' => ' ',
+ 'href' => "#elgg-widget-content-$widget->guid",
+ 'class' => 'elgg-widget-collapse-button',
+ 'rel' => 'toggle',
+ 'priority' => 1
+ );
+ $return[] = ElggMenuItem::factory($collapse);
+
+ if ($widget->canEdit()) {
+ $delete = array(
+ 'name' => 'delete',
+ 'text' => elgg_view_icon('delete-alt'),
+ 'title' => elgg_echo('widget:delete', array($widget->getTitle())),
+ 'href' => "action/widgets/delete?widget_guid=$widget->guid",
+ 'is_action' => true,
+ 'class' => 'elgg-widget-delete-button',
+ 'id' => "elgg-widget-delete-button-$widget->guid",
+ 'priority' => 900
+ );
+ $return[] = ElggMenuItem::factory($delete);
+
+ if ($show_edit) {
+ $edit = array(
+ 'name' => 'settings',
+ 'text' => elgg_view_icon('settings-alt'),
+ 'title' => elgg_echo('widget:edit'),
+ 'href' => "#widget-edit-$widget->guid",
+ 'class' => "elgg-widget-edit-button",
+ 'rel' => 'toggle',
+ 'priority' => 800,
+ );
+ $return[] = ElggMenuItem::factory($edit);
+ }
+ }
+
+ return $return;
+}
+
+/**
+ * Adds a delete link to "generic_comment" annotations
+ * @access private
+ */
+function elgg_annotation_menu_setup($hook, $type, $return, $params) {
+ $annotation = $params['annotation'];
+ /* @var ElggAnnotation $annotation */
+
+ if ($annotation->name == 'generic_comment' && $annotation->canEdit()) {
+ $url = elgg_http_add_url_query_elements('action/comments/delete', array(
+ 'annotation_id' => $annotation->id,
+ ));
+
+ $options = array(
+ 'name' => 'delete',
+ 'href' => $url,
+ 'text' => "<span class=\"elgg-icon elgg-icon-delete\"></span>",
+ 'confirm' => elgg_echo('deleteconfirm'),
+ 'encode_text' => false
+ );
+ $return[] = ElggMenuItem::factory($options);
+ }
+
+ return $return;
+}
+
+
+/**
* Navigation initialization
+ * @access private
*/
function elgg_nav_init() {
elgg_register_plugin_hook_handler('prepare', 'menu:site', 'elgg_site_menu_setup');
elgg_register_plugin_hook_handler('register', 'menu:river', 'elgg_river_menu_setup');
elgg_register_plugin_hook_handler('register', 'menu:entity', 'elgg_entity_menu_setup');
+ elgg_register_plugin_hook_handler('register', 'menu:widget', 'elgg_widget_menu_setup');
+ elgg_register_plugin_hook_handler('register', 'menu:annotation', 'elgg_annotation_menu_setup');
}
elgg_register_event_handler('init', 'system', 'elgg_nav_init');
diff --git a/engine/lib/notification.php b/engine/lib/notification.php
index 0754d683a..be0c359d4 100644
--- a/engine/lib/notification.php
+++ b/engine/lib/notification.php
@@ -38,7 +38,7 @@ $NOTIFICATION_HANDLERS = array();
function register_notification_handler($method, $handler, $params = NULL) {
global $NOTIFICATION_HANDLERS;
- if (is_callable($handler)) {
+ if (is_callable($handler, true)) {
$NOTIFICATION_HANDLERS[$method] = new stdClass;
$NOTIFICATION_HANDLERS[$method]->handler = $handler;
@@ -86,7 +86,7 @@ function unregister_notification_handler($method) {
* @throws NotificationException
*/
function notify_user($to, $from, $subject, $message, array $params = NULL, $methods_override = "") {
- global $NOTIFICATION_HANDLERS, $CONFIG;
+ global $NOTIFICATION_HANDLERS;
// Sanitise
if (!is_array($to)) {
@@ -110,12 +110,15 @@ function notify_user($to, $from, $subject, $message, array $params = NULL, $meth
// Are we overriding delivery?
$methods = $methods_override;
if (!$methods) {
- $tmp = (array)get_user_notification_settings($guid);
+ $tmp = get_user_notification_settings($guid);
$methods = array();
- foreach ($tmp as $k => $v) {
- // Add method if method is turned on for user!
- if ($v) {
- $methods[] = $k;
+ // $tmp may be false. don't cast
+ if (is_object($tmp)) {
+ foreach ($tmp as $k => $v) {
+ // Add method if method is turned on for user!
+ if ($v) {
+ $methods[] = $k;
+ }
}
}
}
@@ -131,8 +134,9 @@ function notify_user($to, $from, $subject, $message, array $params = NULL, $meth
// Extract method details from list
$details = $NOTIFICATION_HANDLERS[$method];
$handler = $details->handler;
+ /* @var callable $handler */
- if ((!$NOTIFICATION_HANDLERS[$method]) || (!$handler)) {
+ if ((!$NOTIFICATION_HANDLERS[$method]) || (!$handler) || (!is_callable($handler))) {
error_log(elgg_echo('NotificationException:NoHandlerFound', array($method)));
}
@@ -140,7 +144,7 @@ function notify_user($to, $from, $subject, $message, array $params = NULL, $meth
// Trigger handler and retrieve result.
try {
- $result[$guid][$method] = $handler(
+ $result[$guid][$method] = call_user_func($handler,
$from ? get_entity($from) : NULL, // From entity
get_entity($guid), // To entity
$subject, // The subject
@@ -164,7 +168,7 @@ function notify_user($to, $from, $subject, $message, array $params = NULL, $meth
*
* @param int $user_guid The user id
*
- * @return stdClass
+ * @return stdClass|false
*/
function get_user_notification_settings($user_guid = 0) {
$user_guid = (int)$user_guid;
@@ -173,7 +177,8 @@ function get_user_notification_settings($user_guid = 0) {
$user_guid = elgg_get_logged_in_user_guid();
}
- // @todo: holy crap, really?
+ // @todo: there should be a better way now that metadata is cached. E.g. just query for MD names, then
+ // query user object directly
$all_metadata = elgg_get_metadata(array(
'guid' => $user_guid,
'limit' => 0
@@ -236,6 +241,8 @@ function set_user_notification_setting($user_guid, $method, $value) {
* @param array $params Optional parameters (none taken in this instance)
*
* @return bool
+ * @throws NotificationException
+ * @access private
*/
function email_notify_handler(ElggEntity $from, ElggUser $to, $subject, $message,
array $params = NULL) {
@@ -261,7 +268,7 @@ array $params = NULL) {
$to = $to->email;
// From
- $site = get_entity($CONFIG->site_guid);
+ $site = elgg_get_site_entity();
// If there's an email address, use it - but only if its not from a user.
if (!($from instanceof ElggUser) && $from->email) {
$from = $from->email;
@@ -286,6 +293,7 @@ array $params = NULL) {
* @param array $params Optional parameters (none used in this function)
*
* @return bool
+ * @throws NotificationException
* @since 1.7.2
*/
function elgg_send_email($from, $to, $subject, $body, array $params = NULL) {
@@ -342,6 +350,8 @@ function elgg_send_email($from, $to, $subject, $body, array $params = NULL) {
// Sanitise subject by stripping line endings
$subject = preg_replace("/(\r\n|\r|\n)/", " ", $subject);
+ // this is because Elgg encodes everything and matches what is done with body
+ $subject = html_entity_decode($subject, ENT_COMPAT, 'UTF-8'); // Decode any html entities
if (is_callable('mb_encode_mimeheader')) {
$subject = mb_encode_mimeheader($subject, "UTF-8", "B");
}
@@ -359,6 +369,7 @@ function elgg_send_email($from, $to, $subject, $body, array $params = NULL) {
* Correctly initialise notifications and register the email handler.
*
* @return void
+ * @access private
*/
function notification_init() {
// Register a notification handler for the default email method
@@ -375,6 +386,7 @@ function notification_init() {
*
* @return void
* @todo why can't this call action(...)?
+ * @access private
*/
function notification_user_settings_save() {
global $CONFIG;
@@ -418,7 +430,7 @@ function register_notification_object($entity_type, $object_subtype, $language_n
* @param int $user_guid The GUID of the user who wants to follow a user's content
* @param int $author_guid The GUID of the user whose content the user wants to follow
*
- * @return true|false Depending on success
+ * @return bool Depending on success
*/
function register_notification_interest($user_guid, $author_guid) {
return add_entity_relationship($user_guid, 'notify', $author_guid);
@@ -430,7 +442,7 @@ function register_notification_interest($user_guid, $author_guid) {
* @param int $user_guid The GUID of the user who is following a user's content
* @param int $author_guid The GUID of the user whose content the user wants to unfollow
*
- * @return true|false Depending on success
+ * @return bool Depending on success
*/
function remove_notification_interest($user_guid, $author_guid) {
return remove_entity_relationship($user_guid, 'notify', $author_guid);
@@ -446,11 +458,13 @@ function remove_notification_interest($user_guid, $author_guid) {
* @param string $object_type mixed
* @param mixed $object The object created
*
- * @return void
+ * @return bool
+ * @access private
*/
function object_notifications($event, $object_type, $object) {
// We only want to trigger notification events for ElggEntities
if ($object instanceof ElggEntity) {
+ /* @var ElggEntity $object */
// Get config data
global $CONFIG, $SESSION, $NOTIFICATION_HANDLERS;
@@ -476,35 +490,37 @@ function object_notifications($event, $object_type, $object) {
}
if (isset($CONFIG->register_objects[$object_type][$object_subtype])) {
- $descr = $CONFIG->register_objects[$object_type][$object_subtype];
- $string = $descr . ": " . $object->getURL();
+ $subject = $CONFIG->register_objects[$object_type][$object_subtype];
+ $string = $subject . ": " . $object->getURL();
// Get users interested in content from this person and notify them
// (Person defined by container_guid so we can also subscribe to groups if we want)
foreach ($NOTIFICATION_HANDLERS as $method => $foo) {
$interested_users = elgg_get_entities_from_relationship(array(
+ 'site_guids' => ELGG_ENTITIES_ANY_VALUE,
'relationship' => 'notify' . $method,
'relationship_guid' => $object->container_guid,
'inverse_relationship' => TRUE,
- 'types' => 'user',
- 'limit' => 99999
+ 'type' => 'user',
+ 'limit' => false
));
+ /* @var ElggUser[] $interested_users */
if ($interested_users && is_array($interested_users)) {
foreach ($interested_users as $user) {
if ($user instanceof ElggUser && !$user->isBanned()) {
if (($user->guid != $SESSION['user']->guid) && has_access_to_entity($object, $user)
&& $object->access_id != ACCESS_PRIVATE) {
- $methodstring = elgg_trigger_plugin_hook('notify:entity:message', $object->getType(), array(
+ $body = elgg_trigger_plugin_hook('notify:entity:message', $object->getType(), array(
'entity' => $object,
'to_entity' => $user,
'method' => $method), $string);
- if (empty($methodstring) && $methodstring !== false) {
- $methodstring = $string;
+ if (empty($body) && $body !== false) {
+ $body = $string;
}
- if ($methodstring !== false) {
- notify_user($user->guid, $object->container_guid, $descr, $methodstring,
- NULL, array($method));
+ if ($body !== false) {
+ notify_user($user->guid, $object->container_guid, $subject, $body,
+ null, array($method));
}
}
}
diff --git a/engine/lib/objects.php b/engine/lib/objects.php
index b138d6888..ff3cc733f 100644
--- a/engine/lib/objects.php
+++ b/engine/lib/objects.php
@@ -13,6 +13,7 @@
* @param int $guid The guid to retreive
*
* @return bool
+ * @access private
*/
function get_object_entity_as_row($guid) {
global $CONFIG;
@@ -30,6 +31,7 @@ function get_object_entity_as_row($guid) {
* @param string $description The object's description
*
* @return bool
+ * @access private
*/
function create_object_entity($guid, $title, $description) {
global $CONFIG;
@@ -51,11 +53,8 @@ function create_object_entity($guid, $title, $description) {
if ($result != false) {
// Update succeeded, continue
$entity = get_entity($guid);
- if (elgg_trigger_event('update', $entity->type, $entity)) {
- return $guid;
- } else {
- $entity->delete();
- }
+ elgg_trigger_event('update', $entity->type, $entity);
+ return $guid;
}
} else {
// Update failed, attempt an insert.
@@ -94,21 +93,22 @@ function get_object_sites($object_guid, $limit = 10, $offset = 0) {
return elgg_get_entities_from_relationship(array(
'relationship' => 'member_of_site',
'relationship_guid' => $object_guid,
- 'types' => 'site',
+ 'type' => 'site',
'limit' => $limit,
- 'offset' => $offset
+ 'offset' => $offset,
));
}
/**
* Runs unit tests for ElggObject
*
- * @param sting $hook unit_test
+ * @param string $hook unit_test
* @param string $type system
* @param mixed $value Array of tests
* @param mixed $params Params
*
* @return array
+ * @access private
*/
function objects_test($hook, $type, $value, $params) {
global $CONFIG;
diff --git a/engine/lib/opendd.php b/engine/lib/opendd.php
index 69977d1d9..7d635a295 100644
--- a/engine/lib/opendd.php
+++ b/engine/lib/opendd.php
@@ -7,12 +7,15 @@
* @version 0.4
*/
+// @codingStandardsIgnoreStart
+
/**
* Attempt to construct an ODD object out of a XmlElement or sub-elements.
*
* @param XmlElement $element The element(s)
*
* @return mixed An ODD object if the element can be handled, or false.
+ * @access private
*/
function ODD_factory (XmlElement $element) {
$name = $element->name;
@@ -57,6 +60,7 @@ function ODD_factory (XmlElement $element) {
* @param string $xml The XML ODD.
*
* @return ODDDocument
+ * @access private
*/
function ODD_Import($xml) {
// Parse XML to an array
@@ -96,7 +100,10 @@ function ODD_Import($xml) {
* @param ODDDocument $document The Document.
*
* @return string
+ * @access private
*/
function ODD_Export(ODDDocument $document) {
return "$document";
}
+
+// @codingStandardsIgnoreEnd
diff --git a/engine/lib/output.php b/engine/lib/output.php
index 3f35a1576..de4f911fb 100644
--- a/engine/lib/output.php
+++ b/engine/lib/output.php
@@ -12,29 +12,34 @@
*
* @param string $text The input string
*
- * @return string The output stirng with formatted links
- **/
+ * @return string The output string with formatted links
+ */
function parse_urls($text) {
+
+ // URI specification: http://www.ietf.org/rfc/rfc3986.txt
+ // This varies from the specification in the following ways:
+ // * Supports non-ascii characters
+ // * Does not allow parentheses and single quotes
+ // * Cuts off commas, exclamation points, and periods off as last character
+
// @todo this causes problems with <attr = "val">
- // must be ing <attr="val"> format (no space).
+ // must be in <attr="val"> format (no space).
// By default htmlawed rewrites tags to this format.
// if PHP supported conditional negative lookbehinds we could use this:
// $r = preg_replace_callback('/(?<!=)(?<![ ])?(?<!["\'])((ht|f)tps?:\/\/[^\s\r\n\t<>"\'\!\(\),]+)/i',
- //
- // we can put , in the list of excluded char but need to keep . because of domain names.
- // it is removed in the callback.
- $r = preg_replace_callback('/(?<!=)(?<!["\'])((ht|f)tps?:\/\/[^\s\r\n\t<>"\'\!\(\),]+)/i',
+ $r = preg_replace_callback('/(?<![=\/"\'])((ht|f)tps?:\/\/[^\s\r\n\t<>"\']+)/i',
create_function(
'$matches',
'
$url = $matches[1];
- $period = \'\';
- if (substr($url, -1, 1) == \'.\') {
- $period = \'.\';
- $url = trim($url, \'.\');
+ $punc = "";
+ $last = substr($url, -1, 1);
+ if (in_array($last, array(".", "!", ",", "(", ")"))) {
+ $punc = $last;
+ $url = rtrim($url, ".!,()");
}
$urltext = str_replace("/", "/<wbr />", $url);
- return "<a href=\"$url\" style=\"text-decoration:underline;\">$urltext</a>$period";
+ return "<a href=\"$url\" rel=\"nofollow\">$urltext</a>$punc";
'
), $text);
@@ -43,51 +48,26 @@ function parse_urls($text) {
/**
* Create paragraphs from text with line spacing
- * Borrowed from Wordpress.
*
* @param string $pee The string
- * @param bool $br Add BRs?
+ * @deprecated Use elgg_autop instead
+ * @todo Add deprecation warning in 1.9
*
- * @todo Rewrite
* @return string
**/
-function autop($pee, $br = 1) {
- $pee = $pee . "\n"; // just to make things a little easier, pad the end
- $pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee);
- // Space things out a little
- $allblocks = '(?:table|thead|tfoot|caption|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|map|area|blockquote|address|math|style|input|p|h[1-6]|hr)';
- $pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "\n$1", $pee);
- $pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
- $pee = str_replace(array("\r\n", "\r"), "\n", $pee); // cross-platform newlines
- if (strpos($pee, '<object') !== false) {
- $pee = preg_replace('|\s*<param([^>]*)>\s*|', "<param$1>", $pee); // no pee inside object/embed
- $pee = preg_replace('|\s*</embed>\s*|', '</embed>', $pee);
- }
- $pee = preg_replace("/\n\n+/", "\n\n", $pee); // take care of duplicates
- $pee = preg_replace('/\n?(.+?)(?:\n\s*\n|\z)/s', "<p>$1</p>\n", $pee); // make paragraphs, including one at the end
- $pee = preg_replace('|<p>\s*?</p>|', '', $pee); // under certain strange conditions it could create a P of entirely whitespace
- $pee = preg_replace('!<p>([^<]+)\s*?(</(?:div|address|form)[^>]*>)!', "<p>$1</p>$2", $pee);
- $pee = preg_replace( '|<p>|', "$1<p>", $pee );
- $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee); // don't pee all over a tag
- $pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // problem with nested lists
- $pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
- $pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
- $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
- $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
- if ($br) {
- $pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', create_function('$matches', 'return str_replace("\n", "<WPPreserveNewline />", $matches[0]);'), $pee);
- $pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); // optionally make line breaks
- $pee = str_replace('<WPPreserveNewline />', "\n", $pee);
- }
- $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
- $pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
-// if (strpos($pee, '<pre') !== false) {
-// mind the space between the ? and >. Only there because of the comment.
-// $pee = preg_replace_callback('!(<pre.*? >)(.*?)</pre>!is', 'clean_pre', $pee );
-// }
- $pee = preg_replace( "|\n</p>$|", '</p>', $pee );
-
- return $pee;
+function autop($pee) {
+ return elgg_autop($pee);
+}
+
+/**
+ * Create paragraphs from text with line spacing
+ *
+ * @param string $string The string
+ *
+ * @return string
+ **/
+function elgg_autop($string) {
+ return ElggAutoP::getInstance()->process($string);
}
/**
@@ -170,7 +150,7 @@ function elgg_format_attributes(array $attrs) {
}
// ignore $vars['entity'] => ElggEntity stuff
- if (is_not_null($val) && (is_array($val) || !is_object($val))) {
+ if ($val !== NULL && $val !== false && (is_array($val) || !is_object($val))) {
// allow $vars['class'] => array('one', 'two');
// @todo what about $vars['style']? Needs to be semi-colon separated...
@@ -198,6 +178,7 @@ function elgg_format_attributes(array $attrs) {
* @param array $vars The raw $vars array with all it's dirtiness (config, url, etc.)
*
* @return array The array, ready to be used in elgg_format_attributes().
+ * @access private
*/
function elgg_clean_vars(array $vars = array()) {
unset($vars['config']);
@@ -215,6 +196,14 @@ function elgg_clean_vars(array $vars = array()) {
unset($vars['internalid']);
}
+ if (isset($vars['__ignoreInternalid'])) {
+ unset($vars['__ignoreInternalid']);
+ }
+
+ if (isset($vars['__ignoreInternalname'])) {
+ unset($vars['__ignoreInternalname']);
+ }
+
return $vars;
}
@@ -225,7 +214,7 @@ function elgg_clean_vars(array $vars = array()) {
*
* @example
* elgg_normalize_url(''); // 'http://my.site.com/'
- * elgg_normalize_url('dashboard'); // 'http://my.site.com/dashboard'
+ * elgg_normalize_url('dashboard'); // 'http://my.site.com/dashboard'
* elgg_normalize_url('http://google.com/'); // no change
* elgg_normalize_url('//google.com/'); // no change
*
@@ -234,13 +223,36 @@ function elgg_clean_vars(array $vars = array()) {
* @return string The absolute url
*/
function elgg_normalize_url($url) {
- // 'http://example.com', 'https://example.com', '//example.com'
- // '#target', '?query=string'
- if (preg_match("#^(\#|\?|(https?:)?//)#i", $url)) {
+ // see https://bugs.php.net/bug.php?id=51192
+ // from the bookmarks save action.
+ $php_5_2_13_and_below = version_compare(PHP_VERSION, '5.2.14', '<');
+ $php_5_3_0_to_5_3_2 = version_compare(PHP_VERSION, '5.3.0', '>=') &&
+ version_compare(PHP_VERSION, '5.3.3', '<');
+
+ if ($php_5_2_13_and_below || $php_5_3_0_to_5_3_2) {
+ $tmp_address = str_replace("-", "", $url);
+ $validated = filter_var($tmp_address, FILTER_VALIDATE_URL);
+ } else {
+ $validated = filter_var($url, FILTER_VALIDATE_URL);
+ }
+
+ // work around for handling absoluate IRIs (RFC 3987) - see #4190
+ if (!$validated && (strpos($url, 'http:') === 0) || (strpos($url, 'https:') === 0)) {
+ $validated = true;
+ }
+
+ if ($validated) {
+ // all normal URLs including mailto:
return $url;
- } elseif (stripos($url, 'javascript:') === 0) {
- // 'javascript:'
+ } elseif (preg_match("#^(\#|\?|//)#i", $url)) {
+ // '//example.com' (Shortcut for protocol.)
+ // '?query=test', #target
+ return $url;
+
+ } elseif (stripos($url, 'javascript:') === 0 || stripos($url, 'mailto:') === 0) {
+ // 'javascript:' and 'mailto:'
+ // Not covered in FILTER_VALIDATE_URL
return $url;
} elseif (preg_match("#^[^/]*\.php(\?.*)?$#i", $url)) {
@@ -277,12 +289,11 @@ function elgg_get_friendly_title($title) {
return $result;
}
- //$title = iconv('UTF-8', 'ASCII//TRANSLIT', $title);
- $title = preg_replace("/[^\w ]/", "", $title);
- $title = str_replace(" ", "-", $title);
- $title = str_replace("--", "-", $title);
- $title = trim($title);
- $title = strtolower($title);
+ // titles are often stored HTML encoded
+ $title = html_entity_decode($title, ENT_QUOTES, 'UTF-8');
+
+ $title = ElggTranslit::urlize($title);
+
return $title;
}
@@ -352,7 +363,7 @@ function elgg_get_friendly_time($time) {
/**
* Strip tags and offer plugins the chance.
* Plugins register for output:strip_tags plugin hook.
- * Original string included in $params['original_string']
+ * Original string included in $params['original_string']
*
* @param string $string Formatted string
*
@@ -366,3 +377,93 @@ function elgg_strip_tags($string) {
return $string;
}
+
+/**
+ * Apply html_entity_decode() to a string while re-entitising HTML
+ * special char entities to prevent them from being decoded back to their
+ * unsafe original forms.
+ *
+ * This relies on html_entity_decode() not translating entities when
+ * doing so leaves behind another entity, e.g. &amp;gt; if decoded would
+ * create &gt; which is another entity itself. This seems to escape the
+ * usual behaviour where any two paired entities creating a HTML tag are
+ * usually decoded, i.e. a lone &gt; is not decoded, but &lt;foo&gt; would
+ * be decoded to <foo> since it creates a full tag.
+ *
+ * Note: This function is poorly explained in the manual - which is really
+ * bad given its potential for misuse on user input already escaped elsewhere.
+ * Stackoverflow is littered with advice to use this function in the precise
+ * way that would lead to user input being capable of injecting arbitrary HTML.
+ *
+ * @param string $string
+ *
+ * @return string
+ *
+ * @author Pádraic Brady
+ * @copyright Copyright (c) 2010 Pádraic Brady (http://blog.astrumfutura.com)
+ * @license Released under dual-license GPL2/MIT by explicit permission of Pádraic Brady
+ *
+ * @access private
+ */
+function _elgg_html_decode($string) {
+ $string = str_replace(
+ array('&gt;', '&lt;', '&amp;', '&quot;', '&#039;'),
+ array('&amp;gt;', '&amp;lt;', '&amp;amp;', '&amp;quot;', '&amp;#039;'),
+ $string
+ );
+ $string = html_entity_decode($string, ENT_NOQUOTES, 'UTF-8');
+ $string = str_replace(
+ array('&amp;gt;', '&amp;lt;', '&amp;amp;', '&amp;quot;', '&amp;#039;'),
+ array('&gt;', '&lt;', '&amp;', '&quot;', '&#039;'),
+ $string
+ );
+ return $string;
+}
+
+/**
+ * Prepares query string for output to prevent CSRF attacks.
+ *
+ * @param string $string
+ * @return string
+ *
+ * @access private
+ */
+function _elgg_get_display_query($string) {
+ //encode <,>,&, quotes and characters above 127
+ if (function_exists('mb_convert_encoding')) {
+ $display_query = mb_convert_encoding($string, 'HTML-ENTITIES', 'UTF-8');
+ } else {
+ // if no mbstring extension, we just strip characters
+ $display_query = preg_replace("/[^\x01-\x7F]/", "", $string);
+ }
+ return htmlspecialchars($display_query, ENT_QUOTES, 'UTF-8', false);
+}
+
+/**
+ * Unit tests for Output
+ *
+ * @param string $hook unit_test
+ * @param string $type system
+ * @param mixed $value Array of tests
+ * @param mixed $params Params
+ *
+ * @return array
+ * @access private
+ */
+function output_unit_test($hook, $type, $value, $params) {
+ global $CONFIG;
+ $value[] = $CONFIG->path . 'engine/tests/api/output.php';
+ return $value;
+}
+
+/**
+ * Initialise the Output subsystem.
+ *
+ * @return void
+ * @access private
+ */
+function output_init() {
+ elgg_register_plugin_hook_handler('unit_test', 'system', 'output_unit_test');
+}
+
+elgg_register_event_handler('init', 'system', 'output_init');
diff --git a/engine/lib/pagehandler.php b/engine/lib/pagehandler.php
index e598d6821..0cf99b6fe 100644
--- a/engine/lib/pagehandler.php
+++ b/engine/lib/pagehandler.php
@@ -7,14 +7,17 @@
*/
/**
- * Turns the current page over to the page handler, allowing registered handlers to take over.
+ * Routes the request to a registered page handler
*
- * If a page handler returns FALSE, the request is handed over to the default_page_handler.
+ * This function sets the context based on the handler name (first segment of the
+ * URL). It also triggers a plugin hook 'route', $handler so that plugins can
+ * modify the routing or handle a request.
*
* @param string $handler The name of the handler type (eg 'blog')
* @param array $page The parameters to the page, as an array (exploded by '/' slashes)
*
- * @return true|false Depending on whether a registered page handler was found
+ * @return bool
+ * @access private
*/
function page_handler($handler, $page) {
global $CONFIG;
@@ -27,26 +30,30 @@ function page_handler($handler, $page) {
array_pop($page);
}
- if (!isset($CONFIG->pagehandler) || empty($handler)) {
- $result = false;
- } else if (isset($CONFIG->pagehandler[$handler]) && is_callable($CONFIG->pagehandler[$handler])) {
- $function = $CONFIG->pagehandler[$handler];
- $result = call_user_func($function, $page, $handler);
- if ($result !== false) {
- $result = true;
- }
- } else {
- $result = false;
+ // return false to stop processing the request (because you handled it)
+ // return a new $request array if you want to route the request differently
+ $request = array(
+ 'handler' => $handler,
+ 'segments' => $page,
+ );
+ $request = elgg_trigger_plugin_hook('route', $handler, null, $request);
+ if ($request === false) {
+ return true;
}
- if (!$result) {
- $result = default_page_handler($page, $handler);
- }
- if ($result !== false) {
- $result = true;
+ $handler = $request['handler'];
+ $page = $request['segments'];
+
+ $result = false;
+ if (isset($CONFIG->pagehandler)
+ && !empty($handler)
+ && isset($CONFIG->pagehandler[$handler])
+ && is_callable($CONFIG->pagehandler[$handler])) {
+ $function = $CONFIG->pagehandler[$handler];
+ $result = call_user_func($function, $page, $handler);
}
- return $result;
+ return $result || headers_sent();
}
/**
@@ -59,25 +66,28 @@ function page_handler($handler, $page) {
* For example, the URL http://yoururl/blog/username/friends/ would result in the call:
* blog_page_handler(array('username','friends'), blog);
*
- * Page handler functions should return true or the default page handler will be called.
- *
* A request to register a page handler with the same identifier as previously registered
* handler will replace the previous one.
*
* The context is set to the page handler identifier before the registered
* page handler function is called. For the above example, the context is set to 'blog'.
*
+ * Page handlers should return true to indicate that they handled the request.
+ * Requests not handled are forwarded to the front page with a reason of 404.
+ * Plugins can register for the 'forward', '404' plugin hook. @see forward()
+ *
* @param string $handler The page type to handle
* @param string $function Your function name
*
- * @return true|false Depending on success
+ * @return bool Depending on success
*/
function elgg_register_page_handler($handler, $function) {
global $CONFIG;
+
if (!isset($CONFIG->pagehandler)) {
$CONFIG->pagehandler = array();
}
- if (is_callable($function)) {
+ if (is_callable($function, true)) {
$CONFIG->pagehandler[$handler] = $function;
return true;
}
@@ -106,35 +116,35 @@ function elgg_unregister_page_handler($handler) {
}
/**
- * A default page handler
- * Tries to locate a suitable file to include. Only works for core pages, not plugins.
+ * Serve an error page
*
- * @param array $page The page URL elements
- * @param string $handler The base handler
+ * @todo not sending status codes yet
*
- * @return true|false Depending on success
+ * @param string $hook The name of the hook
+ * @param string $type The type of the hook
+ * @param bool $result The current value of the hook
+ * @param array $params Parameters related to the hook
+ * @return void
*/
-function default_page_handler($page, $handler) {
- global $CONFIG;
-
- $page = implode('/', $page);
-
- // protect against including arbitary files
- $page = str_replace("..", "", $page);
-
- $callpath = $CONFIG->path . $handler . "/" . $page;
- if (is_dir($callpath)) {
- $callpath = sanitise_filepath($callpath);
- $callpath .= "index.php";
- if (file_exists($callpath)) {
- if (include($callpath)) {
- return TRUE;
- }
- }
- } else if (file_exists($callpath)) {
- include($callpath);
- return TRUE;
+function elgg_error_page_handler($hook, $type, $result, $params) {
+ if (elgg_view_exists("errors/$type")) {
+ $content = elgg_view("errors/$type", $params);
+ } else {
+ $content = elgg_view("errors/default", $params);
}
+ $body = elgg_view_layout('error', array('content' => $content));
+ echo elgg_view_page('', $body, 'error');
+ exit;
+}
- return FALSE;
+/**
+ * Initializes the page handler/routing system
+ *
+ * @return void
+ * @access private
+ */
+function page_handler_init() {
+ elgg_register_plugin_hook_handler('forward', '404', 'elgg_error_page_handler');
}
+
+elgg_register_event_handler('init', 'system', 'page_handler_init');
diff --git a/engine/lib/pageowner.php b/engine/lib/pageowner.php
index 504d34a4e..bd63d08c6 100644
--- a/engine/lib/pageowner.php
+++ b/engine/lib/pageowner.php
@@ -29,7 +29,9 @@ function elgg_get_page_owner_guid($guid = 0) {
// return guid of page owner entity
$guid = elgg_trigger_plugin_hook('page_owner', 'system', NULL, 0);
- $page_owner_guid = $guid;
+ if ($guid) {
+ $page_owner_guid = $guid;
+ }
return $guid;
}
@@ -37,24 +39,30 @@ function elgg_get_page_owner_guid($guid = 0) {
/**
* Gets the owner entity for the current page.
*
- * @return ElggEntity|false The current page owner or false if none.
+ * @note Access is disabled when getting the page owner entity.
+ *
+ * @return ElggUser|ElggGroup|false The current page owner or false if none.
*
* @since 1.8.0
*/
function elgg_get_page_owner_entity() {
$guid = elgg_get_page_owner_guid();
if ($guid > 0) {
- return get_entity($guid);
+ $ia = elgg_set_ignore_access(true);
+ $owner = get_entity($guid);
+ elgg_set_ignore_access($ia);
+
+ return $owner;
}
- return FALSE;
+ return false;
}
/**
* Set the guid of the entity that owns this page
*
* @param int $guid The guid of the page owner
- *
+ * @return void
* @since 1.8.0
*/
function elgg_set_page_owner_guid($guid) {
@@ -75,6 +83,8 @@ function elgg_set_page_owner_guid($guid) {
* <handler>/edit/<entity guid>
* <handler>/group/<group guid>
*
+ * @note Access is disabled while finding the page owner for the group gatekeeper functions.
+ *
*
* @param string $hook 'page_owner'
* @param string $entity_type 'system'
@@ -82,6 +92,7 @@ function elgg_set_page_owner_guid($guid) {
* @param array $params no parameters
*
* @return int GUID
+ * @access private
*/
function default_page_owner_handler($hook, $entity_type, $returnvalue, $params) {
@@ -89,6 +100,8 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params)
return $returnvalue;
}
+ $ia = elgg_set_ignore_access(true);
+
$username = get_input("username");
if ($username) {
// @todo using a username of group:<guid> is deprecated
@@ -96,11 +109,13 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params)
preg_match('/group\:([0-9]+)/i', $username, $matches);
$guid = $matches[1];
if ($entity = get_entity($guid)) {
+ elgg_set_ignore_access($ia);
return $entity->getGUID();
}
}
if ($user = get_user_by_username($username)) {
+ elgg_set_ignore_access($ia);
return $user->getGUID();
}
}
@@ -108,6 +123,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params)
$owner = get_input("owner_guid");
if ($owner) {
if ($user = get_entity($owner)) {
+ elgg_set_ignore_access($ia);
return $user->getGUID();
}
}
@@ -129,6 +145,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params)
case 'friends':
$user = get_user_by_username($segments[2]);
if ($user) {
+ elgg_set_ignore_access($ia);
return $user->getGUID();
}
break;
@@ -136,6 +153,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params)
case 'edit':
$entity = get_entity($segments[2]);
if ($entity) {
+ elgg_set_ignore_access($ia);
return $entity->getContainerGUID();
}
break;
@@ -143,6 +161,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params)
case 'group':
$entity = get_entity($segments[2]);
if ($entity) {
+ elgg_set_ignore_access($ia);
return $entity->getGUID();
}
break;
@@ -150,7 +169,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params)
}
}
- return $returnvalue;
+ elgg_set_ignore_access($ia);
}
/**
@@ -172,7 +191,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params)
* @warning The context is not available until the page_handler runs (after
* the 'init, system' event processing has completed).
*
- * @param string $context The context of the page
+ * @param string $context The context of the page
* @return bool
* @since 1.8.0
*/
@@ -215,6 +234,7 @@ function elgg_get_context() {
* Push a context onto the top of the stack
*
* @param string $context The context string to add to the context stack
+ * @return void
* @since 1.8.0
*/
function elgg_push_context($context) {
@@ -243,7 +263,7 @@ function elgg_pop_context() {
* itself differently based on being on the dashboard or profile pages, it
* can check the stack.
*
- * @param string $context The context string to check for
+ * @param string $context The context string to check for
* @return bool
* @since 1.8.0
*/
@@ -259,14 +279,15 @@ function elgg_in_context($context) {
* @note This is on the 'boot, system' event so that the context is set up quickly.
*
* @return void
+ * @access private
*/
function page_owner_boot() {
- global $CONFIG;
elgg_register_plugin_hook_handler('page_owner', 'system', 'default_page_owner_handler');
- $CONFIG->context = array();
- // @todo Ew... hacky
+ // Bootstrap the context stack by setting its first entry to the handler.
+ // This is the first segment of the URL and the handler is set by the rewrite rules.
+ // @todo this does not work for actions
$handler = get_input('handler', FALSE);
if ($handler) {
elgg_set_context($handler);
diff --git a/engine/lib/pam.php b/engine/lib/pam.php
index e335b7e52..1c9c3bfe1 100644
--- a/engine/lib/pam.php
+++ b/engine/lib/pam.php
@@ -30,7 +30,9 @@ $_PAM_HANDLERS = array();
* failure, return false or throw an exception. Returning nothing indicates that
* the handler wants to be skipped.
*
- * @param string $handler The handler function in the format
+ * Note, $handler must be string callback (not an array/Closure).
+ *
+ * @param string $handler Callable global handler function in the format ()
* pam_handler($credentials = NULL);
* @param string $importance The importance - "sufficient" (default) or "required"
* @param string $policy The policy type, default is "user"
@@ -45,7 +47,8 @@ function register_pam_handler($handler, $importance = "sufficient", $policy = "u
$_PAM_HANDLERS[$policy] = array();
}
- if (is_callable($handler)) {
+ // @todo remove requirement that $handle be a global function
+ if (is_string($handler) && is_callable($handler, true)) {
$_PAM_HANDLERS[$policy][$handler] = new stdClass;
$_PAM_HANDLERS[$policy][$handler]->handler = $handler;
@@ -71,4 +74,3 @@ function unregister_pam_handler($handler, $policy = "user") {
unset($_PAM_HANDLERS[$policy][$handler]);
}
-
diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php
index 3a144abc5..d5d3db466 100644
--- a/engine/lib/plugins.php
+++ b/engine/lib/plugins.php
@@ -54,13 +54,15 @@ define('ELGG_PLUGIN_INTERNAL_PREFIX', 'elgg:internal:');
* @param string $dir A dir to scan for plugins. Defaults to config's plugins_path.
*
* @return array
+ * @since 1.8.0
+ * @access private
*/
function elgg_get_plugin_ids_in_dir($dir = null) {
if (!$dir) {
$dir = elgg_get_plugins_path();
}
- $plugin_idss = array();
+ $plugin_ids = array();
$handle = opendir($dir);
if ($handle) {
@@ -85,14 +87,21 @@ function elgg_get_plugin_ids_in_dir($dir = null) {
*
* @todo Crappy name?
* @return bool
+ * @since 1.8.0
+ * @access private
*/
function elgg_generate_plugin_entities() {
+ // @todo $site unused, can remove?
$site = get_config('site');
+
$dir = elgg_get_plugins_path();
+ $db_prefix = elgg_get_config('dbprefix');
$options = array(
'type' => 'object',
'subtype' => 'plugin',
+ 'selects' => array('plugin_oe.*'),
+ 'joins' => array("JOIN {$db_prefix}objects_entity plugin_oe on plugin_oe.guid = e.guid"),
'limit' => ELGG_ENTITIES_NO_VALUE
);
@@ -100,6 +109,7 @@ function elgg_generate_plugin_entities() {
$old_access = access_get_show_hidden_status();
access_show_hidden_entities(true);
$known_plugins = elgg_get_entities_from_relationship($options);
+ /* @var ElggPlugin[] $known_plugins */
if (!$known_plugins) {
$known_plugins = array();
@@ -131,7 +141,7 @@ function elgg_generate_plugin_entities() {
$index = $id_map[$plugin_id];
$plugin = $known_plugins[$index];
// was this plugin deleted and its entity disabled?
- if ($plugin->enabled != 'yes') {
+ if (!$plugin->isEnabled()) {
$plugin->enable();
$plugin->deactivate();
$plugin->setPriority('last');
@@ -169,12 +179,31 @@ function elgg_generate_plugin_entities() {
}
/**
+ * Cache a reference to this plugin by its ID
+ *
+ * @param ElggPlugin $plugin
+ *
+ * @access private
+ */
+function _elgg_cache_plugin_by_id(ElggPlugin $plugin) {
+ $map = (array) elgg_get_config('plugins_by_id_map');
+ $map[$plugin->getID()] = $plugin;
+ elgg_set_config('plugins_by_id_map', $map);
+}
+
+/**
* Returns an ElggPlugin object with the path $path.
*
* @param string $plugin_id The id (dir name) of the plugin. NOT the guid.
- * @return mixed ElggPlugin or false.
+ * @return ElggPlugin|false
+ * @since 1.8.0
*/
function elgg_get_plugin_from_id($plugin_id) {
+ $map = (array) elgg_get_config('plugins_by_id_map');
+ if (isset($map[$plugin_id])) {
+ return $map[$plugin_id];
+ }
+
$plugin_id = sanitize_string($plugin_id);
$db_prefix = get_config('dbprefix');
@@ -182,6 +211,7 @@ function elgg_get_plugin_from_id($plugin_id) {
'type' => 'object',
'subtype' => 'plugin',
'joins' => array("JOIN {$db_prefix}objects_entity oe on oe.guid = e.guid"),
+ 'selects' => array("oe.title", "oe.description"),
'wheres' => array("oe.title = '$plugin_id'"),
'limit' => 1
);
@@ -203,6 +233,7 @@ function elgg_get_plugin_from_id($plugin_id) {
* {@link elgg_generate_plugin_objects()} first.
*
* @param string $id The plugin ID.
+ * @since 1.8.0
* @return bool
*/
function elgg_plugin_exists($id) {
@@ -215,6 +246,8 @@ function elgg_plugin_exists($id) {
* Returns the highest priority of the plugins
*
* @return int
+ * @since 1.8.0
+ * @access private
*/
function elgg_get_max_plugin_priority() {
$db_prefix = get_config('dbprefix');
@@ -230,6 +263,8 @@ function elgg_get_max_plugin_priority() {
$data = get_data($q);
if ($data) {
$max = $data[0]->max;
+ } else {
+ $max = 1;
}
// can't have a priority of 0.
@@ -241,6 +276,7 @@ function elgg_get_max_plugin_priority() {
*
* @param string $plugin_id The plugin ID
* @param int $site_guid The site guid
+ * @since 1.8.0
* @return bool
*/
function elgg_is_active_plugin($plugin_id, $site_guid = null) {
@@ -266,20 +302,20 @@ function elgg_is_active_plugin($plugin_id, $site_guid = null) {
/**
* Loads all active plugins in the order specified in the tool admin panel.
*
- * @note This is called on every page load and includes additional checking that plugins
- * are fit to be loaded. If a plugin is active and problematic, it will be disabled
- * and a visible error emitted.
+ * @note This is called on every page load. If a plugin is active and problematic, it
+ * will be disabled and a visible error emitted. This does not check the deps system because
+ * that was too slow.
*
* @return bool
+ * @since 1.8.0
+ * @access private
*/
function elgg_load_plugins() {
- global $CONFIG;
-
$plugins_path = elgg_get_plugins_path();
- $start_flags = ELGG_PLUGIN_INCLUDE_START
- | ELGG_PLUGIN_REGISTER_VIEWS
- | ELGG_PLUGIN_REGISTER_LANGUAGES
- | ELGG_PLUGIN_REGISTER_CLASSES;
+ $start_flags = ELGG_PLUGIN_INCLUDE_START |
+ ELGG_PLUGIN_REGISTER_VIEWS |
+ ELGG_PLUGIN_REGISTER_LANGUAGES |
+ ELGG_PLUGIN_REGISTER_CLASSES;
if (!$plugins_path) {
return false;
@@ -287,44 +323,31 @@ function elgg_load_plugins() {
// temporary disable all plugins if there is a file called 'disabled' in the plugin dir
if (file_exists("$plugins_path/disabled")) {
+ if (elgg_is_admin_logged_in() && elgg_in_context('admin')) {
+ system_message(elgg_echo('plugins:disabled'));
+ }
return false;
}
- // Load view caches if available
- $cached_view_paths = elgg_filepath_cache_load('views');
- $cached_view_types = elgg_filepath_cache_load('view_types');
- $cached_view_info = is_string($cached_view_paths) && is_string($cached_view_types);
-
- if ($cached_view_info) {
- $CONFIG->views = unserialize($cached_view_paths);
- $CONFIG->view_types = unserialize($cached_view_types);
-
- // don't need to register views
+ if (elgg_get_config('system_cache_loaded')) {
$start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_VIEWS;
}
+ if (elgg_get_config('i18n_loaded_from_cache')) {
+ $start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_LANGUAGES;
+ }
+
$return = true;
$plugins = elgg_get_plugins('active');
if ($plugins) {
foreach ($plugins as $plugin) {
- // check if plugin can be started and try to start it.
- // if anything is bad, disable it and emit a message.
- if (!$plugin->isValid()) {
- $plugin->deactivate();
- $msg = elgg_echo('PluginException:MisconfiguredPlugin', array($plugin->getID(), $plugin->guid));
- register_error($msg);
- $return = false;
-
- continue;
- }
-
try {
$plugin->start($start_flags);
} catch (Exception $e) {
$plugin->deactivate();
$msg = elgg_echo('PluginException:CannotStart',
array($plugin->getID(), $plugin->guid, $e->getMessage()));
- register_error($msg);
+ elgg_add_admin_notice('cannot_start' . $plugin->getID(), $msg);
$return = false;
continue;
@@ -332,12 +355,6 @@ function elgg_load_plugins() {
}
}
- // Cache results
- if (!$cached_view_info) {
- elgg_filepath_cache_save('views', serialize($CONFIG->views));
- elgg_filepath_cache_save('view_types', serialize($CONFIG->view_types));
- }
-
return $return;
}
@@ -345,11 +362,12 @@ function elgg_load_plugins() {
* Returns an ordered list of plugins
*
* @param string $status The status of the plugins. active, inactive, or all.
- * @param bool $include_bad Include physically deleted and invalid plugins?
* @param mixed $site_guid Optional site guid
- * @return array
+ * @return ElggPlugin[]
+ * @since 1.8.0
+ * @access private
*/
-function elgg_get_plugins($status = 'active', $include_bad = false, $site_guid = NULL) {
+function elgg_get_plugins($status = 'active', $site_guid = null) {
$db_prefix = get_config('dbprefix');
$priority = elgg_namespace_plugin_private_setting('internal', 'priority');
@@ -363,7 +381,11 @@ function elgg_get_plugins($status = 'active', $include_bad = false, $site_guid =
'type' => 'object',
'subtype' => 'plugin',
'limit' => ELGG_ENTITIES_NO_VALUE,
- 'joins' => array("JOIN {$db_prefix}private_settings ps on ps.entity_guid = e.guid"),
+ 'selects' => array('plugin_oe.*'),
+ 'joins' => array(
+ "JOIN {$db_prefix}private_settings ps on ps.entity_guid = e.guid",
+ "JOIN {$db_prefix}objects_entity plugin_oe on plugin_oe.guid = e.guid"
+ ),
'wheres' => array("ps.name = '$priority'"),
'order_by' => "CAST(ps.value as unsigned), e.guid"
);
@@ -388,22 +410,9 @@ function elgg_get_plugins($status = 'active', $include_bad = false, $site_guid =
break;
}
- if ($include_bad) {
- $old_ia = elgg_set_ignore_access(true);
- }
-
+ $old_ia = elgg_set_ignore_access(true);
$plugins = elgg_get_entities_from_relationship($options);
-
- if ($include_bad) {
- elgg_set_ignore_access($old_ia);
- } else {
- // remove bad plugins
- foreach ($plugins as $i => $plugin) {
- if (!$plugin->isValid()) {
- unset ($plugins[$i]);
- }
- }
- }
+ elgg_set_ignore_access($old_ia);
return $plugins;
}
@@ -418,11 +427,13 @@ function elgg_get_plugins($status = 'active', $include_bad = false, $site_guid =
*
* @param array $order An array of plugin ids in the order to set them
* @return bool
+ * @since 1.8.0
+ * @access private
*/
function elgg_set_plugin_priorities(array $order) {
$name = elgg_namespace_plugin_private_setting('internal', 'priority');
- $plugins = elgg_get_plugins('any', true);
+ $plugins = elgg_get_plugins('any');
if (!$plugins) {
return false;
}
@@ -433,6 +444,7 @@ function elgg_set_plugin_priorities(array $order) {
// though we do start with 1
$order = array_values($order);
+ $missing_plugins = array();
foreach ($plugins as $plugin) {
$plugin_id = $plugin->getID();
@@ -449,9 +461,9 @@ function elgg_set_plugin_priorities(array $order) {
}
}
- // set the missing plugins priorities
+ // set the missing plugins' priorities
if ($return && $missing_plugins) {
- if (!$priority) {
+ if (!isset($priority)) {
$priority = 0;
}
foreach ($missing_plugins as $plugin) {
@@ -471,6 +483,8 @@ function elgg_set_plugin_priorities(array $order) {
*
* @todo Can this be done in a single sql command?
* @return bool
+ * @since 1.8.0
+ * @access private
*/
function elgg_reindex_plugin_priorities() {
return elgg_set_plugin_priorities(array());
@@ -483,12 +497,15 @@ function elgg_reindex_plugin_priorities() {
* @param string $name The name to namespace.
* @param string $id The plugin's ID to namespace with. Required for user_setting.
* @return string
+ * @since 1.8.0
+ * @access private
*/
function elgg_namespace_plugin_private_setting($type, $name, $id = null) {
switch ($type) {
-// case 'setting':
-// $name = ELGG_PLUGIN_SETTING_PREFIX . $name;
-// break;
+ // commented out because it breaks $plugin->$name access to variables
+ //case 'setting':
+ // $name = ELGG_PLUGIN_SETTING_PREFIX . $name;
+ // break;
case 'user_setting':
if (!$id) {
@@ -515,9 +532,11 @@ function elgg_namespace_plugin_private_setting($type, $name, $id = null) {
* context from the main script filename called by
* the browser. Default = false.
*
- * @since 1.8
- *
* @return string|false Plugin name, or false if no plugin name was called
+ * @since 1.8.0
+ * @access private
+ *
+ * @todo get rid of this
*/
function elgg_get_calling_plugin_id($mainfilename = false) {
if (!$mainfilename) {
@@ -563,7 +582,8 @@ function elgg_get_calling_plugin_id($mainfilename = false) {
* @param string $name A specific provided name to return. Requires $provide_type.
*
* @return array
- * @since 1.8
+ * @since 1.8.0
+ * @access private
*/
function elgg_get_plugins_provides($type = null, $name = null) {
static $provides = null;
@@ -573,11 +593,16 @@ function elgg_get_plugins_provides($type = null, $name = null) {
$provides = array();
foreach ($active_plugins as $plugin) {
- if ($plugin_provides = $plugin->manifest->getProvides()) {
+ $plugin_provides = array();
+ $manifest = $plugin->getManifest();
+ if ($manifest instanceof ElggPluginManifest) {
+ $plugin_provides = $plugin->getManifest()->getProvides();
+ }
+ if ($plugin_provides) {
foreach ($plugin_provides as $provided) {
$provides[$provided['type']][$provided['name']] = array(
'version' => $provided['version'],
- 'provided_by' => $plugin_id
+ 'provided_by' => $plugin->getID()
);
}
}
@@ -614,22 +639,22 @@ function elgg_get_plugins_provides($type = null, $name = null) {
* 'status' => bool Does the provide exist?,
* 'value' => string The version provided
* )
- * @since 1.8
+ * @since 1.8.0
+ * @access private
*/
function elgg_check_plugins_provides($type, $name, $version = null, $comparison = 'ge') {
- if (!$provided = elgg_get_plugins_provides($type, $name)) {
+ $provided = elgg_get_plugins_provides($type, $name);
+ if (!$provided) {
return array(
'status' => false,
'version' => ''
);
}
- if ($provided) {
- if ($version) {
- $status = version_compare($provided['version'], $version, $comparison);
- } else {
- $status = true;
- }
+ if ($version) {
+ $status = version_compare($provided['version'], $version, $comparison);
+ } else {
+ $status = true;
}
return array(
@@ -650,6 +675,8 @@ function elgg_check_plugins_provides($type, $name, $version = null, $comparison
*
* @param array $dep An ElggPluginPackage dependency array
* @return array
+ * @since 1.8.0
+ * @access private
*/
function elgg_get_plugin_dependency_strings($dep) {
$dep_system = elgg_extract('type', $dep);
@@ -759,7 +786,8 @@ function elgg_get_plugin_dependency_strings($dep) {
* Returns the ElggPlugin entity of the last plugin called.
*
* @return mixed ElggPlugin or false
- * @since 1.8
+ * @since 1.8.0
+ * @access private
*/
function elgg_get_calling_plugin_entity() {
$plugin_id = elgg_get_calling_plugin_id();
@@ -779,8 +807,7 @@ function elgg_get_calling_plugin_entity() {
* @param bool $return_obj Return settings as an object? This can be used to in reusable
* views where the settings are passed as $vars['entity'].
* @return array
- *
- * @since 1.8
+ * @since 1.8.0
*/
function elgg_get_all_plugin_user_settings($user_guid = null, $plugin_id = null, $return_obj = false) {
if ($plugin_id) {
@@ -818,6 +845,7 @@ function elgg_get_all_plugin_user_settings($user_guid = null, $plugin_id = null,
* is detected from where you are calling from.
*
* @return bool
+ * @since 1.8.0
*/
function elgg_set_plugin_user_setting($name, $value, $user_guid = null, $plugin_id = null) {
if ($plugin_id) {
@@ -836,11 +864,12 @@ function elgg_set_plugin_user_setting($name, $value, $user_guid = null, $plugin_
/**
* Unsets a user-specific plugin setting
*
- * @param str $name Name of the plugin setting
- * @param int $user_guid Defaults to logged in user
- * @param str $plugin_id Defaults to contextual plugin name
+ * @param string $name Name of the setting
+ * @param int $user_guid Defaults to logged in user
+ * @param string $plugin_id Defaults to contextual plugin name
*
- * @return bool Success
+ * @return bool
+ * @since 1.8.0
*/
function elgg_unset_plugin_user_setting($name, $user_guid = null, $plugin_id = null) {
if ($plugin_id) {
@@ -859,12 +888,13 @@ function elgg_unset_plugin_user_setting($name, $user_guid = null, $plugin_id = n
/**
* Get a user specific setting for a plugin.
*
- * @param string $name The name.
+ * @param string $name The name of the setting.
* @param int $user_guid Guid of owning user
* @param string $plugin_id Optional plugin name, if not specified
* it is detected from where you are calling.
*
* @return mixed
+ * @since 1.8.0
*/
function elgg_get_plugin_user_setting($name, $user_guid = null, $plugin_id = null) {
if ($plugin_id) {
@@ -883,12 +913,13 @@ function elgg_get_plugin_user_setting($name, $user_guid = null, $plugin_id = nul
/**
* Set a setting for a plugin.
*
- * @param string $name The name - note, can't be "title".
+ * @param string $name The name of the setting - note, can't be "title".
* @param mixed $value The value.
* @param string $plugin_id Optional plugin name, if not specified
* then it is detected from where you are calling from.
*
- * @return int|false
+ * @return bool
+ * @since 1.8.0
*/
function elgg_set_plugin_setting($name, $value, $plugin_id = null) {
if ($plugin_id) {
@@ -907,11 +938,13 @@ function elgg_set_plugin_setting($name, $value, $plugin_id = null) {
/**
* Get setting for a plugin.
*
- * @param string $name The name.
+ * @param string $name The name of the setting.
* @param string $plugin_id Optional plugin name, if not specified
* then it is detected from where you are calling from.
*
* @return mixed
+ * @since 1.8.0
+ * @todo make $plugin_id required in future version
*/
function elgg_get_plugin_setting($name, $plugin_id = null) {
if ($plugin_id) {
@@ -930,11 +963,12 @@ function elgg_get_plugin_setting($name, $plugin_id = null) {
/**
* Unsets a plugin setting.
*
- * @param string $name The name.
+ * @param string $name The name of the setting.
* @param string $plugin_id Optional plugin name, if not specified
* then it is detected from where you are calling from.
*
* @return bool
+ * @since 1.8.0
*/
function elgg_unset_plugin_setting($name, $plugin_id = null) {
if ($plugin_id) {
@@ -957,7 +991,7 @@ function elgg_unset_plugin_setting($name, $plugin_id = null) {
* then it is detected from where you are calling from.
*
* @return bool
- * @since 1.8
+ * @since 1.8.0
*/
function elgg_unset_all_plugin_settings($plugin_id = null) {
if ($plugin_id) {
@@ -998,7 +1032,7 @@ function elgg_unset_all_plugin_settings($plugin_id = null) {
* plugin_user_setting_name_value_pairs_operator => NULL|STR The operator to use for combining
* (name = value) OPERATOR (name = value); default AND
*
- * @return mixed
+ * @return mixed int If count, int. If not count, array. false on errors.
*/
function elgg_get_entities_from_plugin_user_settings(array $options = array()) {
// if they're passing it don't bother
@@ -1046,7 +1080,8 @@ function elgg_get_entities_from_plugin_user_settings(array $options = array()) {
/**
* Register object, plugin entities as ElggPlugin classes
*
- * @return void
+ * @return void
+ * @access private
*/
function plugin_run_once() {
add_subtype("object", "plugin", "ElggPlugin");
@@ -1055,12 +1090,13 @@ function plugin_run_once() {
/**
* Runs unit tests for the entity objects.
*
- * @param sting $hook unit_test
+ * @param string $hook unit_test
* @param string $type system
* @param mixed $value Array of tests
* @param mixed $params Params
*
* @return array
+ * @access private
*/
function plugins_test($hook, $type, $value, $params) {
global $CONFIG;
@@ -1069,15 +1105,63 @@ function plugins_test($hook, $type, $value, $params) {
}
/**
- * Initialise the file modules.
- * Listens to system boot and registers any appropriate file types and classes
+ * Checks on deactivate plugin event if disabling it won't create unmet dependencies and blocks disable in such case.
+ *
+ * @param string $event deactivate
+ * @param string $type plugin
+ * @param array $params Parameters array containing entry with ELggPlugin instance under 'plugin_entity' key
+ * @return bool false to block plugin deactivation action
+ *
+ * @access private
+ */
+function _plugins_deactivate_dependency_check($event, $type, $params) {
+ $plugin_id = $params['plugin_entity']->getManifest()->getPluginID();
+ $plugin_name = $params['plugin_entity']->getManifest()->getName();
+
+ $active_plugins = elgg_get_plugins();
+
+ $dependents = array();
+ foreach ($active_plugins as $plugin) {
+ $manifest = $plugin->getManifest();
+ $requires = $manifest->getRequires();
+
+ foreach ($requires as $required) {
+ if ($required['type'] == 'plugin' && $required['name'] == $plugin_id) {
+ // there are active dependents
+ $dependents[$manifest->getPluginID()] = $plugin;
+ }
+ }
+ }
+
+ if ($dependents) {
+ $list = '<ul>';
+ // construct error message and prevent disabling
+ foreach ($dependents as $dependent) {
+ $list .= '<li>' . $dependent->getManifest()->getName() . '</li>';
+ }
+ $list .= '</ul>';
+
+ register_error(elgg_echo('ElggPlugin:Dependencies:ActiveDependent', array($plugin_name, $list)));
+
+ return false;
+ }
+}
+
+/**
+ * Initialize the plugin system
+ * Listens to system init and registers actions
*
* @return void
+ * @access private
*/
function plugin_init() {
run_function_once("plugin_run_once");
elgg_register_plugin_hook_handler('unit_test', 'system', 'plugins_test');
+
+ // note - plugins are booted by the time this handler is registered
+ // deactivation due to error may have already occurred
+ elgg_register_event_handler('deactivate', 'plugin', '_plugins_deactivate_dependency_check');
elgg_register_action("plugins/settings/save", '', 'admin');
elgg_register_action("plugins/usersettings/save");
@@ -1088,6 +1172,8 @@ function plugin_init() {
elgg_register_action('admin/plugins/deactivate_all', '', 'admin');
elgg_register_action('admin/plugins/set_priority', '', 'admin');
+
+ elgg_register_library('elgg:markdown', elgg_get_root_path() . 'vendors/markdown/markdown.php');
}
elgg_register_event_handler('init', 'system', 'plugin_init');
diff --git a/engine/lib/private_settings.php b/engine/lib/private_settings.php
index e5e7b2213..7541f7b3b 100644
--- a/engine/lib/private_settings.php
+++ b/engine/lib/private_settings.php
@@ -38,7 +38,7 @@
* their own settings.
*
*
- * @return array
+ * @return mixed int If count, int. If not count, array. false on errors.
* @since 1.8.0
*/
function elgg_get_entities_from_private_settings(array $options = array()) {
@@ -95,6 +95,7 @@ function elgg_get_entities_from_private_settings(array $options = array()) {
* @param string $name_prefix A string to prefix all names with
* @return array
* @since 1.8.0
+ * @access private
*/
function elgg_get_entity_private_settings_where_sql($table, $names = NULL, $values = NULL,
$pairs = NULL, $pair_operator = 'AND', $name_prefix = '') {
@@ -239,7 +240,7 @@ $pairs = NULL, $pair_operator = 'AND', $name_prefix = '') {
$i++;
}
- $where = implode (" $pair_operator ", $pair_wheres);
+ $where = implode(" $pair_operator ", $pair_wheres);
if ($where) {
$wheres[] = "($where)";
}
@@ -334,7 +335,7 @@ function get_all_private_settings($entity_guid) {
* @param string $name The name of the setting
* @param string $value The value of the setting
*
- * @return mixed The setting ID, or false on failure
+ * @return bool
* @see get_private_setting()
* @see get_all_private_settings()
* @see remove_private_setting()
@@ -348,19 +349,12 @@ function set_private_setting($entity_guid, $name, $value) {
$name = sanitise_string($name);
$value = sanitise_string($value);
- $entity = get_entity($entity_guid);
- if (!$entity instanceof ElggEntity) {
- return false;
- }
-
$result = insert_data("INSERT into {$CONFIG->dbprefix}private_settings
(entity_guid, name, value) VALUES
($entity_guid, '$name', '$value')
ON DUPLICATE KEY UPDATE value='$value'");
- if ($result === 0) {
- return true;
- }
- return $result;
+
+ return $result !== false;
}
/**
@@ -369,7 +363,7 @@ function set_private_setting($entity_guid, $name, $value) {
* @param int $entity_guid The Entity GUID
* @param string $name The name of the setting
*
- * @return true|false depending on success
+ * @return bool
* @see get_private_setting()
* @see get_all_private_settings()
* @see set_private_setting()
@@ -389,8 +383,8 @@ function remove_private_setting($entity_guid, $name) {
$name = sanitise_string($name);
return delete_data("DELETE from {$CONFIG->dbprefix}private_settings
- where name = '{$name}'
- and entity_guid = {$entity_guid}");
+ WHERE name = '{$name}'
+ AND entity_guid = {$entity_guid}");
}
/**
@@ -398,7 +392,7 @@ function remove_private_setting($entity_guid, $name) {
*
* @param int $entity_guid The Entity GUID
*
- * @return true|false depending on success
+ * @return bool
* @see get_private_setting()
* @see get_all_private_settings()
* @see set_private_setting()
@@ -416,5 +410,5 @@ function remove_all_private_settings($entity_guid) {
}
return delete_data("DELETE from {$CONFIG->dbprefix}private_settings
- where entity_guid = {$entity_guid}");
+ WHERE entity_guid = {$entity_guid}");
}
diff --git a/engine/lib/relationships.php b/engine/lib/relationships.php
index 5224efaf1..b0cd627fc 100644
--- a/engine/lib/relationships.php
+++ b/engine/lib/relationships.php
@@ -12,7 +12,8 @@
*
* @param stdClass $row Database row from the relationship table
*
- * @return stdClass or ElggMetadata
+ * @return ElggRelationship|stdClass
+ * @access private
*/
function row_to_elggrelationship($row) {
if (!($row instanceof stdClass)) {
@@ -27,7 +28,7 @@ function row_to_elggrelationship($row) {
*
* @param int $id The ID of a relationship
*
- * @return mixed
+ * @return ElggRelationship|false
*/
function get_relationship($id) {
global $CONFIG;
@@ -108,7 +109,7 @@ function add_entity_relationship($guid_one, $relationship, $guid_two) {
* @param string $relationship The type of relationship
* @param int $guid_two The GUID of the entity the relationship is with
*
- * @return object|false Depending on success
+ * @return ElggRelationship|false Depending on success
*/
function check_entity_relationship($guid_one, $relationship, $guid_two) {
global $CONFIG;
@@ -122,7 +123,7 @@ function check_entity_relationship($guid_one, $relationship, $guid_two) {
AND relationship='$relationship'
AND guid_two=$guid_two limit 1";
- $row = $row = get_data_row($query);
+ $row = row_to_elggrelationship(get_data_row($query));
if ($row) {
return $row;
}
@@ -157,7 +158,7 @@ function remove_entity_relationship($guid_one, $relationship, $guid_two) {
and relationship='$relationship'
and guid_two=$guid_two";
- return delete_data($query);
+ return (bool)delete_data($query);
} else {
return false;
}
@@ -219,7 +220,7 @@ function remove_entity_relationships($guid_one, $relationship = "", $inverse = f
* @param int $guid The GUID of the relationship owner
* @param bool $inverse_relationship Inverse relationship owners?
*
- * @return mixed
+ * @return ElggRelationship[]
*/
function get_entity_relationships($guid, $inverse_relationship = FALSE) {
global $CONFIG;
@@ -235,6 +236,20 @@ function get_entity_relationships($guid, $inverse_relationship = FALSE) {
/**
* Return entities matching a given query joining against a relationship.
+ * Also accepts all options available to elgg_get_entities() and
+ * elgg_get_entities_from_metadata().
+ *
+ * To ask for entities that do not have a particulat relationship to an entity,
+ * use a custom where clause like the following:
+ *
+ * $options['wheres'][] = "NOT EXISTS (
+ * SELECT 1 FROM {$db_prefix}entity_relationships
+ * WHERE guid_one = e.guid
+ * AND relationship = '$relationship'
+ * )";
+ *
+ * @see elgg_get_entities
+ * @see elgg_get_entities_from_metadata
*
* @param array $options Array in format:
*
@@ -244,7 +259,7 @@ function get_entity_relationships($guid, $inverse_relationship = FALSE) {
*
* inverse_relationship => BOOL Inverse the relationship
*
- * @return array
+ * @return ElggEntity[]|mixed If count, int. If not count, array. false on errors.
* @since 1.7.0
*/
function elgg_get_entities_from_relationship($options) {
@@ -284,7 +299,7 @@ function elgg_get_entities_from_relationship($options) {
$options['selects'] = array();
}
- $select = array('r.*');
+ $select = array('r.id');
$options['selects'] = array_merge($options['selects'], $select);
}
@@ -301,10 +316,11 @@ function elgg_get_entities_from_relationship($options) {
* Provide in table.column format.
* @param string $relationship Relationship string
* @param int $relationship_guid Entity guid to check
- * @param string $inverse_relationship Inverse relationship check?
+ * @param bool $inverse_relationship Inverse relationship check?
*
* @return mixed
* @since 1.7.0
+ * @access private
*/
function elgg_get_entity_relationship_where_sql($column, $relationship = NULL,
$relationship_guid = NULL, $inverse_relationship = FALSE) {
@@ -347,7 +363,7 @@ $relationship_guid = NULL, $inverse_relationship = FALSE) {
/**
* Returns a viewable list of entities by relationship
*
- * @param array $options
+ * @param array $options Options array for retrieval of entities
*
* @see elgg_list_entities()
* @see elgg_get_entities_from_relationship()
@@ -365,7 +381,7 @@ function elgg_list_entities_from_relationship(array $options = array()) {
*
* @param array $options An options array compatible with
* elgg_get_entities_from_relationship()
- * @return array
+ * @return ElggEntity[]|mixed int If count, int. If not count, array. false on errors.
* @since 1.8.0
*/
function elgg_get_entities_from_relationship_count(array $options = array()) {
@@ -382,7 +398,7 @@ function elgg_get_entities_from_relationship_count(array $options = array()) {
*
* @param array $options Options array
*
- * @return array
+ * @return string
* @since 1.8.0
*/
function elgg_list_entities_from_relationship_count($options) {
@@ -392,15 +408,15 @@ function elgg_list_entities_from_relationship_count($options) {
/**
* Sets the URL handler for a particular relationship type
*
- * @param string $function_name The function to register
* @param string $relationship_type The relationship type.
+ * @param string $function_name The function to register
*
* @return bool Depending on success
*/
function elgg_register_relationship_url_handler($relationship_type, $function_name) {
global $CONFIG;
- if (!is_callable($function_name)) {
+ if (!is_callable($function_name, true)) {
return false;
}
@@ -467,7 +483,8 @@ function get_relationship_url($id) {
* @param int $guid_two This is the object trying to attach to $guid_one
*
* @return bool
- **/
+ * @access private
+ */
function already_attached($guid_one, $guid_two) {
if ($attached = check_entity_relationship($guid_one, "attached", $guid_two)) {
return true;
@@ -482,14 +499,15 @@ function already_attached($guid_one, $guid_two) {
* @param int $guid Entity GUID
* @param string $type The type of object to return e.g. 'file', 'friend_of' etc
*
- * @return an array of objects
-**/
+ * @return ElggEntity[]
+ * @access private
+ */
function get_attachments($guid, $type = "") {
$options = array(
'relationship' => 'attached',
'relationship_guid' => $guid,
'inverse_relationship' => false,
- 'types' => $type,
+ 'type' => $type,
'subtypes' => '',
'owner_guid' => 0,
'order_by' => 'time_created desc',
@@ -509,7 +527,8 @@ function get_attachments($guid, $type = "") {
* @param int $guid_two This is the object to remove from $guid_one
*
* @return void
-**/
+ * @access private
+ */
function remove_attachment($guid_one, $guid_two) {
if (already_attached($guid_one, $guid_two)) {
remove_entity_relationship($guid_one, "attached", $guid_two);
@@ -523,7 +542,8 @@ function remove_attachment($guid_one, $guid_two) {
* @param int $guid_two This is the object trying to attach to $guid_one
*
* @return true|void
-**/
+ * @access private
+ */
function make_attachment($guid_one, $guid_two) {
if (!(already_attached($guid_one, $guid_two))) {
if (add_entity_relationship($guid_one, "attached", $guid_two)) {
@@ -541,7 +561,7 @@ function make_attachment($guid_one, $guid_two) {
* @param mixed $params Array of params
*
* @return mixed
- *
+ * @access private
*/
function import_relationship_plugin_hook($hook, $entity_type, $returnvalue, $params) {
$element = $params['element'];
@@ -551,9 +571,8 @@ function import_relationship_plugin_hook($hook, $entity_type, $returnvalue, $par
if ($element instanceof ODDRelationship) {
$tmp = new ElggRelationship();
$tmp->import($element);
-
- return $tmp;
}
+ return $tmp;
}
/**
@@ -566,10 +585,10 @@ function import_relationship_plugin_hook($hook, $entity_type, $returnvalue, $par
*
* @elgg_event_handler export all
* @return mixed
+ * @throws InvalidParameterException
+ * @access private
*/
function export_relationship_plugin_hook($hook, $entity_type, $returnvalue, $params) {
- global $CONFIG;
-
// Sanity check values
if ((!is_array($params)) && (!isset($params['guid']))) {
throw new InvalidParameterException(elgg_echo('InvalidParameterException:GUIDNotForExport'));
@@ -593,38 +612,32 @@ function export_relationship_plugin_hook($hook, $entity_type, $returnvalue, $par
}
/**
- * An event listener which will notify users based on certain events.
+ * Notify user that someone has friended them
*
- * @param string $event Event name
- * @param string $object_type Object type
- * @param mixed $object Object
+ * @param string $event Event name
+ * @param string $type Object type
+ * @param mixed $object Object
*
* @return bool
+ * @access private
*/
-function relationship_notification_hook($event, $object_type, $object) {
- global $CONFIG;
-
- if (
- ($object instanceof ElggRelationship) &&
- ($event == 'create') &&
- ($object_type == 'friend')
- ) {
- $user_one = get_entity($object->guid_one);
- $user_two = get_entity($object->guid_two);
+function relationship_notification_hook($event, $type, $object) {
+ /* @var ElggRelationship $object */
+ $user_one = get_entity($object->guid_one);
+ /* @var ElggUser $user_one */
- // Notify target user
- return notify_user($object->guid_two, $object->guid_one,
+ return notify_user($object->guid_two,
+ $object->guid_one,
elgg_echo('friend:newfriend:subject', array($user_one->name)),
elgg_echo("friend:newfriend:body", array($user_one->name, $user_one->getURL()))
- );
- }
+ );
}
-/** Register the import hook */
+// Register the import hook
elgg_register_plugin_hook_handler("import", "all", "import_relationship_plugin_hook", 3);
-/** Register the hook, ensuring entities are serialised first */
+// Register the hook, ensuring entities are serialised first
elgg_register_plugin_hook_handler("export", "all", "export_relationship_plugin_hook", 3);
-/** Register event to listen to some events **/
+// Register event to listen to some events
elgg_register_event_handler('create', 'friend', 'relationship_notification_hook');
diff --git a/engine/lib/river.php b/engine/lib/river.php
index 55d1c783a..e92040eb7 100644
--- a/engine/lib/river.php
+++ b/engine/lib/river.php
@@ -18,12 +18,14 @@
* @param int $posted The UNIX epoch timestamp of the river item (default: now)
* @param int $annotation_id The annotation ID associated with this river entry
*
- * @return bool Depending on success
+ * @return int/bool River ID or false on failure
*/
function add_to_river($view, $action_type, $subject_guid, $object_guid, $access_id = "",
$posted = 0, $annotation_id = 0) {
- // use default viewtype for when called from REST api
+ global $CONFIG;
+
+ // use default viewtype for when called from web services api
if (!elgg_view_exists($view, 'default')) {
return false;
}
@@ -42,12 +44,18 @@ $posted = 0, $annotation_id = 0) {
if ($access_id === "") {
$access_id = $object->access_id;
}
- $annotation_id = (int)$annotation_id;
$type = $object->getType();
$subtype = $object->getSubtype();
+
+ $view = sanitise_string($view);
$action_type = sanitise_string($action_type);
+ $subject_guid = sanitise_int($subject_guid);
+ $object_guid = sanitise_int($object_guid);
+ $access_id = sanitise_int($access_id);
+ $posted = sanitise_int($posted);
+ $annotation_id = sanitise_int($annotation_id);
- $params = array(
+ $values = array(
'type' => $type,
'subtype' => $subtype,
'action_type' => $action_type,
@@ -60,19 +68,16 @@ $posted = 0, $annotation_id = 0) {
);
// return false to stop insert
- $params = elgg_trigger_plugin_hook('add', 'river', null, $params);
- if ($params == false) {
+ $values = elgg_trigger_plugin_hook('creating', 'river', null, $values);
+ if ($values == false) {
// inserting did not fail - it was just prevented
return true;
}
- extract($params);
-
- // Load config
- global $CONFIG;
+ extract($values);
// Attempt to save river item; return success status
- $insert_data = insert_data("insert into {$CONFIG->dbprefix}river " .
+ $id = insert_data("insert into {$CONFIG->dbprefix}river " .
" set type = '$type', " .
" subtype = '$subtype', " .
" action_type = '$action_type', " .
@@ -83,89 +88,135 @@ $posted = 0, $annotation_id = 0) {
" annotation_id = $annotation_id, " .
" posted = $posted");
- //update the entities which had the action carried out on it
- if ($insert_data) {
+ // update the entities which had the action carried out on it
+ // @todo shouldn't this be down elsewhere? Like when an annotation is saved?
+ if ($id) {
update_entity_last_action($object_guid, $posted);
- return $insert_data;
+
+ $river_items = elgg_get_river(array('id' => $id));
+ if ($river_items) {
+ elgg_trigger_event('created', 'river', $river_items[0]);
+ }
+ return $id;
+ } else {
+ return false;
}
}
/**
- * Removes all items relating to a particular acting entity from the river
+ * Delete river items
*
- * @param int $subject_guid The GUID of the entity
+ * @warning not checking access (should we?)
*
- * @return bool Depending on success
+ * @param array $options Parameters:
+ * ids => INT|ARR River item id(s)
+ * subject_guids => INT|ARR Subject guid(s)
+ * object_guids => INT|ARR Object guid(s)
+ * annotation_ids => INT|ARR The identifier of the annotation(s)
+ * action_types => STR|ARR The river action type(s) identifier
+ * views => STR|ARR River view(s)
+ *
+ * types => STR|ARR Entity type string(s)
+ * subtypes => STR|ARR Entity subtype string(s)
+ * type_subtype_pairs => ARR Array of type => subtype pairs where subtype
+ * can be an array of subtype strings
+ *
+ * posted_time_lower => INT The lower bound on the time posted
+ * posted_time_upper => INT The upper bound on the time posted
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function remove_from_river_by_subject($subject_guid) {
- // Sanitise
- $subject_guid = (int) $subject_guid;
-
- // Load config
+function elgg_delete_river(array $options = array()) {
global $CONFIG;
- // Remove
- return delete_data("delete from {$CONFIG->dbprefix}river where subject_guid = {$subject_guid}");
-}
+ $defaults = array(
+ 'ids' => ELGG_ENTITIES_ANY_VALUE,
-/**
- * Removes all items relating to a particular entity being acted upon from the river
- *
- * @param int $object_guid The GUID of the entity
- *
- * @return bool Depending on success
- */
-function remove_from_river_by_object($object_guid) {
- // Sanitise
- $object_guid = (int) $object_guid;
+ 'subject_guids' => ELGG_ENTITIES_ANY_VALUE,
+ 'object_guids' => ELGG_ENTITIES_ANY_VALUE,
+ 'annotation_ids' => ELGG_ENTITIES_ANY_VALUE,
- // Load config
- global $CONFIG;
+ 'views' => ELGG_ENTITIES_ANY_VALUE,
+ 'action_types' => ELGG_ENTITIES_ANY_VALUE,
- // Remove
- return delete_data("delete from {$CONFIG->dbprefix}river where object_guid = {$object_guid}");
-}
+ 'types' => ELGG_ENTITIES_ANY_VALUE,
+ 'subtypes' => ELGG_ENTITIES_ANY_VALUE,
+ 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE,
-/**
- * Removes all items relating to a particular annotation being acted upon from the river
- *
- * @param int $annotation_id The ID of the annotation
- *
- * @return bool Depending on success
- * @since 1.7.0
- */
-function remove_from_river_by_annotation($annotation_id) {
- // Sanitise
- $annotation_id = (int) $annotation_id;
+ 'posted_time_lower' => ELGG_ENTITIES_ANY_VALUE,
+ 'posted_time_upper' => ELGG_ENTITIES_ANY_VALUE,
- // Load config
- global $CONFIG;
+ 'wheres' => array(),
+ 'joins' => array(),
- // Remove
- return delete_data("delete from {$CONFIG->dbprefix}river where annotation_id = {$annotation_id}");
-}
+ );
-/**
- * Removes a single river entry
- *
- * @param int $id The ID of the river entry
- *
- * @return bool Depending on success
- * @since 1.7.2
- */
-function remove_from_river_by_id($id) {
- global $CONFIG;
+ $options = array_merge($defaults, $options);
- // Sanitise
- $id = (int) $id;
+ $singulars = array('id', 'subject_guid', 'object_guid', 'annotation_id', 'action_type', 'view', 'type', 'subtype');
+ $options = elgg_normalise_plural_options_array($options, $singulars);
+
+ $wheres = $options['wheres'];
+
+ $wheres[] = elgg_get_guid_based_where_sql('rv.id', $options['ids']);
+ $wheres[] = elgg_get_guid_based_where_sql('rv.subject_guid', $options['subject_guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('rv.object_guid', $options['object_guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('rv.annotation_id', $options['annotation_ids']);
+ $wheres[] = elgg_river_get_action_where_sql($options['action_types']);
+ $wheres[] = elgg_river_get_view_where_sql($options['views']);
+ $wheres[] = elgg_get_river_type_subtype_where_sql('rv', $options['types'],
+ $options['subtypes'], $options['type_subtype_pairs']);
- return delete_data("delete from {$CONFIG->dbprefix}river where id = {$id}");
+ if ($options['posted_time_lower'] && is_int($options['posted_time_lower'])) {
+ $wheres[] = "rv.posted >= {$options['posted_time_lower']}";
+ }
+
+ if ($options['posted_time_upper'] && is_int($options['posted_time_upper'])) {
+ $wheres[] = "rv.posted <= {$options['posted_time_upper']}";
+ }
+
+ // see if any functions failed
+ // remove empty strings on successful functions
+ foreach ($wheres as $i => $where) {
+ if ($where === FALSE) {
+ return FALSE;
+ } elseif (empty($where)) {
+ unset($wheres[$i]);
+ }
+ }
+
+ // remove identical where clauses
+ $wheres = array_unique($wheres);
+
+ $query = "DELETE rv.* FROM {$CONFIG->dbprefix}river rv ";
+
+ // remove identical join clauses
+ $joins = array_unique($options['joins']);
+
+ // add joins
+ foreach ($joins as $j) {
+ $query .= " $j ";
+ }
+
+ // add wheres
+ $query .= ' WHERE ';
+
+ foreach ($wheres as $w) {
+ $query .= " $w AND ";
+ }
+ $query .= "1=1";
+
+ return delete_data($query);
}
/**
* Get river items
*
- * @param array $options
+ * @note If using types and subtypes in a query, they are joined with an AND.
+ *
+ * @param array $options Parameters:
+ * ids => INT|ARR River item id(s)
* subject_guids => INT|ARR Subject guid(s)
* object_guids => INT|ARR Object guid(s)
* annotation_ids => INT|ARR The identifier of the annotation(s)
@@ -195,6 +246,8 @@ function elgg_get_river(array $options = array()) {
global $CONFIG;
$defaults = array(
+ 'ids' => ELGG_ENTITIES_ANY_VALUE,
+
'subject_guids' => ELGG_ENTITIES_ANY_VALUE,
'object_guids' => ELGG_ENTITIES_ANY_VALUE,
'annotation_ids' => ELGG_ENTITIES_ANY_VALUE,
@@ -224,11 +277,12 @@ function elgg_get_river(array $options = array()) {
$options = array_merge($defaults, $options);
- $singulars = array('subject_guid', 'object_guid', 'annotation_id', 'action_type', 'type', 'subtype');
+ $singulars = array('id', 'subject_guid', 'object_guid', 'annotation_id', 'action_type', 'type', 'subtype');
$options = elgg_normalise_plural_options_array($options, $singulars);
$wheres = $options['wheres'];
+ $wheres[] = elgg_get_guid_based_where_sql('rv.id', $options['ids']);
$wheres[] = elgg_get_guid_based_where_sql('rv.subject_guid', $options['subject_guids']);
$wheres[] = elgg_get_guid_based_where_sql('rv.object_guid', $options['object_guids']);
$wheres[] = elgg_get_guid_based_where_sql('rv.annotation_id', $options['annotation_ids']);
@@ -258,9 +312,6 @@ function elgg_get_river(array $options = array()) {
}
}
- // remove identical where clauses
- $wheres = array_unique($wheres);
-
// see if any functions failed
// remove empty strings on successful functions
foreach ($wheres as $i => $where) {
@@ -271,6 +322,9 @@ function elgg_get_river(array $options = array()) {
}
}
+ // remove identical where clauses
+ $wheres = array_unique($wheres);
+
if (!$options['count']) {
$query = "SELECT DISTINCT rv.* FROM {$CONFIG->dbprefix}river rv ";
} else {
@@ -302,11 +356,12 @@ function elgg_get_river(array $options = array()) {
if ($options['limit']) {
$limit = sanitise_int($options['limit']);
- $offset = sanitise_int($options['offset']);
+ $offset = sanitise_int($options['offset'], false);
$query .= " LIMIT $offset, $limit";
}
$river_items = get_data($query, 'elgg_row_to_elgg_river_item');
+ _elgg_prefetch_river_entities($river_items);
return $river_items;
} else {
@@ -316,11 +371,56 @@ function elgg_get_river(array $options = array()) {
}
/**
+ * Prefetch entities that will be displayed in the river.
+ *
+ * @param ElggRiverItem[] $river_items
+ * @access private
+ */
+function _elgg_prefetch_river_entities(array $river_items) {
+ // prefetch objects and subjects
+ $guids = array();
+ foreach ($river_items as $item) {
+ if ($item->subject_guid && !_elgg_retrieve_cached_entity($item->subject_guid)) {
+ $guids[$item->subject_guid] = true;
+ }
+ if ($item->object_guid && !_elgg_retrieve_cached_entity($item->object_guid)) {
+ $guids[$item->object_guid] = true;
+ }
+ }
+ if ($guids) {
+ // avoid creating oversized query
+ // @todo how to better handle this?
+ $guids = array_slice($guids, 0, 300, true);
+ // return value unneeded, just priming cache
+ elgg_get_entities(array(
+ 'guids' => array_keys($guids),
+ 'limit' => 0,
+ ));
+ }
+
+ // prefetch object containers
+ $guids = array();
+ foreach ($river_items as $item) {
+ $object = $item->getObjectEntity();
+ if ($object->container_guid && !_elgg_retrieve_cached_entity($object->container_guid)) {
+ $guids[$object->container_guid] = true;
+ }
+ }
+ if ($guids) {
+ $guids = array_slice($guids, 0, 300, true);
+ elgg_get_entities(array(
+ 'guids' => array_keys($guids),
+ 'limit' => 0,
+ ));
+ }
+}
+
+/**
* List river items
*
* @param array $options Any options from elgg_get_river() plus:
* pagination => BOOL Display pagination links (true)
-
+ *
* @return string
* @since 1.8.0
*/
@@ -332,10 +432,15 @@ function elgg_list_river(array $options = array()) {
'offset' => (int) max(get_input('offset', 0), 0),
'limit' => (int) max(get_input('limit', 20), 0),
'pagination' => TRUE,
- 'list_class' => 'elgg-river',
+ 'list_class' => 'elgg-list-river elgg-river', // @todo remove elgg-river in Elgg 1.9
);
-
+
$options = array_merge($defaults, $options);
+
+ if (!$options["limit"] && !$options["offset"]) {
+ // no need for pagination if listing is unlimited
+ $options["pagination"] = false;
+ }
$options['count'] = TRUE;
$count = elgg_get_river($options);
@@ -345,6 +450,7 @@ function elgg_list_river(array $options = array()) {
$options['count'] = $count;
$options['items'] = $items;
+
return elgg_view('page/components/list', $options);
}
@@ -375,7 +481,7 @@ function elgg_row_to_elgg_river_item($row) {
function elgg_river_get_access_sql() {
// rewrite default access where clause to work with river table
return str_replace("and enabled='yes'", '',
- str_replace('owner_guid', 'rv.subject_guid',
+ str_replace('owner_guid', 'rv.subject_guid',
str_replace('access_id', 'rv.access_id', get_access_sql_suffix())));
}
@@ -384,7 +490,6 @@ function elgg_river_get_access_sql() {
*
* @internal This is a simplified version of elgg_get_entity_type_subtype_where_sql()
* which could be used for all queries once the subtypes have been denormalized.
- * FYI: It allows types and subtypes to not be paired.
*
* @param string $table 'rv'
* @param NULL|array $types Array of types or NULL if none.
@@ -402,6 +507,8 @@ function elgg_get_river_type_subtype_where_sql($table, $types, $subtypes, $pairs
}
$wheres = array();
+ $types_wheres = array();
+ $subtypes_wheres = array();
// if no pairs, use types and subtypes
if (!is_array($pairs)) {
@@ -411,7 +518,7 @@ function elgg_get_river_type_subtype_where_sql($table, $types, $subtypes, $pairs
}
foreach ($types as $type) {
$type = sanitise_string($type);
- $wheres[] = "({$table}.type = '$type')";
+ $types_wheres[] = "({$table}.type = '$type')";
}
}
@@ -421,13 +528,20 @@ function elgg_get_river_type_subtype_where_sql($table, $types, $subtypes, $pairs
}
foreach ($subtypes as $subtype) {
$subtype = sanitise_string($subtype);
- $wheres[] = "({$table}.subtype = '$subtype')";
+ $subtypes_wheres[] = "({$table}.subtype = '$subtype')";
}
}
- if (is_array($wheres) && count($wheres)) {
- $wheres = array(implode(' AND ', $wheres));
+ if (is_array($types_wheres) && count($types_wheres)) {
+ $types_wheres = array(implode(' OR ', $types_wheres));
}
+
+ if (is_array($subtypes_wheres) && count($subtypes_wheres)) {
+ $subtypes_wheres = array('(' . implode(' OR ', $subtypes_wheres) . ')');
+ }
+
+ $wheres = array(implode(' AND ', array_merge($types_wheres, $subtypes_wheres)));
+
} else {
// using type/subtype pairs
foreach ($pairs as $paired_type => $paired_subtypes) {
@@ -471,7 +585,7 @@ function elgg_river_get_action_where_sql($types) {
if (!is_array($types)) {
$types = sanitise_string($types);
- return "'(rv.action_type = '$types')";
+ return "(rv.action_type = '$types')";
}
// sanitize types array
@@ -485,6 +599,35 @@ function elgg_river_get_action_where_sql($types) {
}
/**
+ * Get the where clause based on river view strings
+ *
+ * @param array $views Array of view strings
+ *
+ * @return string
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_river_get_view_where_sql($views) {
+ if (!$views) {
+ return '';
+ }
+
+ if (!is_array($views)) {
+ $views = sanitise_string($views);
+ return "(rv.view = '$views')";
+ }
+
+ // sanitize views array
+ $views_sanitized = array();
+ foreach ($views as $view) {
+ $views_sanitized[] = sanitise_string($view);
+ }
+
+ $view_str = implode("','", $views_sanitized);
+ return "(rv.view IN ('$view_str'))";
+}
+
+/**
* Sets the access ID on river items for a particular object
*
* @param int $object_guid The GUID of the entity
@@ -508,36 +651,53 @@ function update_river_access_by_object($object_guid, $access_id) {
}
/**
- * Page handler for activiy
+ * Page handler for activity
*
* @param array $page
+ * @return bool
+ * @access private
*/
function elgg_river_page_handler($page) {
global $CONFIG;
elgg_set_page_owner_guid(elgg_get_logged_in_user_guid());
+ // make a URL segment available in page handler script
$page_type = elgg_extract(0, $page, 'all');
+ $page_type = preg_replace('[\W]', '', $page_type);
if ($page_type == 'owner') {
$page_type = 'mine';
}
-
- // content filter code here
- $entity_type = '';
- $entity_subtype = '';
+ set_input('page_type', $page_type);
require_once("{$CONFIG->path}pages/river.php");
+ return true;
+}
+
+/**
+ * Register river unit tests
+ * @access private
+ */
+function elgg_river_test($hook, $type, $value) {
+ global $CONFIG;
+ $value[] = $CONFIG->path . 'engine/tests/api/river.php';
+ return $value;
}
/**
* Initialize river library
+ * @access private
*/
function elgg_river_init() {
elgg_register_page_handler('activity', 'elgg_river_page_handler');
$item = new ElggMenuItem('activity', elgg_echo('activity'), 'activity');
elgg_register_menu_item('site', $item);
-
+
elgg_register_widget_type('river_widget', elgg_echo('river:widget:title'), elgg_echo('river:widget:description'));
+
+ elgg_register_action('river/delete', '', 'admin');
+
+ elgg_register_plugin_hook_handler('unit_test', 'system', 'elgg_river_test');
}
elgg_register_event_handler('init', 'system', 'elgg_river_init');
diff --git a/engine/lib/sessions.php b/engine/lib/sessions.php
index 5d45cc73d..e3d5ce9cd 100644
--- a/engine/lib/sessions.php
+++ b/engine/lib/sessions.php
@@ -87,6 +87,9 @@ function elgg_is_admin_logged_in() {
*/
function elgg_is_admin_user($user_guid) {
global $CONFIG;
+
+ $user_guid = (int)$user_guid;
+
// cannot use magic metadata here because of recursion
// must support the old way of getting admin from metadata
@@ -127,12 +130,17 @@ function elgg_is_admin_user($user_guid) {
/**
* Perform user authentication with a given username and password.
*
+ * @warning This returns an error message on failure. Use the identical operator to check
+ * for access: if (true === elgg_authenticate()) { ... }.
+ *
+ *
* @see login
*
* @param string $username The username
* @param string $password The password
*
* @return true|string True or an error message on failure
+ * @access private
*/
function elgg_authenticate($username, $password) {
$pam = new ElggPAM('user');
@@ -154,10 +162,11 @@ function elgg_authenticate($username, $password) {
*
* @return bool
* @throws LoginException
+ * @access private
*/
-function pam_auth_userpass($credentials = NULL) {
+function pam_auth_userpass(array $credentials = array()) {
- if (!is_array($credentials) || !isset($credentials['username']) || !isset($credentials['password'])) {
+ if (!isset($credentials['username']) || !isset($credentials['password'])) {
return false;
}
@@ -183,7 +192,7 @@ function pam_auth_userpass($credentials = NULL) {
*
* @param int $user_guid User GUID
*
- * @return bool on success
+ * @return bool
*/
function log_login_failure($user_guid) {
$user_guid = (int)$user_guid;
@@ -280,8 +289,6 @@ function check_rate_limit_exceeded($user_guid) {
* @throws LoginException
*/
function login(ElggUser $user, $persistent = false) {
- global $CONFIG;
-
// User is banned, return false.
if ($user->isBanned()) {
throw new LoginException(elgg_echo('LoginException:BannedUser'));
@@ -319,6 +326,12 @@ function login(ElggUser $user, $persistent = false) {
set_last_login($_SESSION['guid']);
reset_login_failure_count($user->guid); // Reset any previous failed login attempts
+ // if memcache is enabled, invalidate the user in memcache @see https://github.com/Elgg/Elgg/issues/3143
+ if (is_memcache_available()) {
+ // this needs to happen with a shutdown function because of the timing with set_last_login()
+ register_shutdown_function("_elgg_invalidate_memcache_for_entity", $_SESSION['guid']);
+ }
+
return true;
}
@@ -328,8 +341,6 @@ function login(ElggUser $user, $persistent = false) {
* @return bool
*/
function logout() {
- global $CONFIG;
-
if (isset($_SESSION['user'])) {
if (!elgg_trigger_event('logout', 'user', $_SESSION['user'])) {
return false;
@@ -353,7 +364,7 @@ function logout() {
session_destroy();
// starting a default session to store any post-logout messages.
- session_init(NULL, NULL, NULL);
+ _elgg_session_boot(NULL, NULL, NULL);
$_SESSION['msg'] = $old_msg;
return TRUE;
@@ -370,13 +381,10 @@ function logout() {
*
* @uses $_SESSION
*
- * @param string $event Event name
- * @param string $object_type Object type
- * @param mixed $object Object
- *
* @return bool
+ * @access private
*/
-function session_init($event, $object_type, $object) {
+function _elgg_session_boot() {
global $DB_PREFIX, $CONFIG;
// Use database for sessions
@@ -441,8 +449,8 @@ function session_init($event, $object_type, $object) {
set_last_action($_SESSION['guid']);
}
- elgg_register_action("login", '', 'public');
- elgg_register_action("logout");
+ elgg_register_action('login', '', 'public');
+ elgg_register_action('logout');
// Register a default PAM handler
register_pam_handler('pam_auth_userpass');
@@ -457,9 +465,6 @@ function session_init($event, $object_type, $object) {
return false;
}
- // Since we have loaded a new user, this user may have different language preferences
- register_translations(dirname(dirname(dirname(__FILE__))) . "/languages/");
-
return true;
}
@@ -499,6 +504,7 @@ function admin_gatekeeper() {
*
* @return true
* @todo Document
+ * @access private
*/
function _elgg_session_open($save_path, $session_name) {
global $sess_save_path;
@@ -514,6 +520,7 @@ function _elgg_session_open($save_path, $session_name) {
* @todo document
*
* @return true
+ * @access private
*/
function _elgg_session_close() {
return true;
@@ -525,6 +532,7 @@ function _elgg_session_close() {
* @param string $id The session ID
*
* @return string
+ * @access private
*/
function _elgg_session_read($id) {
global $DB_PREFIX;
@@ -558,6 +566,7 @@ function _elgg_session_read($id) {
* @param mixed $sess_data Session data
*
* @return bool
+ * @access private
*/
function _elgg_session_write($id, $sess_data) {
global $DB_PREFIX;
@@ -597,6 +606,7 @@ function _elgg_session_write($id, $sess_data) {
* @param string $id Session ID
*
* @return bool
+ * @access private
*/
function _elgg_session_destroy($id) {
global $DB_PREFIX;
@@ -611,10 +621,8 @@ function _elgg_session_destroy($id) {
global $sess_save_path;
$sess_file = "$sess_save_path/sess_$id";
- return(@unlink($sess_file));
+ return @unlink($sess_file);
}
-
- return false;
}
/**
@@ -623,6 +631,7 @@ function _elgg_session_destroy($id) {
* @param int $maxlifetime Max age of a session
*
* @return bool
+ * @access private
*/
function _elgg_session_gc($maxlifetime) {
global $DB_PREFIX;
@@ -645,5 +654,3 @@ function _elgg_session_gc($maxlifetime) {
return true;
}
-
-elgg_register_event_handler("boot", "system", "session_init", 20);
diff --git a/engine/lib/sites.php b/engine/lib/sites.php
index 5fed29822..3de0eccc2 100644
--- a/engine/lib/sites.php
+++ b/engine/lib/sites.php
@@ -18,11 +18,19 @@
function elgg_get_site_entity($site_guid = 0) {
global $CONFIG;
+ $result = false;
+
if ($site_guid == 0) {
- return $CONFIG->site;
+ $site = $CONFIG->site;
+ } else {
+ $site = get_entity($site_guid);
+ }
+
+ if ($site instanceof ElggSite) {
+ $result = $site;
}
- return get_entity($site_guid);
+ return $result;
}
/**
@@ -31,6 +39,7 @@ function elgg_get_site_entity($site_guid = 0) {
* @param int $guid The site GUID
*
* @return mixed
+ * @access private
*/
function get_site_entity_as_row($guid) {
global $CONFIG;
@@ -49,6 +58,7 @@ function get_site_entity_as_row($guid) {
* @param string $url URL of the site
*
* @return bool
+ * @access private
*/
function create_site_entity($guid, $name, $description, $url) {
global $CONFIG;
@@ -108,8 +118,6 @@ function create_site_entity($guid, $name, $description, $url) {
* @return bool
*/
function add_site_user($site_guid, $user_guid) {
- global $CONFIG;
-
$site_guid = (int)$site_guid;
$user_guid = (int)$user_guid;
@@ -140,8 +148,6 @@ function remove_site_user($site_guid, $user_guid) {
* @return mixed
*/
function add_site_object($site_guid, $object_guid) {
- global $CONFIG;
-
$site_guid = (int)$site_guid;
$object_guid = (int)$object_guid;
@@ -182,8 +188,8 @@ function get_site_objects($site_guid, $subtype = "", $limit = 10, $offset = 0) {
'relationship' => 'member_of_site',
'relationship_guid' => $site_guid,
'inverse_relationship' => TRUE,
- 'types' => 'object',
- 'subtypes' => $subtype,
+ 'type' => 'object',
+ 'subtype' => $subtype,
'limit' => $limit,
'offset' => $offset
));
@@ -204,7 +210,7 @@ function get_site_by_url($url) {
$row = get_data_row("SELECT * from {$CONFIG->dbprefix}sites_entity where url='$url'");
if ($row) {
- return new ElggSite($row);
+ return get_entity($row->guid);
}
return false;
@@ -230,53 +236,21 @@ function get_site_domain($guid) {
}
/**
- * Initialise site handling
- *
- * Called at the beginning of system running, to set the ID of the current site.
- * This is 0 by default, but plugins may alter this behaviour by attaching functions
- * to the sites init event and changing $CONFIG->site_id.
- *
- * @uses $CONFIG
- *
- * @param string $event Event API required parameter
- * @param string $object_type Event API required parameter
- * @param null $object Event API required parameter
- *
- * @return true
- */
-function sites_boot($event, $object_type, $object) {
- global $CONFIG;
-
- $site = elgg_trigger_plugin_hook("siteid", "system");
- if ($site === null || $site === false) {
- $CONFIG->site_id = (int) datalist_get('default_site');
- } else {
- $CONFIG->site_id = $site;
- }
- $CONFIG->site_guid = $CONFIG->site_id;
- $CONFIG->site = get_entity($CONFIG->site_guid);
-
- return true;
-}
-
-// Register event handlers
-elgg_register_event_handler('boot', 'system', 'sites_boot', 2);
-
-// Register with unit test
-elgg_register_plugin_hook_handler('unit_test', 'system', 'sites_test');
-
-/**
* Unit tests for sites
*
- * @param sting $hook unit_test
+ * @param string $hook unit_test
* @param string $type system
* @param mixed $value Array of tests
* @param mixed $params Params
*
* @return array
+ * @access private
*/
function sites_test($hook, $type, $value, $params) {
global $CONFIG;
$value[] = "{$CONFIG->path}engine/tests/objects/sites.php";
return $value;
}
+
+// Register with unit test
+elgg_register_plugin_hook_handler('unit_test', 'system', 'sites_test');
diff --git a/engine/lib/statistics.php b/engine/lib/statistics.php
index 4e822e8af..4cb0bb0b8 100644
--- a/engine/lib/statistics.php
+++ b/engine/lib/statistics.php
@@ -95,19 +95,27 @@ function get_number_users($show_deactivated = false) {
* @return string
*/
function get_online_users() {
- $offset = get_input('offset', 0);
- $count = count(find_active_users(600, 9999));
- $objects = find_active_users(600, 10, $offset);
+ $limit = max(0, (int) get_input("limit", 10));
+ $offset = max(0, (int) get_input("offset", 0));
+
+ $count = find_active_users(600, $limit, $offset, true);
+ $objects = find_active_users(600, $limit, $offset);
if ($objects) {
- return elgg_view_entity_list($objects, $count, $offset, 10, false);
+ return elgg_view_entity_list($objects, array(
+ 'count' => $count,
+ 'limit' => $limit,
+ 'offset' => $offset
+ ));
}
+ return '';
}
/**
* Initialise the statistics admin page.
*
* @return void
+ * @access private
*/
function statistics_init() {
elgg_extend_view('core/settings/statistics', 'core/settings/statistics/online');
diff --git a/engine/lib/system_log.php b/engine/lib/system_log.php
index d6c746af1..84302632e 100644
--- a/engine/lib/system_log.php
+++ b/engine/lib/system_log.php
@@ -10,7 +10,10 @@
/**
* Retrieve the system log based on a number of parameters.
*
+ * @todo too many args, and the first arg is too confusing
+ *
* @param int|array $by_user The guid(s) of the user(s) who initiated the event.
+ * Use 0 for unowned entries. Anything else falsey means anyone.
* @param string $event The event you are searching on.
* @param string $class The class of object it effects.
* @param string $type The type
@@ -21,11 +24,12 @@
* @param int $timebefore Lower time limit
* @param int $timeafter Upper time limit
* @param int $object_id GUID of an object
- *
+ * @param string $ip_address The IP address.
* @return mixed
*/
-function get_system_log($by_user = "", $event = "", $class = "", $type = "", $subtype = "",
-$limit = 10, $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $object_id = 0) {
+function get_system_log($by_user = "", $event = "", $class = "", $type = "", $subtype = "", $limit = 10,
+ $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $object_id = 0,
+ $ip_address = "") {
global $CONFIG;
@@ -37,16 +41,18 @@ $limit = 10, $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $obje
} else {
$by_user = (int)$by_user;
}
+
$event = sanitise_string($event);
$class = sanitise_string($class);
$type = sanitise_string($type);
$subtype = sanitise_string($subtype);
+ $ip_address = sanitise_string($ip_address);
$limit = (int)$limit;
$offset = (int)$offset;
$where = array();
- if ($by_user_orig !== "") {
+ if ($by_user_orig !== "" && $by_user_orig !== false && $by_user_orig !== null) {
if (is_int($by_user)) {
$where[] = "performed_by_guid=$by_user";
} else if (is_array($by_user)) {
@@ -75,6 +81,9 @@ $limit = 10, $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $obje
if ($object_id) {
$where[] = "object_id = " . ((int) $object_id);
}
+ if ($ip_address) {
+ $where[] = "ip_address = '$ip_address'";
+ }
$select = "*";
if ($count) {
@@ -91,7 +100,8 @@ $limit = 10, $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $obje
}
if ($count) {
- if ($numrows = get_data_row($query)) {
+ $numrows = get_data_row($query);
+ if ($numrows) {
return $numrows->count;
}
} else {
@@ -148,9 +158,8 @@ function get_object_from_log_entry($entry_id) {
* This is called by the event system and should not be called directly.
*
* @param object $object The object you're talking about.
- * @param string $event String The event being logged
- *
- * @return mixed
+ * @param string $event The event being logged
+ * @return void
*/
function system_log($object, $event) {
global $CONFIG;
@@ -158,6 +167,13 @@ function system_log($object, $event) {
static $cache_size = 0;
if ($object instanceof Loggable) {
+
+ /* @var ElggEntity|ElggExtender $object */
+ if (datalist_get('version') < 2012012000) {
+ // this is a site that doesn't have the ip_address column yet
+ return;
+ }
+
// reset cache if it has grown too large
if (!is_array($log_cache) || $cache_size > 500) {
$log_cache = array();
@@ -171,6 +187,16 @@ function system_log($object, $event) {
$object_subtype = $object->getSubtype();
$event = sanitise_string($event);
$time = time();
+
+ if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+ $ip_address = array_pop(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
+ } elseif (!empty($_SERVER['HTTP_X_REAL_IP'])) {
+ $ip_address = array_pop(explode(',', $_SERVER['HTTP_X_REAL_IP']));
+ } else {
+ $ip_address = $_SERVER['REMOTE_ADDR'];
+ }
+ $ip_address = sanitise_string($ip_address);
+
$performed_by = elgg_get_logged_in_user_guid();
if (isset($object->access_id)) {
@@ -194,18 +220,16 @@ function system_log($object, $event) {
if (!isset($log_cache[$time][$object_id][$event])) {
$query = "INSERT DELAYED into {$CONFIG->dbprefix}system_log
(object_id, object_class, object_type, object_subtype, event,
- performed_by_guid, owner_guid, access_id, enabled, time_created)
+ performed_by_guid, owner_guid, access_id, enabled, time_created, ip_address)
VALUES
('$object_id','$object_class','$object_type', '$object_subtype', '$event',
- $performed_by, $owner_guid, $access_id, '$enabled', '$time')";
+ $performed_by, $owner_guid, $access_id, '$enabled', '$time', '$ip_address')";
insert_data($query);
$log_cache[$time][$object_id][$event] = true;
$cache_size += 1;
}
-
- return true;
}
}
@@ -270,6 +294,7 @@ function system_log_default_logger($event, $object_type, $object) {
* @param Loggable $object Object to log
*
* @return true
+ * @access private
*/
function system_log_listener($event, $object_type, $object) {
if (($object_type != 'systemlog') && ($event != 'log')) {
diff --git a/engine/lib/tags.php b/engine/lib/tags.php
index 1116d63f3..586a9b9e4 100644
--- a/engine/lib/tags.php
+++ b/engine/lib/tags.php
@@ -17,6 +17,7 @@
* @param int $buckets The number of buckets
*
* @return int
+ * @access private
*/
function calculate_tag_size($min, $max, $number_of_tags, $buckets = 6) {
$delta = (($max - $min) / $buckets);
@@ -47,7 +48,8 @@ function calculate_tag_size($min, $max, $number_of_tags, $buckets = 6) {
* @param array $tags The array of tags.
* @param int $buckets The number of buckets
*
- * @return An associated array of tags with a weighting, this can then be mapped to a display class.
+ * @return array An associated array of tags with a weighting, this can then be mapped to a display class.
+ * @access private
*/
function generate_tag_cloud(array $tags, $buckets = 6) {
$cloud = array();
@@ -112,8 +114,8 @@ function generate_tag_cloud(array $tags, $buckets = 6) {
*
* joins => array() Additional joins
*
- * @return false/array - if no tags or error, false
- * otherwise, array of objects with ->tag and ->total values
+ * @return object[]|false If no tags or error, false
+ * otherwise, array of objects with ->tag and ->total values
* @since 1.7.1
*/
function elgg_get_tags(array $options = array()) {
@@ -170,6 +172,7 @@ function elgg_get_tags(array $options = array()) {
// catch for tags that were spaces
$wheres[] = "msv.string != ''";
+ $sanitised_tags = array();
foreach ($options['tag_names'] as $tag) {
$sanitised_tags[] = '"' . sanitise_string($tag) . '"';
}
@@ -184,9 +187,6 @@ function elgg_get_tags(array $options = array()) {
$wheres[] = elgg_get_entity_time_where_sql('e', $options['created_time_upper'],
$options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']);
- // remove identical where clauses
- $wheres = array_unique($wheres);
-
// see if any functions failed
// remove empty strings on successful functions
foreach ($wheres as $i => $where) {
@@ -197,6 +197,8 @@ function elgg_get_tags(array $options = array()) {
}
}
+ // remove identical where clauses
+ $wheres = array_unique($wheres);
$joins = $options['joins'];
@@ -320,26 +322,28 @@ function elgg_get_registered_tag_metadata_names() {
*
* @param array $page Page array
*
- * @return void
+ * @return bool
+ * @access private
*/
function elgg_tagcloud_page_handler($page) {
- switch ($page[0]) {
- default:
- $title = elgg_view_title(elgg_echo('tags:site_cloud'));
- $options = array(
- 'threshold' => 0,
- 'limit' => 100,
- 'tag_name' => 'tags',
- );
- $tags = elgg_view_tagcloud($options);
- $content = $title . $tags;
- $body = elgg_view_layout('one_sidebar', array('content' => $content));
-
- echo elgg_view_page(elgg_echo('tags:site_cloud'), $body);
- break;
- }
+
+ $title = elgg_view_title(elgg_echo('tags:site_cloud'));
+ $options = array(
+ 'threshold' => 0,
+ 'limit' => 100,
+ 'tag_name' => 'tags',
+ );
+ $tags = elgg_view_tagcloud($options);
+ $content = $title . $tags;
+ $body = elgg_view_layout('one_sidebar', array('content' => $content));
+
+ echo elgg_view_page(elgg_echo('tags:site_cloud'), $body);
+ return true;
}
+/**
+ * @access private
+ */
function elgg_tags_init() {
// register the standard tags metadata name
elgg_register_tag_metadata_name('tags');
diff --git a/engine/lib/upgrade.php b/engine/lib/upgrade.php
index 85810956b..158ec9ec1 100644
--- a/engine/lib/upgrade.php
+++ b/engine/lib/upgrade.php
@@ -14,21 +14,23 @@
* @param bool $quiet Suppress errors. Don't use this.
*
* @return bool
+ * @access private
*/
function upgrade_code($version, $quiet = FALSE) {
+ // do not remove - upgrade scripts depend on this
global $CONFIG;
-
+
$version = (int) $version;
$upgrade_path = elgg_get_config('path') . 'engine/lib/upgrades/';
- $processed_upgrades = unserialize(datalist_get('processed_upgrades'));
- // the day we started the new upgrade names
- $upgrade_epoch = 2011021700;
+ $processed_upgrades = elgg_get_processed_upgrades();
+ // upgrading from 1.7 to 1.8. Need to bootstrap.
if (!$processed_upgrades) {
- $processed_upgrades = array();
- }
+ elgg_upgrade_bootstrap_17_to_18();
- $upgrades = array();
+ // grab accurate processed upgrades
+ $processed_upgrades = elgg_get_processed_upgrades();
+ }
$upgrade_files = elgg_get_upgrade_files($upgrade_path);
@@ -36,23 +38,7 @@ function upgrade_code($version, $quiet = FALSE) {
return false;
}
- // if before the new upgrade system, run through all upgrades and check
- // version number. After the upgrade epoch, pull run upgrades from db
- if ($version < $upgrade_epoch) {
- foreach ($upgrade_files as $upgrade_file) {
- $upgrade_version = elgg_get_upgrade_file_version($upgrade_file);
-
- if ($version < $upgrade_version) {
- $upgrades[] = $upgrade_file;
- } else {
- // set this upgrade as processed so that we don't run it again
- $processed_upgrades[] = $upgrade_file;
- }
- }
- } else {
- // add any upgrades that haven't been run to the upgrades list
- $upgrades = elgg_get_unprocessed_upgrades($upgrade_files, $processed_upgrades);
- }
+ $upgrades = elgg_get_unprocessed_upgrades($upgrade_files, $processed_upgrades);
// Sort and execute
sort($upgrades);
@@ -67,7 +53,7 @@ function upgrade_code($version, $quiet = FALSE) {
try {
if (!@include("$upgrade_path/$upgrade")) {
$success = false;
- error_log($e->getmessage());
+ error_log("Could not include $upgrade_path/$upgrade");
}
} catch (Exception $e) {
$success = false;
@@ -76,6 +62,7 @@ function upgrade_code($version, $quiet = FALSE) {
} else {
if (!include("$upgrade_path/$upgrade")) {
$success = false;
+ error_log("Could not include $upgrade_path/$upgrade");
}
}
@@ -84,13 +71,12 @@ function upgrade_code($version, $quiet = FALSE) {
$processed_upgrades[] = $upgrade;
// don't set the version to a lower number in instances where an upgrade
- // has been merged from a lower version
+ // has been merged from a lower version of Elgg
if ($upgrade_version > $version) {
datalist_set('version', $upgrade_version);
}
- $processed_upgrades = array_unique($processed_upgrades);
- datalist_set('processed_upgrades', serialize($processed_upgrades));
+ elgg_set_processed_upgrades($processed_upgrades);
} else {
return false;
}
@@ -100,11 +86,37 @@ function upgrade_code($version, $quiet = FALSE) {
}
/**
+ * Saves the processed upgrades to a dataset.
+ *
+ * @param array $processed_upgrades An array of processed upgrade filenames
+ * (not the path, just the file)
+ * @return bool
+ * @access private
+ */
+function elgg_set_processed_upgrades(array $processed_upgrades) {
+ $processed_upgrades = array_unique($processed_upgrades);
+ return datalist_set('processed_upgrades', serialize($processed_upgrades));
+}
+
+/**
+ * Gets a list of processes upgrades
+ *
+ * @return mixed Array of processed upgrade filenames or false
+ * @access private
+ */
+function elgg_get_processed_upgrades() {
+ $upgrades = datalist_get('processed_upgrades');
+ $unserialized = unserialize($upgrades);
+ return $unserialized;
+}
+
+/**
* Returns the version of the upgrade filename.
*
* @param string $filename The upgrade filename. No full path.
* @return int|false
- * @since 1.8
+ * @since 1.8.0
+ * @access private
*/
function elgg_get_upgrade_file_version($filename) {
preg_match('/^([0-9]{10})([\.a-z0-9-_]+)?\.(php)$/i', $filename, $matches);
@@ -121,6 +133,7 @@ function elgg_get_upgrade_file_version($filename) {
*
* @param string $upgrade_path The up
* @return array|false
+ * @access private
*/
function elgg_get_upgrade_files($upgrade_path = null) {
if (!$upgrade_path) {
@@ -153,7 +166,7 @@ function elgg_get_upgrade_files($upgrade_path = null) {
}
/**
- * Get the current version information
+ * Get the current Elgg version information
*
* @param bool $humanreadable Whether to return a human readable version (default: false)
*
@@ -162,13 +175,18 @@ function elgg_get_upgrade_files($upgrade_path = null) {
function get_version($humanreadable = false) {
global $CONFIG;
+ static $version, $release;
+
if (isset($CONFIG->path)) {
- if (include($CONFIG->path . "version.php")) {
- return (!$humanreadable) ? $version : $release;
+ if (!isset($version) || !isset($release)) {
+ if (!include($CONFIG->path . "version.php")) {
+ return false;
+ }
}
+ return (!$humanreadable) ? $version : $release;
}
- return FALSE;
+ return false;
}
/**
@@ -177,7 +195,8 @@ function get_version($humanreadable = false) {
* @param null|array $upgrade_files Optional upgrade files
* @param null|array $processed_upgrades Optional processed upgrades
*
- * @return array()
+ * @return array
+ * @access private
*/
function elgg_get_unprocessed_upgrades($upgrade_files = null, $processed_upgrades = null) {
if ($upgrade_files === null) {
@@ -198,7 +217,8 @@ function elgg_get_unprocessed_upgrades($upgrade_files = null, $processed_upgrade
/**
* Determines whether or not the database needs to be upgraded.
*
- * @return true|false Depending on whether or not the db version matches the code version
+ * @return bool Depending on whether or not the db version matches the code version
+ * @access private
*/
function version_upgrade_check() {
$dbversion = (int) datalist_get('version');
@@ -215,7 +235,7 @@ function version_upgrade_check() {
* Upgrades Elgg Database and code
*
* @return bool
- *
+ * @access private
*/
function version_upgrade() {
// It's possible large upgrades could exceed the max execution time.
@@ -225,7 +245,7 @@ function version_upgrade() {
// No version number? Oh snap...this is an upgrade from a clean installation < 1.7.
// Run all upgrades without error reporting and hope for the best.
- // See http://trac.elgg.org/elgg/ticket/1432 for more.
+ // See https://github.com/elgg/elgg/issues/1432 for more.
$quiet = !$dbversion;
// Note: Database upgrades are deprecated as of 1.8. Use code upgrades. See #1433
@@ -248,3 +268,98 @@ function version_upgrade() {
return false;
}
+
+/**
+ * Boot straps into 1.8 upgrade system from 1.7
+ *
+ * This runs all the 1.7 upgrades, then sets the processed_upgrades to all existing 1.7 upgrades.
+ * Control is then passed back to the main upgrade function which detects and runs the
+ * 1.8 upgrades, regardless of filename convention.
+ *
+ * @return bool
+ * @access private
+ */
+function elgg_upgrade_bootstrap_17_to_18() {
+ $db_version = (int) datalist_get('version');
+
+ // the 1.8 upgrades before the upgrade system change that are interspersed with 1.7 upgrades.
+ $upgrades_18 = array(
+ '2010111501.php',
+ '2010121601.php',
+ '2010121602.php',
+ '2010121701.php',
+ '2010123101.php',
+ '2011010101.php',
+ );
+
+ $upgrade_files = elgg_get_upgrade_files();
+ $processed_upgrades = array();
+
+ foreach ($upgrade_files as $upgrade_file) {
+ // ignore if not in 1.7 format or if it's a 1.8 upgrade
+ if (in_array($upgrade_file, $upgrades_18) || !preg_match("/[0-9]{10}\.php/", $upgrade_file)) {
+ continue;
+ }
+
+ $upgrade_version = elgg_get_upgrade_file_version($upgrade_file);
+
+ // this has already been run in a previous 1.7.X -> 1.7.X upgrade
+ if ($upgrade_version < $db_version) {
+ $processed_upgrades[] = $upgrade_file;
+ }
+ }
+
+ return elgg_set_processed_upgrades($processed_upgrades);
+}
+
+/**
+ * Creates a table {prefix}upgrade_lock that is used as a mutex for upgrades.
+ *
+ * @see _elgg_upgrade_lock()
+ *
+ * @return bool
+ * @access private
+ */
+function _elgg_upgrade_lock() {
+ global $CONFIG;
+
+ if (!_elgg_upgrade_is_locked()) {
+ // lock it
+ insert_data("create table {$CONFIG->dbprefix}upgrade_lock (id INT)");
+ elgg_log('Locked for upgrade.', 'NOTICE');
+ return true;
+ }
+
+ elgg_log('Cannot lock for upgrade: already locked.', 'WARNING');
+ return false;
+}
+
+/**
+ * Unlocks upgrade.
+ *
+ * @see _elgg_upgrade_lock()
+ *
+ * @access private
+ */
+function _elgg_upgrade_unlock() {
+ global $CONFIG;
+ delete_data("drop table {$CONFIG->dbprefix}upgrade_lock");
+ elgg_log('Upgrade unlocked.', 'NOTICE');
+}
+
+/**
+ * Checks if upgrade is locked
+ *
+ * @return bool
+ * @access private
+ */
+function _elgg_upgrade_is_locked() {
+ global $CONFIG;
+
+ $is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}upgrade_lock'"));
+
+ // @todo why?
+ _elgg_invalidate_query_cache();
+
+ return $is_locked;
+}
diff --git a/engine/lib/upgrades/2009102801.php b/engine/lib/upgrades/2009102801.php
index cab9a6835..3ad113fb2 100644
--- a/engine/lib/upgrades/2009102801.php
+++ b/engine/lib/upgrades/2009102801.php
@@ -203,14 +203,15 @@ function user_file_matrix($guid) {
return "$time_created/$user->guid/";
}
-global $DB_QUERY_CACHE, $DB_PROFILE, $ENTITY_CACHE;
+global $ENTITY_CACHE, $CONFIG;
/**
* Upgrade file locations
*/
$users = mysql_query("SELECT guid, username
FROM {$CONFIG->dbprefix}users_entity WHERE username != ''");
while ($user = mysql_fetch_object($users)) {
- $DB_QUERY_CACHE = $DB_PROFILE = $ENTITY_CACHE = array();
+ $ENTITY_CACHE = array();
+ _elgg_invalidate_query_cache();
$to = $CONFIG->dataroot . user_file_matrix($user->guid);
foreach (array('1_0', '1_1', '1_6') as $version) {
diff --git a/engine/lib/upgrades/2010033101.php b/engine/lib/upgrades/2010033101.php
index 0bffee001..4779295fd 100644
--- a/engine/lib/upgrades/2010033101.php
+++ b/engine/lib/upgrades/2010033101.php
@@ -1,7 +1,7 @@
<?php
/**
- * Conditional upgrade for UTF8 as described in http://trac.elgg.org/ticket/1928
+ * Conditional upgrade for UTF8 as described in https://github.com/elgg/elgg/issues/1928
*/
// get_version() returns the code version.
diff --git a/engine/lib/upgrades/2010052601.php b/engine/lib/upgrades/2010052601.php
index 5b477910f..a9cca6dc5 100644
--- a/engine/lib/upgrades/2010052601.php
+++ b/engine/lib/upgrades/2010052601.php
@@ -9,14 +9,14 @@ $params = array('type' => 'group',
$groups = elgg_get_entities($params);
if ($groups) {
foreach ($groups as $group) {
- $group->name = html_entity_decode($group->name, ENT_COMPAT, 'UTF-8');
- $group->description = html_entity_decode($group->description, ENT_COMPAT, 'UTF-8');
- $group->briefdescription = html_entity_decode($group->briefdescription, ENT_COMPAT, 'UTF-8');
- $group->website = html_entity_decode($group->website, ENT_COMPAT, 'UTF-8');
+ $group->name = _elgg_html_decode($group->name);
+ $group->description = _elgg_html_decode($group->description);
+ $group->briefdescription = _elgg_html_decode($group->briefdescription);
+ $group->website = _elgg_html_decode($group->website);
if ($group->interests) {
$tags = $group->interests;
- foreach ($tags as $index=>$tag) {
- $tags[$index] = html_entity_decode($tag, ENT_COMPAT, 'UTF-8');
+ foreach ($tags as $index => $tag) {
+ $tags[$index] = _elgg_html_decode($tag);
}
$group->interests = $tags;
}
diff --git a/engine/lib/upgrades/2010061501.php b/engine/lib/upgrades/2010061501.php
index 9ff7d3102..744c28fd5 100644
--- a/engine/lib/upgrades/2010061501.php
+++ b/engine/lib/upgrades/2010061501.php
@@ -45,7 +45,7 @@ if ($dbversion < 2009100701) {
}
}
- global $DB_QUERY_CACHE, $DB_PROFILE, $ENTITY_CACHE;
+ global $ENTITY_CACHE;
/**
Upgrade file locations
@@ -60,7 +60,9 @@ if ($dbversion < 2009100701) {
$users = mysql_query("SELECT guid, username FROM {$CONFIG->dbprefix}users_entity
WHERE username != ''", $link);
while ($user = mysql_fetch_object($users)) {
- $DB_QUERY_CACHE = $DB_PROFILE = $ENTITY_CACHE = array();
+ $ENTITY_CACHE = array();
+ _elgg_invalidate_query_cache();
+
$to = $CONFIG->dataroot . user_file_matrix($user->guid);
foreach (array('1_0', '1_1', '1_6') as $version) {
diff --git a/engine/lib/upgrades/2010071001.php b/engine/lib/upgrades/2010071001.php
index 1b5d379d8..5594493a8 100644
--- a/engine/lib/upgrades/2010071001.php
+++ b/engine/lib/upgrades/2010071001.php
@@ -30,11 +30,12 @@ function user_file_matrix_2010071001($guid) {
$sizes = array('large', 'medium', 'small', 'tiny', 'master', 'topbar');
-global $DB_QUERY_CACHE, $DB_PROFILE, $ENTITY_CACHE, $CONFIG;
+global $ENTITY_CACHE, $CONFIG;
$users = mysql_query("SELECT guid, username FROM {$CONFIG->dbprefix}users_entity
WHERE username != ''");
while ($user = mysql_fetch_object($users)) {
- $DB_QUERY_CACHE = $DB_PROFILE = $ENTITY_CACHE = array();
+ $ENTITY_CACHE = array();
+ _elgg_invalidate_query_cache();
$user_directory = user_file_matrix_2010071001($user->guid);
if (!$user_directory) {
diff --git a/engine/lib/upgrades/2010071002.php b/engine/lib/upgrades/2010071002.php
index 30bd6538c..52aa15ef5 100644
--- a/engine/lib/upgrades/2010071002.php
+++ b/engine/lib/upgrades/2010071002.php
@@ -4,12 +4,13 @@
*/
// loop through all users checking collections and notifications
-global $DB_QUERY_CACHE, $DB_PROFILE, $ENTITY_CACHE, $CONFIG;
+global $ENTITY_CACHE, $CONFIG;
global $NOTIFICATION_HANDLERS;
$users = mysql_query("SELECT guid, username FROM {$CONFIG->dbprefix}users_entity
WHERE username != ''");
while ($user = mysql_fetch_object($users)) {
- $DB_QUERY_CACHE = $DB_PROFILE = $ENTITY_CACHE = array();
+ $ENTITY_CACHE = array();
+ _elgg_invalidate_query_cache();
$user = get_entity($user->guid);
foreach ($NOTIFICATION_HANDLERS as $method => $foo) {
diff --git a/engine/lib/upgrades/2010121602.php b/engine/lib/upgrades/2010121602.php
index 2d55c8214..5b0996b5e 100644
--- a/engine/lib/upgrades/2010121602.php
+++ b/engine/lib/upgrades/2010121602.php
@@ -4,7 +4,7 @@
*/
$query = "UPDATE {$CONFIG->dbprefix}river
- SET view='river/annotation/generic_comment/create', action_type='create'
+ SET view='river/annotation/generic_comment/create'
WHERE view='annotation/annotate' AND action_type='comment'";
update_data($query);
diff --git a/engine/lib/upgrades/2011010101.php b/engine/lib/upgrades/2011010101.php
index 9dbaff1e4..f4411ee20 100644
--- a/engine/lib/upgrades/2011010101.php
+++ b/engine/lib/upgrades/2011010101.php
@@ -66,7 +66,7 @@ if ($old_enabled_plugins) {
// invalidate caches
elgg_invalidate_simplecache();
-elgg_filepath_cache_reset();
+elgg_reset_system_cache();
// clean up.
remove_metadata($site->guid, 'pluginorder');
@@ -87,7 +87,12 @@ if ($upgrade_version > $version) {
datalist_set('version', $upgrade_version);
}
+// add ourselves to the processed_upgrades.
+$processed_upgrades[] = '2011010101.php';
+
$processed_upgrades = array_unique($processed_upgrades);
-datalist_set('processed_upgrades', serialize($processed_upgrades));
+elgg_set_processed_upgrades($processed_upgrades);
+
+_elgg_upgrade_unlock();
forward('upgrade.php');
diff --git a/engine/lib/upgrades/2011030700-1.8_svn-blog_status_metadata-4645225d7b440876.php b/engine/lib/upgrades/2011030700-1.8_svn-blog_status_metadata-4645225d7b440876.php
index e4ab9c137..fe2af9928 100644
--- a/engine/lib/upgrades/2011030700-1.8_svn-blog_status_metadata-4645225d7b440876.php
+++ b/engine/lib/upgrades/2011030700-1.8_svn-blog_status_metadata-4645225d7b440876.php
@@ -9,7 +9,8 @@
$ia = elgg_set_ignore_access(true);
$options = array(
'type' => 'object',
- 'subtype' => 'blog'
+ 'subtype' => 'blog',
+ 'limit' => 0,
);
$batch = new ElggBatch('elgg_get_entities', $options);
diff --git a/engine/lib/upgrades/2011052801.php b/engine/lib/upgrades/2011052801.php
new file mode 100644
index 000000000..b5a8e1018
--- /dev/null
+++ b/engine/lib/upgrades/2011052801.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Make sure all users have the relationship member_of_site
+ */
+global $ENTITY_CACHE;
+$db_prefix = get_config('dbprefix');
+
+$limit = 100;
+
+$q = "SELECT e.* FROM {$db_prefix}entities e
+ WHERE e.type = 'user' AND e.guid NOT IN (
+ SELECT guid_one FROM {$db_prefix}entity_relationships
+ WHERE guid_two = 1 AND relationship = 'member_of_site'
+ )
+ LIMIT $limit";
+
+$users = get_data($q);
+
+while ($users) {
+ $ENTITY_CACHE = array();
+ _elgg_invalidate_query_cache();
+
+ // do manually to not trigger any events because these aren't new users.
+ foreach ($users as $user) {
+ $rel_q = "INSERT INTO {$db_prefix}entity_relationships VALUES (
+ '',
+ '$user->guid',
+ 'member_of_site',
+ '$user->site_guid',
+ '$user->time_created'
+ )";
+
+ insert_data($rel_q);
+ }
+
+ // every time we run this query we've just reduced the rows it returns by $limit
+ // so don't pass an offset.
+ $q = "SELECT e.* FROM {$db_prefix}entities e
+ WHERE e.type = 'user' AND e.guid NOT IN (
+ SELECT guid_one FROM {$db_prefix}entity_relationships
+ WHERE guid_two = 1 AND relationship = 'member_of_site'
+ )
+ LIMIT $limit";
+
+ $users = get_data($q);
+} \ No newline at end of file
diff --git a/engine/lib/upgrades/2011061200-1.8b1-sites_need_a_site_guid-6d9dcbf46c0826cc.php b/engine/lib/upgrades/2011061200-1.8b1-sites_need_a_site_guid-6d9dcbf46c0826cc.php
new file mode 100644
index 000000000..41ab29998
--- /dev/null
+++ b/engine/lib/upgrades/2011061200-1.8b1-sites_need_a_site_guid-6d9dcbf46c0826cc.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Elgg 1.8b1 upgrade 2011061200
+ * sites_need_a_site_guid
+ *
+ * Sites did not have a site guid. This causes problems with getting
+ * metadata on site objects since we default to the current site.
+ */
+
+global $CONFIG;
+
+$ia = elgg_set_ignore_access(true);
+$access_status = access_get_show_hidden_status();
+access_show_hidden_entities(true);
+
+$options = array(
+ 'type' => 'site',
+ 'site_guid' => 0,
+ 'limit' => 0,
+);
+$batch = new ElggBatch('elgg_get_entities', $options);
+
+foreach ($batch as $entity) {
+ if (!$entity->site_guid) {
+ update_data("UPDATE {$CONFIG->dbprefix}entities SET site_guid=$entity->guid
+ WHERE guid=$entity->guid");
+ }
+}
+
+access_show_hidden_entities($access_status);
+elgg_set_ignore_access($ia);
diff --git a/engine/lib/upgrades/2011092500-1.8.0.1-forum_reply_river_view-5758ce8d86ac56ce.php b/engine/lib/upgrades/2011092500-1.8.0.1-forum_reply_river_view-5758ce8d86ac56ce.php
new file mode 100644
index 000000000..3a9200b51
--- /dev/null
+++ b/engine/lib/upgrades/2011092500-1.8.0.1-forum_reply_river_view-5758ce8d86ac56ce.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Elgg 1.8.0.1 upgrade 2011092500
+ * forum_reply_river_view
+ *
+ * The forum reply river view is in a new location in Elgg 1.8
+ */
+
+$query = "UPDATE {$CONFIG->dbprefix}river SET view='river/annotation/group_topic_post/reply',
+ action_type='reply'
+ WHERE view='river/forum/create' AND action_type='create'";
+update_data($query);
diff --git a/engine/lib/upgrades/2011123100-1.8.2-fix_friend_river-b17e7ff8345c2269.php b/engine/lib/upgrades/2011123100-1.8.2-fix_friend_river-b17e7ff8345c2269.php
new file mode 100644
index 000000000..4dc43cd32
--- /dev/null
+++ b/engine/lib/upgrades/2011123100-1.8.2-fix_friend_river-b17e7ff8345c2269.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Elgg 1.8.2 upgrade 2011123100
+ * fix_friend_river
+ *
+ * Action type was incorrect due to previoud friends river upgrade
+ */
+
+$query = "UPDATE {$CONFIG->dbprefix}river
+ SET action_type='friend'
+ WHERE view='river/relationship/friend/create' AND action_type='create'";
+update_data($query);
diff --git a/engine/lib/upgrades/2011123101-1.8.2-fix_blog_status-b14c2a0e7b9e7d55.php b/engine/lib/upgrades/2011123101-1.8.2-fix_blog_status-b14c2a0e7b9e7d55.php
new file mode 100644
index 000000000..e351c6ac9
--- /dev/null
+++ b/engine/lib/upgrades/2011123101-1.8.2-fix_blog_status-b14c2a0e7b9e7d55.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Elgg 1.8.2 upgrade 2011123101
+ * fix_blog_status
+ *
+ * Most blog posts did not have their status properly set with 1.8 upgrade so we run
+ * the blog status upgrade again
+ */
+
+$ia = elgg_set_ignore_access(true);
+$options = array(
+ 'type' => 'object',
+ 'subtype' => 'blog',
+ 'limit' => 0,
+);
+$batch = new ElggBatch('elgg_get_entities', $options);
+
+foreach ($batch as $entity) {
+ if (!$entity->status) {
+ // create metadata owned by the original owner
+ create_metadata($entity->getGUID(), 'status', 'published', '', $entity->owner_guid,
+ $entity->access_id);
+ }
+}
+elgg_set_ignore_access($ia); \ No newline at end of file
diff --git a/engine/lib/upgrades/2012012000-1.8.3-ip_in_syslog-87fe0f068cf62428.php b/engine/lib/upgrades/2012012000-1.8.3-ip_in_syslog-87fe0f068cf62428.php
new file mode 100644
index 000000000..b9514e156
--- /dev/null
+++ b/engine/lib/upgrades/2012012000-1.8.3-ip_in_syslog-87fe0f068cf62428.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Elgg 1.8.3 upgrade 2012012000
+ * ip_in_syslog
+ *
+ * Adds a field for an IP address in the system log table
+ */
+
+$db_prefix = elgg_get_config('dbprefix');
+$q = "ALTER TABLE {$db_prefix}system_log ADD ip_address VARCHAR(15) NOT NULL AFTER time_created";
+
+update_data($q); \ No newline at end of file
diff --git a/engine/lib/upgrades/2012012100-1.8.3-system_cache-93100e7d55a24a11.php b/engine/lib/upgrades/2012012100-1.8.3-system_cache-93100e7d55a24a11.php
new file mode 100644
index 000000000..3a9aae2a1
--- /dev/null
+++ b/engine/lib/upgrades/2012012100-1.8.3-system_cache-93100e7d55a24a11.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Elgg 1.8.3 upgrade 2012012100
+ * system_cache
+ *
+ * Convert viewpath cache to system cache
+ */
+
+$value = datalist_get('viewpath_cache_enabled');
+datalist_set('system_cache_enabled', $value);
+
+$query = "DELETE FROM {$CONFIG->dbprefix}datalists WHERE name='viewpath_cache_enabled'";
+delete_data($query);
diff --git a/engine/lib/upgrades/2012041800-1.8.3-dont_filter_passwords-c0ca4a18b38ae2bc.php b/engine/lib/upgrades/2012041800-1.8.3-dont_filter_passwords-c0ca4a18b38ae2bc.php
new file mode 100644
index 000000000..b82ffbebf
--- /dev/null
+++ b/engine/lib/upgrades/2012041800-1.8.3-dont_filter_passwords-c0ca4a18b38ae2bc.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Elgg 1.8.3 upgrade 2012041800
+ * dont_filter_passwords
+ *
+ * Add admin notice that password handling has changed and if
+ * users can't login to have them reset their passwords.
+ */
+elgg_add_admin_notice('dont_filter_passwords', 'Password handling has been updated to be more secure and flexible. '
+ . 'This change may prevent a small number of users from logging in with their existing passwords. '
+ . 'If a user is unable to log in, please advise him or her to reset their password, or reset it as an admin user.');
diff --git a/engine/lib/upgrades/2012041801-1.8.3-multiple_user_tokens-852225f7fd89f6c5.php b/engine/lib/upgrades/2012041801-1.8.3-multiple_user_tokens-852225f7fd89f6c5.php
new file mode 100644
index 000000000..780038c32
--- /dev/null
+++ b/engine/lib/upgrades/2012041801-1.8.3-multiple_user_tokens-852225f7fd89f6c5.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Elgg 1.8.3 upgrade 2012041801
+ * multiple_user_tokens
+ *
+ * Fixes https://github.com/elgg/elgg/issues/4291
+ * Removes the unique index on users_apisessions for user_guid and site_guid
+ */
+
+$db_prefix = elgg_get_config('dbprefix');
+$q = "ALTER TABLE {$db_prefix}users_apisessions DROP INDEX user_guid,
+ ADD INDEX user_guid (user_guid, site_guid)";
+update_data($q); \ No newline at end of file
diff --git a/engine/lib/upgrades/2013030600-1.8.13-update_user_location-8999eb8bf1bdd9a3.php b/engine/lib/upgrades/2013030600-1.8.13-update_user_location-8999eb8bf1bdd9a3.php
new file mode 100644
index 000000000..8eccf05e2
--- /dev/null
+++ b/engine/lib/upgrades/2013030600-1.8.13-update_user_location-8999eb8bf1bdd9a3.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Elgg 1.8.14 upgrade 2013030600
+ * update_user_location
+ *
+ * Before Elgg 1.8, a location like "London, England" would be stored as an array.
+ * This script turns that back into a string.
+ */
+
+$ia = elgg_set_ignore_access(true);
+$options = array(
+ 'type' => 'user',
+ 'limit' => 0,
+);
+$batch = new ElggBatch('elgg_get_entities', $options);
+
+foreach ($batch as $entity) {
+ _elgg_invalidate_query_cache();
+
+ if (is_array($entity->location)) {
+ $entity->location = implode(', ', $entity->location);
+ }
+}
+elgg_set_ignore_access($ia);
diff --git a/engine/lib/upgrades/2013051700-1.8.15-add_missing_group_index-52a63a3a3ffaced2.php b/engine/lib/upgrades/2013051700-1.8.15-add_missing_group_index-52a63a3a3ffaced2.php
new file mode 100644
index 000000000..ee99bdbc8
--- /dev/null
+++ b/engine/lib/upgrades/2013051700-1.8.15-add_missing_group_index-52a63a3a3ffaced2.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Elgg 1.8.15 upgrade 2013051700
+ * add_missing_group_index
+ *
+ * Some Elgg sites are missing the groups_entity full text index on name and
+ * description. This checks if it exists and adds it if it does not.
+ */
+
+$db_prefix = elgg_get_config('dbprefix');
+
+$full_text_index_exists = false;
+$results = get_data("SHOW INDEX FROM {$db_prefix}groups_entity");
+if ($results) {
+ foreach ($results as $result) {
+ if ($result->Index_type === 'FULLTEXT') {
+ $full_text_index_exists = true;
+ }
+ }
+}
+
+if ($full_text_index_exists == false) {
+ $query = "ALTER TABLE {$db_prefix}groups_entity
+ ADD FULLTEXT name_2 (name, description)";
+ if (!update_data($query)) {
+ elgg_log("Failed to add full text index to groups_entity table", 'ERROR');
+ }
+}
diff --git a/engine/lib/upgrades/2013052900-1.8.15-ipv6_in_syslog-f5c2cc0196e9e731.php b/engine/lib/upgrades/2013052900-1.8.15-ipv6_in_syslog-f5c2cc0196e9e731.php
new file mode 100644
index 000000000..d333a6cd2
--- /dev/null
+++ b/engine/lib/upgrades/2013052900-1.8.15-ipv6_in_syslog-f5c2cc0196e9e731.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Elgg 1.8.15 upgrade 2013052900
+ * ipv6_in_syslog
+ *
+ * Upgrade the ip column in system_log to be able to store ipv6 addresses
+ */
+
+$db_prefix = elgg_get_config('dbprefix');
+$q = "ALTER TABLE {$db_prefix}system_log MODIFY COLUMN ip_address varchar(46) NOT NULL";
+
+update_data($q); \ No newline at end of file
diff --git a/engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php b/engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php
new file mode 100644
index 000000000..538d74dd6
--- /dev/null
+++ b/engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Elgg 1.8.15 upgrade 2013060900
+ * site_secret
+ *
+ * Description
+ */
+
+$strength = _elgg_get_site_secret_strength();
+
+if ($strength !== 'strong') {
+ // a new key is needed immediately
+ register_translations(elgg_get_root_path() . 'languages/');
+
+ elgg_add_admin_notice('weak_site_key', elgg_echo("upgrade:site_secret_warning:$strength"));
+}
diff --git a/engine/lib/upgrades/create_upgrade.php b/engine/lib/upgrades/create_upgrade.php
index 3652e18a2..b34f31b7e 100644
--- a/engine/lib/upgrades/create_upgrade.php
+++ b/engine/lib/upgrades/create_upgrade.php
@@ -93,7 +93,7 @@ if (!$h) {
die("Could not open file $upgrade_file");
}
-if (!fputs($h, $upgrade_code)) {
+if (!fwrite($h, $upgrade_code)) {
die("Could not write to $upgrade_file");
} else {
elgg_set_version_dot_php_version($upgrade_version);
@@ -128,8 +128,9 @@ function elgg_set_version_dot_php_version($version) {
rewind($h);
- fputs($h, $out);
+ fwrite($h, $out);
fclose($h);
+ return true;
}
/**
diff --git a/engine/lib/user_settings.php b/engine/lib/user_settings.php
index 29415f6ba..0e36dc46d 100644
--- a/engine/lib/user_settings.php
+++ b/engine/lib/user_settings.php
@@ -15,6 +15,7 @@
* @note This is a handler for the 'usersettings:save', 'user' plugin hook
*
* @return void
+ * @access private
*/
function users_settings_save() {
elgg_set_user_language();
@@ -29,20 +30,21 @@ function users_settings_save() {
*
* @return bool
* @since 1.8.0
+ * @access private
*/
function elgg_set_user_password() {
- $current_password = get_input('current_password');
- $password = get_input('password');
- $password2 = get_input('password2');
- $user_id = get_input('guid');
+ $current_password = get_input('current_password', null, false);
+ $password = get_input('password', null, false);
+ $password2 = get_input('password2', null, false);
+ $user_guid = get_input('guid');
- if (!$user_id) {
+ if (!$user_guid) {
$user = elgg_get_logged_in_user_entity();
} else {
- $user = get_entity($user_id);
+ $user = get_entity($user_guid);
}
- if (($user) && ($password != "")) {
+ if ($user && $password) {
// let admin user change anyone's password without knowing it except his own.
if (!elgg_is_admin_logged_in() || elgg_is_admin_logged_in() && $user->guid == elgg_get_logged_in_user_guid()) {
$credentials = array(
@@ -50,13 +52,22 @@ function elgg_set_user_password() {
'password' => $current_password
);
- if (!pam_auth_userpass($credentials)) {
- register_error(elgg_echo('user:password:fail:incorrect_current_password'));
+ try {
+ pam_auth_userpass($credentials);
+ } catch (LoginException $e) {
+ register_error(elgg_echo('LoginException:ChangePasswordFailure'));
return false;
}
}
- if (strlen($password) >= 4) {
+ try {
+ $result = validate_password($password);
+ } catch (RegistrationException $e) {
+ register_error($e->getMessage());
+ return false;
+ }
+
+ if ($result) {
if ($password == $password2) {
$user->salt = generate_random_cleartext_password(); // Reset the salt
$user->password = generate_user_password($user, $password);
@@ -76,6 +87,7 @@ function elgg_set_user_password() {
// no change
return null;
}
+
return false;
}
@@ -84,6 +96,7 @@ function elgg_set_user_password() {
*
* @return bool
* @since 1.8.0
+ * @access private
*/
function elgg_set_user_name() {
$name = strip_tags(get_input('name'));
@@ -124,6 +137,7 @@ function elgg_set_user_name() {
*
* @return bool
* @since 1.8.0
+ * @access private
*/
function elgg_set_user_language() {
$language = get_input('language');
@@ -159,6 +173,7 @@ function elgg_set_user_language() {
*
* @return bool
* @since 1.8.0
+ * @access private
*/
function elgg_set_user_email() {
$email = get_input('email');
@@ -206,6 +221,7 @@ function elgg_set_user_email() {
*
* @return bool
* @since 1.8.0
+ * @access private
*/
function elgg_set_user_default_access() {
@@ -246,11 +262,12 @@ function elgg_set_user_default_access() {
* Set up the menu for user settings
*
* @return void
+ * @access private
*/
function usersettings_pagesetup() {
- if (elgg_get_context() == "settings" && elgg_get_logged_in_user_guid()) {
- $user = elgg_get_logged_in_user_entity();
+ $user = elgg_get_page_owner_entity();
+ if ($user && elgg_get_context() == "settings") {
$params = array(
'name' => '1_account',
'text' => elgg_echo('usersettings:user:opt:linktext'),
@@ -277,7 +294,8 @@ function usersettings_pagesetup() {
*
* @param array $page Pages array
*
- * @return void
+ * @return bool
+ * @access private
*/
function usersettings_page_handler($page) {
global $CONFIG;
@@ -286,11 +304,11 @@ function usersettings_page_handler($page) {
$page[0] = 'user';
}
- if ($page[1]) {
+ if (isset($page[1])) {
$user = get_user_by_username($page[1]);
elgg_set_page_owner_guid($user->guid);
} else {
- $user = elgg_get_logged_in_user_guid();
+ $user = elgg_get_logged_in_user_entity();
elgg_set_page_owner_guid($user->guid);
}
@@ -306,18 +324,22 @@ function usersettings_page_handler($page) {
$path = $CONFIG->path . "pages/settings/tools.php";
break;
case 'user':
- default:
$path = $CONFIG->path . "pages/settings/account.php";
break;
}
- require($path);
+ if (isset($path)) {
+ require $path;
+ return true;
+ }
+ return false;
}
/**
* Initialize the user settings library
*
* @return void
+ * @access private
*/
function usersettings_init() {
elgg_register_page_handler('settings', 'usersettings_page_handler');
@@ -325,8 +347,14 @@ function usersettings_init() {
elgg_register_plugin_hook_handler('usersettings:save', 'user', 'users_settings_save');
elgg_register_action("usersettings/save");
+
+ // extend the account settings form
+ elgg_extend_view('forms/account/settings', 'core/settings/account/name', 100);
+ elgg_extend_view('forms/account/settings', 'core/settings/account/password', 100);
+ elgg_extend_view('forms/account/settings', 'core/settings/account/email', 100);
+ elgg_extend_view('forms/account/settings', 'core/settings/account/language', 100);
+ elgg_extend_view('forms/account/settings', 'core/settings/account/default_access', 100);
}
-/// Register init function
elgg_register_event_handler('init', 'system', 'usersettings_init');
elgg_register_event_handler('pagesetup', 'system', 'usersettings_pagesetup');
diff --git a/engine/lib/users.php b/engine/lib/users.php
index dcec36ba5..a8fb9121c 100644
--- a/engine/lib/users.php
+++ b/engine/lib/users.php
@@ -21,6 +21,7 @@ $CODE_TO_GUID_MAP_CACHE = array();
* @param int $guid The ElggUser guid
*
* @return mixed
+ * @access private
*/
function get_user_entity_as_row($guid) {
global $CONFIG;
@@ -43,6 +44,7 @@ function get_user_entity_as_row($guid) {
* @param string $code A code
*
* @return bool
+ * @access private
*/
function create_user_entity($guid, $name, $username, $password, $salt, $email, $language, $code) {
global $CONFIG;
@@ -59,13 +61,12 @@ function create_user_entity($guid, $name, $username, $password, $salt, $email, $
$row = get_entity_as_row($guid);
if ($row) {
// Exists and you have access to it
-
$query = "SELECT guid from {$CONFIG->dbprefix}users_entity where guid = {$guid}";
if ($exists = get_data_row($query)) {
$query = "UPDATE {$CONFIG->dbprefix}users_entity
- set name='$name', username='$username', password='$password', salt='$salt',
- email='$email', language='$language', code='$code', last_action = "
- . time() . " where guid = {$guid}";
+ SET name='$name', username='$username', password='$password', salt='$salt',
+ email='$email', language='$language', code='$code'
+ WHERE guid = $guid";
$result = update_data($query);
if ($result != false) {
@@ -78,7 +79,7 @@ function create_user_entity($guid, $name, $username, $password, $salt, $email, $
}
}
} else {
- // Update failed, attempt an insert.
+ // Exists query failed, attempt an insert.
$query = "INSERT into {$CONFIG->dbprefix}users_entity
(guid, name, username, password, salt, email, language, code)
values ($guid, '$name', '$username', '$password', '$salt', '$email', '$language', '$code')";
@@ -89,7 +90,7 @@ function create_user_entity($guid, $name, $username, $password, $salt, $email, $
if (elgg_trigger_event('create', $entity->type, $entity)) {
return $guid;
} else {
- $entity->delete(); //delete_entity($guid);
+ $entity->delete();
}
}
}
@@ -136,7 +137,6 @@ function ban_user($user_guid, $reason = "") {
global $CONFIG;
$user_guid = (int)$user_guid;
- $reason = sanitise_string($reason);
$user = get_entity($user_guid);
@@ -237,7 +237,7 @@ function make_user_admin($user_guid) {
}
$r = update_data("UPDATE {$CONFIG->dbprefix}users_entity set admin='yes' where guid=$user_guid");
- invalidate_cache_for_entity($user_guid);
+ _elgg_invalidate_cache_for_entity($user_guid);
return $r;
}
@@ -273,7 +273,7 @@ function remove_user_admin($user_guid) {
}
$r = update_data("UPDATE {$CONFIG->dbprefix}users_entity set admin='no' where guid=$user_guid");
- invalidate_cache_for_entity($user_guid);
+ _elgg_invalidate_cache_for_entity($user_guid);
return $r;
}
@@ -290,7 +290,7 @@ function remove_user_admin($user_guid) {
* @param int $limit Number of results to return
* @param int $offset Any indexing offset
*
- * @return false|array On success, an array of ElggSites
+ * @return ElggSite[]|false On success, an array of ElggSites
*/
function get_user_sites($user_guid, $limit = 10, $offset = 0) {
$user_guid = (int)$user_guid;
@@ -298,13 +298,14 @@ function get_user_sites($user_guid, $limit = 10, $offset = 0) {
$offset = (int)$offset;
return elgg_get_entities_from_relationship(array(
+ 'site_guids' => ELGG_ENTITIES_ANY_VALUE,
'relationship' => 'member_of_site',
'relationship_guid' => $user_guid,
'inverse_relationship' => FALSE,
- 'types' => 'site',
+ 'type' => 'site',
'limit' => $limit,
- 'offset' => $offset)
- );
+ 'offset' => $offset,
+ ));
}
/**
@@ -342,8 +343,6 @@ function user_add_friend($user_guid, $friend_guid) {
* @return bool Depending on success
*/
function user_remove_friend($user_guid, $friend_guid) {
- global $CONFIG;
-
$user_guid = (int) $user_guid;
$friend_guid = (int) $friend_guid;
@@ -378,7 +377,7 @@ function user_is_friend($user_guid, $friend_guid) {
* @param int $limit Number of results to return (default 10)
* @param int $offset Indexing offset, if any
*
- * @return false|array Either an array of ElggUsers or false, depending on success
+ * @return ElggUser[]|false Either an array of ElggUsers or false, depending on success
*/
function get_user_friends($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10,
$offset = 0) {
@@ -386,8 +385,8 @@ $offset = 0) {
return elgg_get_entities_from_relationship(array(
'relationship' => 'friend',
'relationship_guid' => $user_guid,
- 'types' => 'user',
- 'subtypes' => $subtype,
+ 'type' => 'user',
+ 'subtype' => $subtype,
'limit' => $limit,
'offset' => $offset
));
@@ -401,7 +400,7 @@ $offset = 0) {
* @param int $limit Number of results to return (default 10)
* @param int $offset Indexing offset, if any
*
- * @return false|array Either an array of ElggUsers or false, depending on success
+ * @return ElggUser[]|false Either an array of ElggUsers or false, depending on success
*/
function get_user_friends_of($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10,
$offset = 0) {
@@ -410,8 +409,8 @@ $offset = 0) {
'relationship' => 'friend',
'relationship_guid' => $user_guid,
'inverse_relationship' => TRUE,
- 'types' => 'user',
- 'subtypes' => $subtype,
+ 'type' => 'user',
+ 'subtype' => $subtype,
'limit' => $limit,
'offset' => $offset
));
@@ -427,7 +426,7 @@ $offset = 0) {
* @param int $timelower The earliest time the entity can have been created. Default: all
* @param int $timeupper The latest time the entity can have been created. Default: all
*
- * @return false|array An array of ElggObjects or false, depending on success
+ * @return ElggObject[]|false An array of ElggObjects or false, depending on success
*/
function get_user_friends_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10,
$offset = 0, $timelower = 0, $timeupper = 0) {
@@ -496,20 +495,26 @@ $timelower = 0, $timeupper = 0) {
* @param int $timelower The earliest time the entity can have been created. Default: all
* @param int $timeupper The latest time the entity can have been created. Default: all
*
- * @return string The list in a form suitable to display
+ * @return string
*/
function list_user_friends_objects($user_guid, $subtype = "", $limit = 10, $full_view = true,
$listtypetoggle = true, $pagination = true, $timelower = 0, $timeupper = 0) {
- $offset = (int) get_input('offset');
- $limit = (int) $limit;
- $count = (int) count_user_friends_objects($user_guid, $subtype, $timelower, $timeupper);
+ $offset = (int)get_input('offset');
+ $limit = (int)$limit;
+ $count = (int)count_user_friends_objects($user_guid, $subtype, $timelower, $timeupper);
$entities = get_user_friends_objects($user_guid, $subtype, $limit, $offset,
$timelower, $timeupper);
- return elgg_view_entity_list($entities, $count, $offset, $limit, $full_view,
- $listtypetoggle, $pagination);
+ return elgg_view_entity_list($entities, array(
+ 'count' => $count,
+ 'offset' => $offset,
+ 'limit' => $limit,
+ 'full_view' => $full_view,
+ 'list_type_toggle' => $listtypetoggle,
+ 'pagination' => $pagination,
+ ));
}
/**
@@ -548,13 +553,18 @@ function get_user($guid) {
function get_user_by_username($username) {
global $CONFIG, $USERNAME_TO_GUID_MAP_CACHE;
+ // Fixes #6052. Username is frequently sniffed from the path info, which,
+ // unlike $_GET, is not URL decoded. If the username was not URL encoded,
+ // this is harmless.
+ $username = rawurldecode($username);
+
$username = sanitise_string($username);
$access = get_access_sql_suffix('e');
// Caching
if ((isset($USERNAME_TO_GUID_MAP_CACHE[$username]))
- && (retrieve_cached_entity($USERNAME_TO_GUID_MAP_CACHE[$username]))) {
- return retrieve_cached_entity($USERNAME_TO_GUID_MAP_CACHE[$username]);
+ && (_elgg_retrieve_cached_entity($USERNAME_TO_GUID_MAP_CACHE[$username]))) {
+ return _elgg_retrieve_cached_entity($USERNAME_TO_GUID_MAP_CACHE[$username]);
}
$query = "SELECT e.* from {$CONFIG->dbprefix}users_entity u
@@ -564,6 +574,8 @@ function get_user_by_username($username) {
$entity = get_data_row($query, 'entity_row_to_elggstar');
if ($entity) {
$USERNAME_TO_GUID_MAP_CACHE[$username] = $entity->guid;
+ } else {
+ $entity = false;
}
return $entity;
@@ -585,9 +597,9 @@ function get_user_by_code($code) {
// Caching
if ((isset($CODE_TO_GUID_MAP_CACHE[$code]))
- && (retrieve_cached_entity($CODE_TO_GUID_MAP_CACHE[$code]))) {
+ && (_elgg_retrieve_cached_entity($CODE_TO_GUID_MAP_CACHE[$code]))) {
- return retrieve_cached_entity($CODE_TO_GUID_MAP_CACHE[$code]);
+ return _elgg_retrieve_cached_entity($CODE_TO_GUID_MAP_CACHE[$code]);
}
$query = "SELECT e.* from {$CONFIG->dbprefix}users_entity u
@@ -603,11 +615,11 @@ function get_user_by_code($code) {
}
/**
- * Get an array of users from their email addresses
+ * Get an array of users from an email address
*
* @param string $email Email address.
*
- * @return Array of users
+ * @return array
*/
function get_user_by_email($email) {
global $CONFIG;
@@ -625,31 +637,37 @@ function get_user_by_email($email) {
/**
* A function that returns a maximum of $limit users who have done something within the last
- * $seconds seconds.
+ * $seconds seconds or the total count of active users.
*
- * @param int $seconds Number of seconds (default 600 = 10min)
- * @param int $limit Limit, default 10.
- * @param int $offset Offset, defualt 0.
+ * @param int $seconds Number of seconds (default 600 = 10min)
+ * @param int $limit Limit, default 10.
+ * @param int $offset Offset, default 0.
+ * @param bool $count Count, default false.
*
* @return mixed
*/
-function find_active_users($seconds = 600, $limit = 10, $offset = 0) {
- global $CONFIG;
-
+function find_active_users($seconds = 600, $limit = 10, $offset = 0, $count = false) {
$seconds = (int)$seconds;
$limit = (int)$limit;
$offset = (int)$offset;
+ $params = array('seconds' => $seconds, 'limit' => $limit, 'offset' => $offset, 'count' => $count);
+ $data = elgg_trigger_plugin_hook('find_active_users', 'system', $params, NULL);
+ if (!$data) {
+ global $CONFIG;
- $time = time() - $seconds;
-
- $access = get_access_sql_suffix("e");
+ $time = time() - $seconds;
- $query = "SELECT distinct e.* from {$CONFIG->dbprefix}entities e
- join {$CONFIG->dbprefix}users_entity u on e.guid = u.guid
- where u.last_action >= {$time} and $access
- order by u.last_action desc limit {$offset}, {$limit}";
-
- return get_data($query, "entity_row_to_elggstar");
+ $data = elgg_get_entities(array(
+ 'type' => 'user',
+ 'limit' => $limit,
+ 'offset' => $offset,
+ 'count' => $count,
+ 'joins' => array("join {$CONFIG->dbprefix}users_entity u on e.guid = u.guid"),
+ 'wheres' => array("u.last_action >= {$time}"),
+ 'order_by' => "u.last_action desc"
+ ));
+ }
+ return $data;
}
/**
@@ -660,25 +678,22 @@ function find_active_users($seconds = 600, $limit = 10, $offset = 0) {
* @return bool
*/
function send_new_password_request($user_guid) {
- global $CONFIG;
-
$user_guid = (int)$user_guid;
$user = get_entity($user_guid);
- if ($user) {
+ if ($user instanceof ElggUser) {
// generate code
$code = generate_random_cleartext_password();
$user->setPrivateSetting('passwd_conf_code', $code);
-
// generate link
- $link = $CONFIG->site->url . "resetpassword?u=$user_guid&c=$code";
+ $link = elgg_get_site_url() . "resetpassword?u=$user_guid&c=$code";
// generate email
$email = elgg_echo('email:resetreq:body', array($user->name, $_SERVER['REMOTE_ADDR'], $link));
- return notify_user($user->guid, $CONFIG->site->guid,
- elgg_echo('email:resetreq:subject'), $email, NULL, 'email');
+ return notify_user($user->guid, elgg_get_site_entity()->guid,
+ elgg_echo('email:resetreq:subject'), $email, array(), 'email');
}
return false;
@@ -695,19 +710,18 @@ function send_new_password_request($user_guid) {
* @return bool
*/
function force_user_password_reset($user_guid, $password) {
- global $CONFIG;
-
$user = get_entity($user_guid);
+ if ($user instanceof ElggUser) {
+ $ia = elgg_set_ignore_access();
- if ($user) {
- $salt = generate_random_cleartext_password(); // Reset the salt
- $user->salt = $salt;
+ $user->salt = generate_random_cleartext_password();
+ $hash = generate_user_password($user, $password);
+ $user->password = $hash;
+ $result = (bool)$user->save();
- $hash = generate_user_password($user, $password);
+ elgg_set_ignore_access($ia);
- $query = "UPDATE {$CONFIG->dbprefix}users_entity
- set password='$hash', salt='$salt' where guid=$user_guid";
- return update_data($query);
+ return $result;
}
return false;
@@ -727,7 +741,7 @@ function execute_new_password_request($user_guid, $conf_code) {
$user_guid = (int)$user_guid;
$user = get_entity($user_guid);
- if ($user) {
+ if ($user instanceof ElggUser) {
$saved_code = $user->getPrivateSetting('passwd_conf_code');
if ($saved_code && $saved_code == $conf_code) {
@@ -735,11 +749,13 @@ function execute_new_password_request($user_guid, $conf_code) {
if (force_user_password_reset($user_guid, $password)) {
remove_private_setting($user_guid, 'passwd_conf_code');
-
+ // clean the logins failures
+ reset_login_failure_count($user_guid);
+
$email = elgg_echo('email:resetpassword:body', array($user->name, $password));
return notify_user($user->guid, $CONFIG->site->guid,
- elgg_echo('email:resetpassword:subject'), $email, NULL, 'email');
+ elgg_echo('email:resetpassword:subject'), $email, array(), 'email');
}
}
}
@@ -748,40 +764,6 @@ function execute_new_password_request($user_guid, $conf_code) {
}
/**
- * Handles pages for password reset requests.
- *
- * @param array $page Pages array
- *
- * @return void
- */
-function elgg_user_resetpassword_page_handler($page) {
-
- $user_guid = get_input('u');
- $code = get_input('c');
-
- $user = get_entity($user_guid);
-
- // don't check code here to avoid automated attacks
- if (!$user instanceof ElggUser) {
- register_error(elgg_echo('user:passwordreset:unknown_user'));
- forward();
- }
-
- $params = array(
- 'guid' => $user_guid,
- 'code' => $code,
- );
- $form = elgg_view_form('user/passwordreset', array(), $params);
-
- $title = elgg_echo('resetpassword');
- $content = elgg_view_title(elgg_echo('resetpassword')) . $form;
-
- $body = elgg_view_layout('one_column', array('content' => $content));
-
- echo elgg_view_page($title, $body);
-}
-
-/**
* Simple function that will generate a random clear text password
* suitable for feeding into generate_user_password().
*
@@ -827,6 +809,12 @@ function validate_username($username) {
$msg = elgg_echo('registration:usernametooshort', array($CONFIG->minusername));
throw new RegistrationException($msg);
}
+
+ // username in the database has a limit of 128 characters
+ if (strlen($username) > 128) {
+ $msg = elgg_echo('registration:usernametoolong', array(128));
+ throw new RegistrationException($msg);
+ }
// Blacklist for bad characters (partially nicked from mediawiki)
$blacklist = '/[' .
@@ -841,6 +829,7 @@ function validate_username($username) {
if (
preg_match($blacklist, $username)
) {
+ // @todo error message needs work
throw new RegistrationException(elgg_echo('registration:invalidchars'));
}
@@ -851,6 +840,7 @@ function validate_username($username) {
for ($n = 0; $n < strlen($blacklist2); $n++) {
if (strpos($username, $blacklist2[$n]) !== false) {
$msg = elgg_echo('registration:invalidchars', array($blacklist2[$n], $blacklist2));
+ $msg = htmlspecialchars($msg, ENT_QUOTES, 'UTF-8');
throw new RegistrationException($msg);
}
}
@@ -917,13 +907,11 @@ function validate_email_address($address) {
* @param string $invitecode An invite code from a friend
*
* @return int|false The new user's GUID; false on failure
+ * @throws RegistrationException
*/
function register_user($username, $password, $name, $email,
$allow_multiple_emails = false, $friend_guid = 0, $invitecode = '') {
- // Load the configuration
- global $CONFIG;
-
// no need to trim password.
$username = trim($username);
$name = trim(strip_tags($name));
@@ -973,6 +961,7 @@ $allow_multiple_emails = false, $friend_guid = 0, $invitecode = '') {
$user->password = generate_user_password($user, $password);
$user->owner_guid = 0; // Users aren't owned by anyone, even if they are admin created.
$user->container_guid = 0; // Users aren't contained by anyone, even if they are admin created.
+ $user->language = get_current_language();
$user->save();
// If $friend_guid has been set, make mutual friends
@@ -983,8 +972,8 @@ $allow_multiple_emails = false, $friend_guid = 0, $invitecode = '') {
$friend_user->addFriend($user->guid);
// @todo Should this be in addFriend?
- add_to_river('friends/river/create', 'friend', $user->getGUID(), $friend_guid);
- add_to_river('friends/river/create', 'friend', $friend_guid, $user->getGUID());
+ add_to_river('river/relationship/friend/create', 'friend', $user->getGUID(), $friend_guid);
+ add_to_river('river/relationship/friend/create', 'friend', $friend_guid, $user->getGUID());
}
}
}
@@ -1039,10 +1028,10 @@ function elgg_get_user_validation_status($user_guid) {
'metadata_name' => 'validated'
));
if ($md == false) {
- return;
+ return null;
}
- if ($md->value) {
+ if ($md[0]->value) {
return true;
}
@@ -1053,6 +1042,7 @@ function elgg_get_user_validation_status($user_guid) {
* Adds collection submenu items
*
* @return void
+ * @access private
*/
function collections_submenu_items() {
@@ -1066,38 +1056,35 @@ function collections_submenu_items() {
}
/**
- * Page handler for friends
+ * Page handler for friends-related pages
*
- * @param array $page_elements Page elements
+ * @param array $segments URL segments
+ * @param string $handler The first segment in URL used for routing
*
- * @return void
+ * @return bool
+ * @access private
*/
-function friends_page_handler($page_elements) {
- if (isset($page_elements[0]) && $user = get_user_by_username($page_elements[0])) {
- set_page_owner($user->getGUID());
+function friends_page_handler($segments, $handler) {
+ elgg_set_context('friends');
+
+ if (isset($segments[0]) && $user = get_user_by_username($segments[0])) {
+ elgg_set_page_owner_guid($user->getGUID());
}
if (elgg_get_logged_in_user_guid() == elgg_get_page_owner_guid()) {
collections_submenu_items();
}
- require_once(dirname(dirname(dirname(__FILE__))) . "/pages/friends/index.php");
-}
-/**
- * Page handler for friends of
- *
- * @param array $page_elements Page elements
- *
- * @return void
- */
-function friends_of_page_handler($page_elements) {
- elgg_set_context('friends');
- if (isset($page_elements[0]) && $user = get_user_by_username($page_elements[0])) {
- set_page_owner($user->getGUID());
+ switch ($handler) {
+ case 'friends':
+ require_once(dirname(dirname(dirname(__FILE__))) . "/pages/friends/index.php");
+ break;
+ case 'friendsof':
+ require_once(dirname(dirname(dirname(__FILE__))) . "/pages/friends/of.php");
+ break;
+ default:
+ return false;
}
- if (elgg_get_logged_in_user_guid() == elgg_get_page_owner_guid()) {
- collections_submenu_items();
- }
- require_once(dirname(dirname(dirname(__FILE__))) . "/pages/friends/of.php");
+ return true;
}
/**
@@ -1105,65 +1092,63 @@ function friends_of_page_handler($page_elements) {
*
* @param array $page_elements Page elements
*
- * @return void
+ * @return bool
+ * @access private
*/
function collections_page_handler($page_elements) {
+ gatekeeper();
elgg_set_context('friends');
$base = elgg_get_config('path');
if (isset($page_elements[0])) {
if ($page_elements[0] == "add") {
- set_page_owner(elgg_get_logged_in_user_guid());
+ elgg_set_page_owner_guid(elgg_get_logged_in_user_guid());
collections_submenu_items();
require_once "{$base}pages/friends/collections/add.php";
+ return true;
} else {
$user = get_user_by_username($page_elements[0]);
if ($user) {
- set_page_owner($user->getGUID());
+ elgg_set_page_owner_guid($user->getGUID());
if (elgg_get_logged_in_user_guid() == elgg_get_page_owner_guid()) {
collections_submenu_items();
}
require_once "{$base}pages/friends/collections/view.php";
+ return true;
}
}
}
+ return false;
}
/**
- * Page handler for dashboard
- *
- * @param array $page_elements Page elements
- *
- * @return void
- */
-function dashboard_page_handler($page_elements) {
- require_once(dirname(dirname(dirname(__FILE__))) . "/pages/dashboard.php");
-}
-
-
-/**
- * Page handler for registration
- *
- * @param array $page_elements Page elements
- *
- * @return void
- */
-function registration_page_handler($page_elements) {
- require_once(dirname(dirname(dirname(__FILE__))) . "/pages/account/register.php");
-}
-
-/**
- * Display a login box.
+ * Page handler for account related pages
*
- * This is a fallback for non-JS users who click on the
- * dropdown login link.
+ * @param array $page_elements Page elements
+ * @param string $handler The handler string
*
- * @return void
- * @todo finish
+ * @return bool
+ * @access private
*/
-function elgg_user_login_page_handler() {
- $login_box = elgg_view('core/account/login_box');
- $content = elgg_view_layout('one_column', array('content' => $login_box));
- echo elgg_view_page(elgg_echo('login'), $content);
+function elgg_user_account_page_handler($page_elements, $handler) {
+
+ $base_dir = elgg_get_root_path() . 'pages/account';
+ switch ($handler) {
+ case 'login':
+ require_once("$base_dir/login.php");
+ break;
+ case 'forgotpassword':
+ require_once("$base_dir/forgotten_password.php");
+ break;
+ case 'resetpassword':
+ require_once("$base_dir/reset_password.php");
+ break;
+ case 'register':
+ require_once("$base_dir/register.php");
+ break;
+ default:
+ return false;
+ }
+ return true;
}
/**
@@ -1190,7 +1175,7 @@ function set_last_action($user_guid) {
*
* @param int $user_guid The user GUID
*
- * @return boid
+ * @return void
*/
function set_last_login($user_guid) {
$user_guid = (int) $user_guid;
@@ -1210,12 +1195,11 @@ function set_last_login($user_guid) {
* @param string $object_type user
* @param ElggUser $object User object
*
- * @return bool
+ * @return void
+ * @access private
*/
function user_create_hook_add_site_relationship($event, $object_type, $object) {
- global $CONFIG;
-
- add_entity_relationship($object->getGUID(), 'member_of_site', $CONFIG->site->getGUID());
+ add_entity_relationship($object->getGUID(), 'member_of_site', elgg_get_site_entity()->guid);
}
/**
@@ -1226,6 +1210,7 @@ function user_create_hook_add_site_relationship($event, $object_type, $object) {
* @param string $returnvalue
* @param array $params
* @return string
+ * @access private
*/
function user_avatar_hook($hook, $entity_type, $returnvalue, $params) {
$user = $params['entity'];
@@ -1240,21 +1225,25 @@ function user_avatar_hook($hook, $entity_type, $returnvalue, $params) {
/**
* Setup the default user hover menu
+ * @access private
*/
function elgg_user_hover_menu($hook, $type, $return, $params) {
$user = $params['entity'];
+ /* @var ElggUser $user */
if (elgg_is_logged_in()) {
if (elgg_get_logged_in_user_guid() != $user->guid) {
if ($user->isFriend()) {
$url = "action/friends/remove?friend={$user->guid}";
$text = elgg_echo('friend:remove');
+ $name = 'remove_friend';
} else {
$url = "action/friends/add?friend={$user->guid}";
$text = elgg_echo('friend:add');
+ $name = 'add_friend';
}
$url = elgg_add_action_tokens_to_url($url);
- $item = new ElggMenuItem('addfriend', $text, $url);
+ $item = new ElggMenuItem($name, $text, $url);
$item->setSection('action');
$return[] = $item;
} else {
@@ -1304,6 +1293,59 @@ function elgg_user_hover_menu($hook, $type, $return, $params) {
$item = new ElggMenuItem('profile:edit', elgg_echo('profile:edit'), $url);
$item->setSection('admin');
$return[] = $item;
+
+ $url = "settings/user/$user->username";
+ $item = new ElggMenuItem('settings:edit', elgg_echo('settings:edit'), $url);
+ $item->setSection('admin');
+ $return[] = $item;
+ }
+
+ return $return;
+}
+
+/**
+ * Setup the menu shown with an entity
+ *
+ * @param string $hook
+ * @param string $type
+ * @param array $return
+ * @param array $params
+ * @return array
+ *
+ * @access private
+ */
+function elgg_users_setup_entity_menu($hook, $type, $return, $params) {
+ if (elgg_in_context('widgets')) {
+ return $return;
+ }
+
+ $entity = $params['entity'];
+ if (!elgg_instanceof($entity, 'user')) {
+ return $return;
+ }
+ /* @var ElggUser $entity */
+
+ if ($entity->isBanned()) {
+ $banned = elgg_echo('banned');
+ $options = array(
+ 'name' => 'banned',
+ 'text' => "<span>$banned</span>",
+ 'href' => false,
+ 'priority' => 0,
+ );
+ $return = array(ElggMenuItem::factory($options));
+ } else {
+ $return = array();
+ if (isset($entity->location)) {
+ $location = htmlspecialchars($entity->location, ENT_QUOTES, 'UTF-8', false);
+ $options = array(
+ 'name' => 'location',
+ 'text' => "<span>$location</span>",
+ 'href' => false,
+ 'priority' => 150,
+ );
+ $return[] = ElggMenuItem::factory($options);
+ }
}
return $return;
@@ -1315,6 +1357,7 @@ function elgg_user_hover_menu($hook, $type, $return, $params) {
*
* Note: This is a secondary system:init call and is run at a super low priority to guarantee that it is called after all
* other plugins have initialised.
+ * @access private
*/
function elgg_profile_fields_setup() {
global $CONFIG;
@@ -1322,7 +1365,7 @@ function elgg_profile_fields_setup() {
$profile_defaults = array (
'description' => 'longtext',
'briefdescription' => 'text',
- 'location' => 'tags',
+ 'location' => 'location',
'interests' => 'tags',
'skills' => 'tags',
'contactemail' => 'email',
@@ -1332,11 +1375,10 @@ function elgg_profile_fields_setup() {
'twitter' => 'text'
);
- $loaded_default = array();
+ $loaded_defaults = array();
if ($fieldlist = elgg_get_config('profile_custom_fields')) {
if (!empty($fieldlist)) {
$fieldlistarray = explode(',', $fieldlist);
- $loaded_defaults = array();
foreach ($fieldlistarray as $listitem) {
if ($translation = elgg_get_config("admin_defined_profile_{$listitem}")) {
$type = elgg_get_config("admin_defined_profile_type_{$listitem}");
@@ -1356,7 +1398,7 @@ function elgg_profile_fields_setup() {
// register any tag metadata names
foreach ($CONFIG->profile_fields as $name => $type) {
- if ($type == 'tags') {
+ if ($type == 'tags' || $type == 'location' || $type == 'tag') {
elgg_register_tag_metadata_name($name);
// register a tag name translation
add_translation(get_current_language(), array("tag_names:$name" => elgg_echo("profile:$name")));
@@ -1371,24 +1413,34 @@ function elgg_profile_fields_setup() {
* /avatar/view/<username>/<size>/<icontime>
*
* @param array $page
+ * @return bool
+ * @access private
*/
function elgg_avatar_page_handler($page) {
global $CONFIG;
- set_input('username', $page[1]);
+ $user = get_user_by_username($page[1]);
+ if ($user) {
+ elgg_set_page_owner_guid($user->getGUID());
+ }
if ($page[0] == 'edit') {
require_once("{$CONFIG->path}pages/avatar/edit.php");
+ return true;
} else {
set_input('size', $page[2]);
require_once("{$CONFIG->path}pages/avatar/view.php");
+ return true;
}
+ return false;
}
/**
* Profile page handler
*
* @param array $page
+ * @return bool
+ * @access private
*/
function elgg_profile_page_handler($page) {
global $CONFIG;
@@ -1398,21 +1450,27 @@ function elgg_profile_page_handler($page) {
if ($page[1] == 'edit') {
require_once("{$CONFIG->path}pages/profile/edit.php");
+ return true;
}
+ return false;
}
/**
* Sets up user-related menu items
*
* @return void
+ * @access private
*/
function users_pagesetup() {
- if (elgg_get_page_owner_guid()) {
+ $owner = elgg_get_page_owner_entity();
+ $viewer = elgg_get_logged_in_user_entity();
+
+ if ($owner) {
$params = array(
'name' => 'friends',
'text' => elgg_echo('friends'),
- 'href' => 'friends/' . elgg_get_page_owner_entity()->username,
+ 'href' => 'friends/' . $owner->username,
'contexts' => array('friends')
);
elgg_register_menu_item('page', $params);
@@ -1420,42 +1478,44 @@ function users_pagesetup() {
$params = array(
'name' => 'friends:of',
'text' => elgg_echo('friends:of'),
- 'href' => 'friendsof/' . elgg_get_page_owner_entity()->username,
+ 'href' => 'friendsof/' . $owner->username,
'contexts' => array('friends')
);
elgg_register_menu_item('page', $params);
- }
-
- // topbar
- $user = elgg_get_logged_in_user_entity();
- if ($user) {
+
elgg_register_menu_item('page', array(
'name' => 'edit_avatar',
- 'href' => "avatar/edit/{$user->username}",
+ 'href' => "avatar/edit/{$owner->username}",
'text' => elgg_echo('avatar:edit'),
'contexts' => array('profile_edit'),
));
elgg_register_menu_item('page', array(
'name' => 'edit_profile',
- 'href' => "profile/{$user->username}/edit",
+ 'href' => "profile/{$owner->username}/edit",
'text' => elgg_echo('profile:edit'),
'contexts' => array('profile_edit'),
));
+ }
- $icon_url = $user->getIconURL('topbar');
- $class = 'elgg-border-plain elgg-transition';
- $title = elgg_echo('profile');
+ // topbar
+ if ($viewer) {
elgg_register_menu_item('topbar', array(
'name' => 'profile',
- 'href' => $user->getURL(),
- 'text' => "<img src=\"$icon_url\" alt=\"$user->name\" title=\"$title\" class=\"$class\" />",
+ 'href' => $viewer->getURL(),
+ 'text' => elgg_view('output/img', array(
+ 'src' => $viewer->getIconURL('topbar'),
+ 'alt' => $viewer->name,
+ 'title' => elgg_echo('profile'),
+ 'class' => 'elgg-border-plain elgg-transition',
+ )),
'priority' => 100,
+ 'link_class' => 'elgg-topbar-avatar',
));
elgg_register_menu_item('topbar', array(
'name' => 'friends',
- 'href' => "friends/{$user->username}",
+ 'href' => "friends/{$viewer->username}",
'text' => elgg_view_icon('users'),
'title' => elgg_echo('friends'),
'priority' => 300,
@@ -1463,7 +1523,7 @@ function users_pagesetup() {
elgg_register_menu_item('topbar', array(
'name' => 'usersettings',
- 'href' => "settings/user/{$user->username}",
+ 'href' => "settings/user/{$viewer->username}",
'text' => elgg_view_icon('settings') . elgg_echo('settings'),
'priority' => 500,
'section' => 'alt',
@@ -1477,7 +1537,6 @@ function users_pagesetup() {
'priority' => 1000,
'section' => 'alt',
));
-
}
}
@@ -1485,15 +1544,16 @@ function users_pagesetup() {
* Users initialisation function, which establishes the page handler
*
* @return void
+ * @access private
*/
function users_init() {
elgg_register_page_handler('friends', 'friends_page_handler');
- elgg_register_page_handler('friendsof', 'friends_of_page_handler');
- elgg_register_page_handler('dashboard', 'dashboard_page_handler');
- elgg_register_page_handler('register', 'registration_page_handler');
- elgg_register_page_handler('resetpassword', 'elgg_user_resetpassword_page_handler');
- elgg_register_page_handler('login', 'elgg_user_login_page_handler');
+ elgg_register_page_handler('friendsof', 'friends_page_handler');
+ elgg_register_page_handler('register', 'elgg_user_account_page_handler');
+ elgg_register_page_handler('forgotpassword', 'elgg_user_account_page_handler');
+ elgg_register_page_handler('resetpassword', 'elgg_user_account_page_handler');
+ elgg_register_page_handler('login', 'elgg_user_account_page_handler');
elgg_register_page_handler('avatar', 'elgg_avatar_page_handler');
elgg_register_page_handler('profile', 'elgg_profile_page_handler');
elgg_register_page_handler('collections', 'collections_page_handler');
@@ -1501,11 +1561,12 @@ function users_init() {
elgg_register_plugin_hook_handler('register', 'menu:user_hover', 'elgg_user_hover_menu');
elgg_register_action('register', '', 'public');
- elgg_register_action('useradd', '', 'public');
+ elgg_register_action('useradd', '', 'admin');
elgg_register_action('friends/add');
elgg_register_action('friends/remove');
elgg_register_action('avatar/upload');
elgg_register_action('avatar/crop');
+ elgg_register_action('avatar/remove');
elgg_register_action('profile/edit');
elgg_register_action('friends/collections/add');
@@ -1519,28 +1580,24 @@ function users_init() {
elgg_register_widget_type('friends', elgg_echo('friends'), elgg_echo('friends:widget:description'));
- // extend the account settings form
- elgg_extend_view('forms/account/settings', 'core/settings/account/name', 100);
- elgg_extend_view('forms/account/settings', 'core/settings/account/password', 100);
- elgg_extend_view('forms/account/settings', 'core/settings/account/email', 100);
- elgg_extend_view('forms/account/settings', 'core/settings/account/language', 100);
- elgg_extend_view('forms/account/settings', 'core/settings/account/default_access', 100);
-
// Register the user type
elgg_register_entity_type('user', '');
+ elgg_register_plugin_hook_handler('register', 'menu:entity', 'elgg_users_setup_entity_menu', 501);
+
elgg_register_event_handler('create', 'user', 'user_create_hook_add_site_relationship');
}
/**
* Runs unit tests for ElggObject
*
- * @param sting $hook unit_test
+ * @param string $hook unit_test
* @param string $type system
* @param mixed $value Array of tests
* @param mixed $params Params
*
* @return array
+ * @access private
*/
function users_test($hook, $type, $value, $params) {
global $CONFIG;
diff --git a/engine/lib/views.php b/engine/lib/views.php
index e2cf6b5c3..1142461fe 100644
--- a/engine/lib/views.php
+++ b/engine/lib/views.php
@@ -101,12 +101,15 @@ function elgg_get_viewtype() {
return $CURRENT_SYSTEM_VIEWTYPE;
}
- $viewtype = get_input('view', NULL);
- if ($viewtype) {
- return $viewtype;
+ $viewtype = get_input('view', '', false);
+ if (is_string($viewtype) && $viewtype !== '') {
+ // only word characters allowed.
+ if (!preg_match('/\W/', $viewtype)) {
+ return $viewtype;
+ }
}
- if (isset($CONFIG->view) && !empty($CONFIG->view)) {
+ if (!empty($CONFIG->view)) {
return $CONFIG->view;
}
@@ -140,6 +143,7 @@ function elgg_register_viewtype($view_type) {
*
* @return bool
* @since 1.7.2
+ * @access private
*/
function elgg_is_valid_view_type($view_type) {
global $CONFIG;
@@ -195,6 +199,37 @@ function elgg_does_viewtype_fallback($viewtype) {
return FALSE;
}
+/**
+ * Register a view to be available for ajax calls
+ *
+ * @param string $view The view name
+ * @return void
+ * @since 1.8.3
+ */
+function elgg_register_ajax_view($view) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->allowed_ajax_views)) {
+ $CONFIG->allowed_ajax_views = array();
+ }
+
+ $CONFIG->allowed_ajax_views[$view] = true;
+}
+
+/**
+ * Unregister a view for ajax calls
+ *
+ * @param string $view The view name
+ * @return void
+ * @since 1.8.3
+ */
+function elgg_unregister_ajax_view($view) {
+ global $CONFIG;
+
+ if (isset($CONFIG->allowed_ajax_views[$view])) {
+ unset($CONFIG->allowed_ajax_views[$view]);
+ }
+}
/**
* Returns the file location for a view.
@@ -223,8 +258,6 @@ function elgg_get_view_location($view, $viewtype = '') {
} else {
return $CONFIG->views->locations[$viewtype][$view];
}
-
- return false;
}
/**
@@ -268,7 +301,7 @@ function elgg_set_view_location($view, $location, $viewtype = '') {
/**
* Returns whether the specified view exists
*
- * @note If $recurse is strue, also checks if a view exists only as an extension.
+ * @note If $recurse is true, also checks if a view exists only as an extension.
*
* @param string $view The view name
* @param string $viewtype If set, forces the viewtype
@@ -294,7 +327,7 @@ function elgg_view_exists($view, $viewtype = '', $recurse = true) {
$location = $CONFIG->views->locations[$viewtype][$view];
}
- if (file_exists($location . "{$viewtype}/{$view}.php")) {
+ if (file_exists("{$location}{$viewtype}/{$view}.php")) {
return true;
}
@@ -309,6 +342,11 @@ function elgg_view_exists($view, $viewtype = '', $recurse = true) {
}
}
+ // Now check if the default view exists if the view is registered as a fallback
+ if ($viewtype != 'default' && elgg_does_viewtype_fallback($viewtype)) {
+ return elgg_view_exists($view, 'default');
+ }
+
return false;
}
@@ -331,14 +369,14 @@ function elgg_view_exists($view, $viewtype = '', $recurse = true) {
* view, $view_name plugin hook.
*
* @warning Any variables in $_SESSION will override passed vars
- * upon name collision. See {@trac #2124}.
+ * upon name collision. See https://github.com/Elgg/Elgg/issues/2124
*
* @param string $view The name and location of the view to use
* @param array $vars Variables to pass to the view.
* @param boolean $bypass If set to true, elgg_view will bypass any specified
* alternative template handler; by default, it will
* hand off to this if requested (see set_template_handler)
- * @param boolean $debug If set to true, the viewer will complain if it can't find a view
+ * @param boolean $ignored This argument is ignored and will be removed eventually
* @param string $viewtype If set, forces the viewtype for the elgg_view call to be
* this value (default: standard detection)
*
@@ -346,30 +384,17 @@ function elgg_view_exists($view, $viewtype = '', $recurse = true) {
* @see set_template_handler()
* @example views/elgg_view.php
* @link http://docs.elgg.org/View
- * @todo $debug isn't used.
- * @todo $usercache is redundant.
*/
-function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $viewtype = '') {
+function elgg_view($view, $vars = array(), $bypass = false, $ignored = false, $viewtype = '') {
global $CONFIG;
- static $usercache;
-
- $view = (string)$view;
+ if (!is_string($view) || !is_string($viewtype)) {
+ elgg_log("View and Viewtype in views must be a strings: $view", 'NOTICE');
+ return '';
+ }
// basic checking for bad paths
if (strpos($view, '..') !== false) {
- return false;
- }
-
- $view_orig = $view;
-
- // Trigger the pagesetup event
- if (!isset($CONFIG->pagesetupdone)) {
- elgg_trigger_event('pagesetup', 'system');
- $CONFIG->pagesetupdone = true;
- }
-
- if (!is_array($usercache)) {
- $usercache = array();
+ return '';
}
if (!is_array($vars)) {
@@ -377,8 +402,20 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
$vars = array();
}
- if (empty($vars)) {
- $vars = array();
+ // Get the current viewtype
+ if ($viewtype === '') {
+ $viewtype = elgg_get_viewtype();
+ } elseif (preg_match('/\W/', $viewtype)) {
+ // Viewtypes can only be alphanumeric
+ return '';
+ }
+
+ $view_orig = $view;
+
+ // Trigger the pagesetup event
+ if (!isset($CONFIG->pagesetupdone) && $CONFIG->boot_complete) {
+ $CONFIG->pagesetupdone = true;
+ elgg_trigger_event('pagesetup', 'system');
}
// @warning - plugin authors: do not expect user, config, and url to be
@@ -395,8 +432,10 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
}
// full_view is the new preferred key for full view on entities @see elgg_view_entity()
- if (isset($vars['full'])) {
- elgg_deprecated_notice("Use \$vars['full_view'] instead of \$vars['full']", 1.8);
+ // check if full_view is set because that means we've already rewritten it and this is
+ // coming from another view passing $vars directly.
+ if (isset($vars['full']) && !isset($vars['full_view'])) {
+ elgg_deprecated_notice("Use \$vars['full_view'] instead of \$vars['full']", 1.8, 2);
$vars['full_view'] = $vars['full'];
}
if (isset($vars['full_view'])) {
@@ -404,18 +443,24 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
}
// internalname => name (1.8)
- if (isset($vars['internalname'])) {
- elgg_deprecated_notice('You should pass $vars[\'name\'] now instead of $vars[\'internalname\']', 1.8);
+ if (isset($vars['internalname']) && !isset($vars['__ignoreInternalname']) && !isset($vars['name'])) {
+ elgg_deprecated_notice('You should pass $vars[\'name\'] now instead of $vars[\'internalname\']', 1.8, 2);
$vars['name'] = $vars['internalname'];
} elseif (isset($vars['name'])) {
+ if (!isset($vars['internalname'])) {
+ $vars['__ignoreInternalname'] = '';
+ }
$vars['internalname'] = $vars['name'];
}
// internalid => id (1.8)
- if (isset($vars['internalid'])) {
- elgg_deprecated_notice('You should pass $vars[\'id\'] now instead of $vars[\'internalid\']', 1.8);
+ if (isset($vars['internalid']) && !isset($vars['__ignoreInternalid']) && !isset($vars['name'])) {
+ elgg_deprecated_notice('You should pass $vars[\'id\'] now instead of $vars[\'internalid\']', 1.8, 2);
$vars['id'] = $vars['internalid'];
} elseif (isset($vars['id'])) {
+ if (!isset($vars['internalid'])) {
+ $vars['__ignoreInternalid'] = '';
+ }
$vars['internalid'] = $vars['id'];
}
@@ -427,16 +472,6 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
}
}
- // Get the current viewtype
- if (empty($viewtype)) {
- $viewtype = elgg_get_viewtype();
- }
-
- // Viewtypes can only be alphanumeric
- if (preg_match('[\W]', $viewtype)) {
- return '';
- }
-
// Set up any extensions to the requested view
if (isset($CONFIG->views->extensions[$view])) {
$viewlist = $CONFIG->views->extensions[$view];
@@ -448,19 +483,21 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
ob_start();
foreach ($viewlist as $priority => $view) {
+
$view_location = elgg_get_view_location($view, $viewtype);
$view_file = "$view_location$viewtype/$view.php";
- $default_location = elgg_get_view_location($view, 'default');
- $default_view_file = "{$default_location}default/$view.php";
-
// try to include view
if (!file_exists($view_file) || !include($view_file)) {
// requested view does not exist
$error = "$viewtype/$view view does not exist.";
// attempt to load default view
- if ($viewtype != 'default' && elgg_does_viewtype_fallback($viewtype)) {
+ if ($viewtype !== 'default' && elgg_does_viewtype_fallback($viewtype)) {
+
+ $default_location = elgg_get_view_location($view, 'default');
+ $default_view_file = "{$default_location}default/$view.php";
+
if (file_exists($default_view_file) && include($default_view_file)) {
// default view found
$error .= " Using default/$view instead.";
@@ -485,7 +522,7 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
// backward compatibility with less granular hook will be gone in 2.0
$content_tmp = elgg_trigger_plugin_hook('display', 'view', $params, $content);
- if ($content_tmp != $content) {
+ if ($content_tmp !== $content) {
$content = $content_tmp;
elgg_deprecated_notice('The display:view plugin hook is deprecated by view:view_name', 1.8);
}
@@ -511,33 +548,32 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
* @param string $view_extension This view is added to $view
* @param int $priority The priority, from 0 to 1000,
* to add at (lowest numbers displayed first)
- * @param string $viewtype Not used
*
* @return void
* @since 1.7.0
- * @link http://docs.elgg.org/Views/Ejxtend
+ * @link http://docs.elgg.org/Views/Extend
* @example views/extend.php
*/
-function elgg_extend_view($view, $view_extension, $priority = 501, $viewtype = '') {
+function elgg_extend_view($view, $view_extension, $priority = 501) {
global $CONFIG;
if (!isset($CONFIG->views)) {
- $CONFIG->views = new stdClass;
- }
-
- if (!isset($CONFIG->views->extensions)) {
- $CONFIG->views->extensions = array();
- }
-
- if (!isset($CONFIG->views->extensions[$view])) {
- $CONFIG->views->extensions[$view][500] = "{$view}";
+ $CONFIG->views = (object) array(
+ 'extensions' => array(),
+ );
+ $CONFIG->views->extensions[$view][500] = (string)$view;
+ } else {
+ if (!isset($CONFIG->views->extensions[$view])) {
+ $CONFIG->views->extensions[$view][500] = (string)$view;
+ }
}
+ // raise priority until it doesn't match one already registered
while (isset($CONFIG->views->extensions[$view][$priority])) {
$priority++;
}
- $CONFIG->views->extensions[$view][$priority] = "{$view_extension}";
+ $CONFIG->views->extensions[$view][$priority] = (string)$view_extension;
ksort($CONFIG->views->extensions[$view]);
}
@@ -553,14 +589,6 @@ function elgg_extend_view($view, $view_extension, $priority = 501, $viewtype = '
function elgg_unextend_view($view, $view_extension) {
global $CONFIG;
- if (!isset($CONFIG->views)) {
- return FALSE;
- }
-
- if (!isset($CONFIG->views->extensions)) {
- return FALSE;
- }
-
if (!isset($CONFIG->views->extensions[$view])) {
return FALSE;
}
@@ -609,13 +637,12 @@ function elgg_view_page($title, $body, $page_shell = 'default', $vars = array())
$vars['title'] = $title;
$vars['body'] = $body;
$vars['sysmessages'] = $messages;
+
+ $vars = elgg_trigger_plugin_hook('output:before', 'page', null, $vars);
// check for deprecated view
if ($page_shell == 'default' && elgg_view_exists('pageshells/pageshell')) {
elgg_deprecated_notice("pageshells/pageshell is deprecated by page/$page_shell", 1.8);
- global $CONFIG;
-
- $vars['config'] = $CONFIG;
$output = elgg_view('pageshells/pageshell', $vars);
} else {
$output = elgg_view("page/$page_shell", $vars);
@@ -673,15 +700,19 @@ function elgg_view_layout($layout_name, $vars = array()) {
$param_array = $vars;
}
+ $params = elgg_trigger_plugin_hook('output:before', 'layout', null, $param_array);
+
// check deprecated location
if (elgg_view_exists("canvas/layouts/$layout_name")) {
elgg_deprecated_notice("canvas/layouts/$layout_name is deprecated by page/layouts/$layout_name", 1.8);
- return elgg_view("canvas/layouts/$layout_name", $param_array);
+ $output = elgg_view("canvas/layouts/$layout_name", $params);
} elseif (elgg_view_exists("page/layouts/$layout_name")) {
- return elgg_view("page/layouts/$layout_name", $param_array);
+ $output = elgg_view("page/layouts/$layout_name", $params);
} else {
- return elgg_view("page/layouts/default", $param_array);
+ $output = elgg_view("page/layouts/default", $params);
}
+
+ return elgg_trigger_plugin_hook('output:after', 'layout', $params, $output);
}
/**
@@ -692,9 +723,9 @@ function elgg_view_layout($layout_name, $vars = array()) {
*
* This function triggers a 'register', 'menu:<menu name>' plugin hook that enables
* plugins to add menu items just before a menu is rendered. This is used by
- * context-sensitive menus (menus that are specific to a particular entity such
- * as the user hover menu). Using elgg_register_menu_item() in response to the hook
- * can cause incorrect links to show up. See the blog plugin's blog_owner_block_menu()
+ * dynamic menus (menus that change based on some input such as the user hover
+ * menu). Using elgg_register_menu_item() in response to the hook can cause
+ * incorrect links to show up. See the blog plugin's blog_owner_block_menu()
* for an example of using this plugin hook.
*
* An additional hook is the 'prepare', 'menu:<menu name>' which enables plugins
@@ -707,8 +738,9 @@ function elgg_view_layout($layout_name, $vars = array()) {
* @param array $vars An associative array of display options for the menu.
* Options include:
* sort_by => string or php callback
- * string options: 'name', 'priority', 'title' (default), 'register' (registration order)
- * php callback: a compare function for usort
+ * string options: 'name', 'priority', 'title' (default),
+ * 'register' (registration order) or a
+ * php callback (a compare function for usort)
* handler: string the page handler to build action URLs
* entity: ElggEntity to use to build action URLs
* class: string the class for the entire menu.
@@ -724,10 +756,14 @@ function elgg_view_menu($menu_name, array $vars = array()) {
$sort_by = elgg_extract('sort_by', $vars, 'text');
- $menu = $CONFIG->menus[$menu_name];
+ if (isset($CONFIG->menus[$menu_name])) {
+ $menu = $CONFIG->menus[$menu_name];
+ } else {
+ $menu = array();
+ }
// Give plugins a chance to add menu items just before creation.
- // This supports context sensitive menus (ex. user_hover).
+ // This supports dynamic menus (example: user_hover).
$menu = elgg_trigger_plugin_hook('register', "menu:$menu_name", $vars, $menu);
$builder = new ElggMenuBuilder($menu);
@@ -759,7 +795,7 @@ function elgg_view_menu($menu_name, array $vars = array()) {
* - bool 'full_view' Whether to show a full or condensed view.
*
* @tip This function can automatically appends annotations to entities if in full
- * view and a handler is registered for the entity:annotate. See {@trac 964} and
+ * view and a handler is registered for the entity:annotate. See https://github.com/Elgg/Elgg/issues/964 and
* {@link elgg_view_entity_annotations()}.
*
* @param ElggEntity $entity The entity to display
@@ -841,7 +877,9 @@ function elgg_view_entity(ElggEntity $entity, $vars = array(), $bypass = true, $
*
* @param ElggEntity $entity The entity to display
* @param string $size The size: tiny, small, medium, large
- * @param array $vars An array of variables to pass to the view
+ * @param array $vars An array of variables to pass to the view. Some possible
+ * variables are img_class and link_class. See the
+ * specific icon view for more parameters.
*
* @return string HTML to display or false
*/
@@ -914,12 +952,7 @@ function elgg_view_annotation(ElggAnnotation $annotation, array $vars = array(),
return elgg_view($view, $vars, $bypass, $debug);
}
- // @todo would be better to always make sure name is initialized properly
$name = $annotation->name;
- $intname = (int) $name;
- if ("{$intname}" == "{$name}") {
- $name = get_metastring($intname);
- }
if (empty($name)) {
return false;
}
@@ -947,9 +980,10 @@ function elgg_view_annotation(ElggAnnotation $annotation, array $vars = array(),
* 'offset' The current indexing offset
* 'limit' The number of entities to display per page
* 'full_view' Display the full view of the entities?
- * 'list_class' CSS Class applied to the list
+ * 'list_class' CSS class applied to the list
+ * 'item_class' CSS class applied to the list items
* 'pagination' Display pagination?
- * 'gallery' Display as gallery?
+ * 'list_type' List type: 'list' (default), 'gallery'
* 'list_type_toggle' Display the list type toggle?
*
* @return string The rendered list of entities
@@ -958,18 +992,30 @@ function elgg_view_annotation(ElggAnnotation $annotation, array $vars = array(),
function elgg_view_entity_list($entities, $vars = array(), $offset = 0, $limit = 10, $full_view = true,
$list_type_toggle = true, $pagination = true) {
+ if (!$vars["limit"] && !$vars["offset"]) {
+ // no need for pagination if listing is unlimited
+ $vars["pagination"] = false;
+ }
+
if (!is_int($offset)) {
$offset = (int)get_input('offset', 0);
}
+ // list type can be passed as request parameter
+ $list_type = get_input('list_type', 'list');
+ if (get_input('listtype')) {
+ elgg_deprecated_notice("'listtype' has been deprecated by 'list_type' for lists", 1.8);
+ $list_type = get_input('listtype');
+ }
+
if (is_array($vars)) {
// new function
$defaults = array(
'items' => $entities,
- 'list_class' => 'elgg-entity-list',
+ 'list_class' => 'elgg-list-entity',
'full_view' => true,
'pagination' => true,
- 'gallery' => false,
+ 'list_type' => $list_type,
'list_type_toggle' => false,
'offset' => $offset,
);
@@ -987,18 +1033,13 @@ $list_type_toggle = true, $pagination = true) {
'limit' => (int) $limit,
'full_view' => $full_view,
'pagination' => $pagination,
- 'gallery' => false,
+ 'list_type' => $list_type,
'list_type_toggle' => $list_type_toggle,
- 'list_class' => 'elgg-entity-list',
+ 'list_class' => 'elgg-list-entity',
);
}
- $listtype = get_input('listtype', 'list');
- if ($listtype != 'list') {
- $vars['gallery'] = true;
- }
-
- if ($vars['gallery']) {
+ if ($vars['list_type'] != 'list') {
return elgg_view('page/components/gallery', $vars);
} else {
return elgg_view('page/components/list', $vars);
@@ -1024,12 +1065,17 @@ $list_type_toggle = true, $pagination = true) {
function elgg_view_annotation_list($annotations, array $vars = array()) {
$defaults = array(
'items' => $annotations,
- 'list_class' => 'elgg-annotation-list',
+ 'list_class' => 'elgg-list-annotation elgg-annotation-list', // @todo remove elgg-annotation-list in Elgg 1.9
'full_view' => true,
'offset_key' => 'annoff',
);
-
+
$vars = array_merge($defaults, $vars);
+
+ if (!$vars["limit"] && !$vars["offset"]) {
+ // no need for pagination if listing is unlimited
+ $vars["pagination"] = false;
+ }
return elgg_view('page/components/list', $vars);
}
@@ -1049,10 +1095,6 @@ function elgg_view_annotation_list($annotations, array $vars = array()) {
* @todo Change the hook name.
*/
function elgg_view_entity_annotations(ElggEntity $entity, $full_view = true) {
- if (!$entity) {
- return false;
- }
-
if (!($entity instanceof ElggEntity)) {
return false;
}
@@ -1070,21 +1112,24 @@ function elgg_view_entity_annotations(ElggEntity $entity, $full_view = true) {
}
/**
- * Returns a rendered title.
+ * Renders a title.
*
* This is a shortcut for {@elgg_view page/elements/title}.
*
- * @param string $title The page title
- * @param string $submenu Should a submenu be displayed? (deprecated)
+ * @param string $title The page title
+ * @param array $vars View variables (was submenu be displayed? (deprecated))
*
* @return string The HTML (etc)
*/
-function elgg_view_title($title, $submenu = false) {
- if ($submenu !== false) {
+function elgg_view_title($title, $vars = array()) {
+ if (!is_array($vars)) {
elgg_deprecated_notice('setting $submenu in elgg_view_title() is deprecated', 1.8);
+ $vars = array('submenu' => $vars);
}
- return elgg_view('page/elements/title', array('title' => $title, 'submenu' => $submenu));
+ $vars['title'] = $title;
+
+ return elgg_view('page/elements/title', $vars);
}
/**
@@ -1144,7 +1189,7 @@ function elgg_view_comments($entity, $add_comment = true, array $vars = array())
*
* @param string $image The icon and other information
* @param string $body Description content
- * @param string $vars Additional parameters for the view
+ * @param array $vars Additional parameters for the view
*
* @return string
* @since 1.8.0
@@ -1165,13 +1210,13 @@ function elgg_view_image_block($image, $body, $vars = array()) {
* @param string $type The type of module (main, info, popup, aside, etc.)
* @param string $title A title to put in the header
* @param string $body Content of the module
- * @param string $vars Additional parameters for the module
+ * @param array $vars Additional parameters for the module
*
* @return string
* @since 1.8.0
*/
-function elgg_view_module($type, $title, $body, $vars = array()) {
- $vars['class'] .= " elgg-module-$type"; //@todo this will probably cause errors?
+function elgg_view_module($type, $title, $body, array $vars = array()) {
+ $vars['class'] = elgg_extract('class', $vars, '') . " elgg-module-$type";
$vars['title'] = $title;
$vars['body'] = $body;
return elgg_view('page/components/module', $vars);
@@ -1183,11 +1228,15 @@ function elgg_view_module($type, $title, $body, $vars = array()) {
* @param ElggRiverItem $item A river item object
* @param array $vars An array of variables for the view
*
- * @return string|false Depending on success
+ * @return string returns empty string if could not be rendered
*/
function elgg_view_river_item($item, array $vars = array()) {
+ if (!($item instanceof ElggRiverItem)) {
+ return '';
+ }
// checking default viewtype since some viewtypes do not have unique views per item (rss)
- if (!$item || !$item->getView() || !elgg_view_exists($item->getView(), 'default')) {
+ $view = $item->getView();
+ if (!$view || !elgg_view_exists($view, 'default')) {
return '';
}
@@ -1198,6 +1247,17 @@ function elgg_view_river_item($item, array $vars = array()) {
return '';
}
+ // @todo this needs to be cleaned up
+ // Don't hide objects in closed groups that a user can see.
+ // see https://github.com/elgg/elgg/issues/4789
+ // else {
+ // // hide based on object's container
+ // $visibility = ElggGroupItemVisibility::factory($object->container_guid);
+ // if ($visibility->shouldHideItems) {
+ // return '';
+ // }
+ // }
+
$vars['item'] = $item;
return elgg_view('river/item', $vars);
@@ -1210,6 +1270,9 @@ function elgg_view_river_item($item, array $vars = array()) {
* sets the action by default to "action/$action". Automatically wraps the forms/$action
* view with a <form> tag and inserts the anti-csrf security tokens.
*
+ * @tip This automatically appends elgg-form-action-name to the form's class. It replaces any
+ * slashes with dashes (blog/save becomes elgg-form-blog-save)
+ *
* @example
* <code>echo elgg_view_form('login');</code>
*
@@ -1239,16 +1302,25 @@ function elgg_view_form($action, $form_vars = array(), $body_vars = array()) {
$defaults = array(
'action' => $CONFIG->wwwroot . "action/$action",
- 'body' => elgg_view("forms/$action", $body_vars),
+ 'body' => elgg_view("forms/$action", $body_vars)
);
+ $form_class = 'elgg-form-' . preg_replace('/[^a-z0-9]/i', '-', $action);
+
+ // append elgg-form class to any class options set
+ if (isset($form_vars['class'])) {
+ $form_vars['class'] = $form_vars['class'] . " $form_class";
+ } else {
+ $form_vars['class'] = $form_class;
+ }
+
return elgg_view('input/form', array_merge($defaults, $form_vars));
}
/**
* View an item in a list
*
- * @param object $item ElggEntity or ElggAnnotation
+ * @param ElggEntity|ElggAnnotation $item
* @param array $vars Additional parameters for the rendering
*
* @return string
@@ -1256,38 +1328,56 @@ function elgg_view_form($action, $form_vars = array(), $body_vars = array()) {
* @access private
*/
function elgg_view_list_item($item, array $vars = array()) {
+ global $CONFIG;
- switch ($item->getType()) {
- case 'user':
- case 'object':
- case 'group':
- case 'site':
- return elgg_view_entity($item, $vars);
- case 'annotation':
- return elgg_view_annotation($item, $vars);
- case 'river':
- return elgg_view_river_item($item, $vars);
- default:
- return false;
- break;
+ $type = $item->getType();
+ if (in_array($type, $CONFIG->entity_types)) {
+ return elgg_view_entity($item, $vars);
+ } else if ($type == 'annotation') {
+ return elgg_view_annotation($item, $vars);
+ } else if ($type == 'river') {
+ return elgg_view_river_item($item, $vars);
}
+
+ return '';
}
/**
* View one of the elgg sprite icons
- *
+ *
* Shorthand for <span class="elgg-icon elgg-icon-$name"></span>
- *
+ *
* @param string $name The specific icon to display
- * @param bool $float Whether to float the icon
- *
+ * @param string $class Additional class: float, float-alt, or custom class
+ *
* @return string The html for displaying an icon
*/
-function elgg_view_icon($name, $float = false) {
- if ($float) {
- $float = 'float';
+function elgg_view_icon($name, $class = '') {
+ // @todo deprecate boolean in Elgg 1.9
+ if ($class === true) {
+ $class = 'float';
+ }
+ return "<span class=\"elgg-icon elgg-icon-$name $class\"></span>";
+}
+
+/**
+ * Displays a user's access collections, using the core/friends/collections view
+ *
+ * @param int $owner_guid The GUID of the owning user
+ *
+ * @return string A formatted rendition of the collections
+ * @todo Move to the friends/collection.php page.
+ * @access private
+ */
+function elgg_view_access_collections($owner_guid) {
+ if ($collections = get_user_access_collections($owner_guid)) {
+ foreach ($collections as $key => $collection) {
+ $collections[$key]->members = get_members_of_access_collection($collection->id, true);
+ $collections[$key]->entities = get_user_friends($owner_guid, "", 9999);
+ }
}
- return "<span class=\"elgg-icon elgg-icon-$name $float\"></span>";
+
+ return elgg_view('core/friends/collections', array('collections' => $collections));
}
/**
@@ -1313,7 +1403,8 @@ function elgg_view_icon($name, $float = false) {
*/
function set_template_handler($function_name) {
global $CONFIG;
- if (!empty($function_name) && is_callable($function_name)) {
+
+ if (is_callable($function_name)) {
$CONFIG->template_handler = $function_name;
return true;
}
@@ -1332,6 +1423,7 @@ function set_template_handler($function_name) {
* @since 1.7.0
* @todo Why isn't this used anywhere else but in elgg_view_tree()?
* Seems like a useful function for autodiscovery.
+ * @access private
*/
function elgg_get_views($dir, $base) {
$return = array();
@@ -1367,20 +1459,17 @@ function elgg_get_views($dir, $base) {
*
* @return array A list of view names underneath that root view
* @todo This is used once in the deprecated get_activity_stream_data() function.
+ * @access private
*/
function elgg_view_tree($view_root, $viewtype = "") {
global $CONFIG;
- static $treecache;
+ static $treecache = array();
// Get viewtype
if (!$viewtype) {
$viewtype = elgg_get_viewtype();
}
- // Has the treecache been initialised?
- if (!isset($treecache)) {
- $treecache = array();
- }
// A little light internal caching
if (!empty($treecache[$view_root])) {
return $treecache[$view_root];
@@ -1424,16 +1513,13 @@ function elgg_view_tree($view_root, $viewtype = "") {
* @param string $base_location_path The base views directory to use with elgg_set_view_location()
* @param string $viewtype The type of view we're looking at (default, rss, etc)
*
- * @return void
+ * @return bool returns false if folder can't be read
* @since 1.7.0
* @see elgg_set_view_location()
* @todo This seems overly complicated.
+ * @access private
*/
function autoregister_views($view_base, $folder, $base_location_path, $viewtype) {
- if (!isset($i)) {
- $i = 0;
- }
-
if ($handle = opendir($folder)) {
while ($view = readdir($handle)) {
if (!in_array($view, array('.', '..', '.svn', 'CVS')) && !is_dir($folder . "/" . $view)) {
@@ -1466,29 +1552,15 @@ function autoregister_views($view_base, $folder, $base_location_path, $viewtype)
}
/**
- * Add the core Elgg head elements that could be cached
- *
- * @return void
- */
-function elgg_views_register_core_head_elements() {
- $url = elgg_get_simplecache_url('js', 'elgg');
- elgg_register_js('elgg', $url, 'head', 10);
- elgg_load_js('elgg');
-
- $url = elgg_get_simplecache_url('css', 'elgg');
- elgg_register_css('elgg', $url, 10);
- elgg_load_css('elgg');
-}
-
-/**
* Add the rss link to the extras when if needed
*
* @return void
+ * @access private
*/
function elgg_views_add_rss_link() {
global $autofeed;
if (isset($autofeed) && $autofeed == true) {
- $url = full_url();
+ $url = current_page_url();
if (substr_count($url, '?')) {
$url .= "&view=rss";
} else {
@@ -1506,6 +1578,19 @@ function elgg_views_add_rss_link() {
}
/**
+ * Registers deprecated views to avoid making some pages from older plugins
+ * completely empty.
+ *
+ * @access private
+ */
+function elgg_views_handle_deprecated_views() {
+ $location = elgg_get_view_location('page_elements/contentwrapper');
+ if ($location === "/var/www/views/") {
+ elgg_extend_view('page_elements/contentwrapper', 'page/elements/wrapper');
+ }
+}
+
+/**
* Initialize viewtypes on system boot event
* This ensures simplecache is cleared during upgrades. See #2252
*
@@ -1516,26 +1601,39 @@ function elgg_views_add_rss_link() {
function elgg_views_boot() {
global $CONFIG;
- elgg_register_simplecache_view('css/elgg');
elgg_register_simplecache_view('css/ie');
elgg_register_simplecache_view('css/ie6');
- elgg_register_simplecache_view('js/elgg');
+ elgg_register_simplecache_view('css/ie7');
- elgg_register_js('jquery', '/vendors/jquery/jquery-1.5.min.js', 'head', 1);
- elgg_register_js('jquery-ui', '/vendors/jquery/jquery-ui-1.8.9.min.js', 'head', 2);
+ elgg_register_js('jquery', '/vendors/jquery/jquery-1.6.4.min.js', 'head');
+ elgg_register_js('jquery-ui', '/vendors/jquery/jquery-ui-1.8.16.min.js', 'head');
elgg_register_js('jquery.form', '/vendors/jquery/jquery.form.js');
+
+ elgg_register_simplecache_view('js/elgg');
+ $elgg_js_url = elgg_get_simplecache_url('js', 'elgg');
+ elgg_register_js('elgg', $elgg_js_url, 'head');
+
elgg_load_js('jquery');
elgg_load_js('jquery-ui');
- elgg_load_js('jquery.form');
+ elgg_load_js('elgg');
elgg_register_simplecache_view('js/lightbox');
$lightbox_js_url = elgg_get_simplecache_url('js', 'lightbox');
elgg_register_js('lightbox', $lightbox_js_url);
- $lightbox_css_url = 'vendors/jquery/fancybox/jquery.fancybox-1.3.4.css';
+
+ elgg_register_simplecache_view('css/lightbox');
+ $lightbox_css_url = elgg_get_simplecache_url('css', 'lightbox');
elgg_register_css('lightbox', $lightbox_css_url);
- elgg_register_event_handler('ready', 'system', 'elgg_views_register_core_head_elements');
- elgg_register_event_handler('pagesetup', 'system', 'elgg_views_add_rss_link');
+ elgg_register_simplecache_view('css/elgg');
+ $elgg_css_url = elgg_get_simplecache_url('css', 'elgg');
+ elgg_register_css('elgg', $elgg_css_url);
+
+ elgg_load_css('elgg');
+
+ elgg_register_ajax_view('js/languages');
+
+ elgg_register_plugin_hook_handler('output:before', 'layout', 'elgg_views_add_rss_link');
// discover the built-in view types
// @todo the cache is loaded in load_plugins() but we need to know view_types earlier
@@ -1544,10 +1642,24 @@ function elgg_views_boot() {
$views = scandir($view_path);
foreach ($views as $view) {
- if ('.' !== substr($view, 0, 1) && is_dir($view_path . $view)) {
+ if ($view[0] !== '.' && is_dir($view_path . $view)) {
elgg_register_viewtype($view);
}
}
+
+ // set default icon sizes - can be overridden in settings.php or with plugin
+ if (!isset($CONFIG->icon_sizes)) {
+ $icon_sizes = array(
+ 'topbar' => array('w' => 16, 'h' => 16, 'square' => TRUE, 'upscale' => TRUE),
+ 'tiny' => array('w' => 25, 'h' => 25, 'square' => TRUE, 'upscale' => TRUE),
+ 'small' => array('w' => 40, 'h' => 40, 'square' => TRUE, 'upscale' => TRUE),
+ 'medium' => array('w' => 100, 'h' => 100, 'square' => TRUE, 'upscale' => TRUE),
+ 'large' => array('w' => 200, 'h' => 200, 'square' => FALSE, 'upscale' => FALSE),
+ 'master' => array('w' => 550, 'h' => 550, 'square' => FALSE, 'upscale' => FALSE),
+ );
+ elgg_set_config('icon_sizes', $icon_sizes);
+ }
}
-elgg_register_event_handler('boot', 'system', 'elgg_views_boot', 1000);
+elgg_register_event_handler('boot', 'system', 'elgg_views_boot');
+elgg_register_event_handler('init', 'system', 'elgg_views_handle_deprecated_views');
diff --git a/engine/lib/web_services.php b/engine/lib/web_services.php
index 8e312209b..51cad6f39 100644
--- a/engine/lib/web_services.php
+++ b/engine/lib/web_services.php
@@ -154,6 +154,7 @@ function unexpose_function($method) {
* @return true or throws an exception
* @throws APIException
* @since 1.7.0
+ * @access private
*/
function authenticate_method($method) {
global $API_METHODS;
@@ -177,7 +178,7 @@ function authenticate_method($method) {
// check if user authentication is required
if ($API_METHODS[$method]["require_user_auth"] == true) {
if ($user_auth_result == false) {
- throw new APIException($user_pam->getFailureMessage());
+ throw new APIException($user_pam->getFailureMessage(), ErrorResult::$RESULT_FAIL_AUTHTOKEN);
}
}
@@ -192,6 +193,7 @@ function authenticate_method($method) {
*
* @return GenericResult The result of the execution.
* @throws APIException, CallException
+ * @access private
*/
function execute_method($method) {
global $API_METHODS, $CONFIG;
@@ -230,6 +232,7 @@ function execute_method($method) {
$function = $API_METHODS[$method]["function"];
$serialised_parameters = trim($serialised_parameters, ", ");
+ // @todo document why we cannot use call_user_func_array here
$result = eval("return $function($serialised_parameters);");
// Sanity check result
@@ -257,6 +260,7 @@ function execute_method($method) {
* Get the request method.
*
* @return string HTTP request method
+ * @access private
*/
function get_call_method() {
return $_SERVER['REQUEST_METHOD'];
@@ -271,6 +275,7 @@ function get_call_method() {
* @param string $method The method
*
* @return array containing parameters as key => value
+ * @access private
*/
function get_parameters_for_method($method) {
global $API_METHODS;
@@ -300,6 +305,7 @@ function get_parameters_for_method($method) {
* Since this is called through a handler, we need to manually get the post data
*
* @return POST data as string encoded as multipart/form-data
+ * @access private
*/
function get_post_data() {
@@ -317,6 +323,7 @@ function get_post_data() {
* @return true on success or exception
* @throws APIException
* @since 1.7.0
+ * @access private
*/
function verify_parameters($method, $parameters) {
global $API_METHODS;
@@ -354,6 +361,7 @@ function verify_parameters($method, $parameters) {
* @return string or exception
* @throws APIException
* @since 1.7.0
+ * @access private
*/
function serialise_parameters($method, $parameters) {
global $API_METHODS;
@@ -438,6 +446,7 @@ function serialise_parameters($method, $parameters) {
* @return mixed
* @throws APIException
* @since 1.7.0
+ * @access private
*/
function api_auth_key() {
global $CONFIG;
@@ -468,6 +477,7 @@ function api_auth_key() {
*
* @throws SecurityException
* @since 1.7.0
+ * @access private
*/
function api_auth_hmac() {
global $CONFIG;
@@ -532,6 +542,7 @@ function api_auth_hmac() {
*
* @return stdClass Containing all the values.
* @throws APIException Detailing any error.
+ * @access private
*/
function get_and_validate_api_headers() {
$result = new stdClass;
@@ -604,6 +615,7 @@ function get_and_validate_api_headers() {
*
* @return string The php algorithm
* @throws APIException if an algorithm is not supported.
+ * @access private
*/
function map_api_hash($algo) {
$algo = strtolower(sanitise_string($algo));
@@ -636,6 +648,7 @@ function map_api_hash($algo) {
* @param string $post_hash Optional sha1 hash of the post data.
*
* @return string The HMAC signature
+ * @access private
*/
function calculate_hmac($algo, $time, $nonce, $api_key, $secret_key,
$get_variables, $post_hash = "") {
@@ -666,6 +679,7 @@ $get_variables, $post_hash = "") {
* @param string $algo The algorithm used.
*
* @return string The hash.
+ * @access private
*/
function calculate_posthash($postdata, $algo) {
$ctx = hash_init(map_api_hash($algo));
@@ -682,6 +696,7 @@ function calculate_posthash($postdata, $algo) {
* @param string $hmac The hmac string.
*
* @return bool True if replay detected, false if not.
+ * @access private
*/
function cache_hmac_check_replay($hmac) {
// cache lifetime is 25 hours (this should be related to the time drift
@@ -779,6 +794,7 @@ function remove_api_user($site_guid, $api_key) {
* session code of Elgg, that user will be logged out of all other sessions.
*
* @return bool
+ * @access private
*/
function pam_auth_usertoken() {
global $CONFIG;
@@ -823,6 +839,7 @@ function pam_auth_usertoken() {
* See if the user has a valid login sesson
*
* @return bool
+ * @access private
*/
function pam_auth_session() {
return elgg_is_logged_in();
@@ -968,6 +985,7 @@ function remove_expired_user_tokens() {
* @param array $headers The array of headers "key" => "value"
*
* @return string
+ * @access private
*/
function serialise_api_headers(array $headers) {
$headers_str = "";
@@ -1123,6 +1141,7 @@ function get_standard_api_key_array($secret_key, $api_key) {
* Simple api to return a list of all api's installed on the system.
*
* @return array
+ * @access private
*/
function list_all_apis() {
global $API_METHODS;
@@ -1144,9 +1163,21 @@ function list_all_apis() {
*
* @return string Token string or exception
* @throws SecurityException
+ * @access private
*/
function auth_gettoken($username, $password) {
- if (authenticate($username, $password)) {
+ // check if username is an email address
+ if (is_email_address($username)) {
+ $users = get_user_by_email($username);
+
+ // check if we have a unique user
+ if (is_array($users) && (count($users) == 1)) {
+ $username = $users[0]->username;
+ }
+ }
+
+ // validate username and password
+ if (true === elgg_authenticate($username, $password)) {
$token = create_user_token($username);
if ($token) {
return $token;
@@ -1174,6 +1205,9 @@ $ERRORS = array();
* @param array $vars Vars
*
* @return void
+ * @access private
+ *
+ * @throws Exception
*/
function _php_api_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
global $ERRORS;
@@ -1211,6 +1245,7 @@ function _php_api_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
* @param Exception $exception Exception
*
* @return void
+ * @access private
*/
function _php_api_exception_handler($exception) {
@@ -1233,6 +1268,7 @@ function _php_api_exception_handler($exception) {
* @param array $request Request string
*
* @return void
+ * @access private
*/
function service_handler($handler, $request) {
global $CONFIG;
@@ -1242,25 +1278,23 @@ function service_handler($handler, $request) {
$request = explode('/', $request);
// after the handler, the first identifier is response format
- // ex) http://example.org/services/api/rest/xml/?method=test
- $reponse_format = array_shift($request);
+ // ex) http://example.org/services/api/rest/json/?method=test
+ $response_format = array_shift($request);
// Which view - xml, json, ...
- if ($reponse_format) {
- elgg_set_viewtype($reponse_format);
+ if ($response_format && elgg_is_valid_view_type($response_format)) {
+ elgg_set_viewtype($response_format);
} else {
- // default to xml
- elgg_set_viewtype("xml");
+ // default to json
+ elgg_set_viewtype("json");
}
if (!isset($CONFIG->servicehandler) || empty($handler)) {
// no handlers set or bad url
header("HTTP/1.0 404 Not Found");
exit;
- } else if (isset($CONFIG->servicehandler[$handler])
- && is_callable($CONFIG->servicehandler[$handler])) {
-
+ } else if (isset($CONFIG->servicehandler[$handler]) && is_callable($CONFIG->servicehandler[$handler])) {
$function = $CONFIG->servicehandler[$handler];
- $function($request, $handler);
+ call_user_func($function, $request, $handler);
} else {
// no handler for this web service
header("HTTP/1.0 404 Not Found");
@@ -1279,10 +1313,11 @@ function service_handler($handler, $request) {
*/
function register_service_handler($handler, $function) {
global $CONFIG;
+
if (!isset($CONFIG->servicehandler)) {
$CONFIG->servicehandler = array();
}
- if (is_callable($function)) {
+ if (is_callable($function, true)) {
$CONFIG->servicehandler[$handler] = $function;
return true;
}
@@ -1297,11 +1332,13 @@ function register_service_handler($handler, $function) {
*
* @param string $handler web services type
*
- * @return 1.7.0
+ * @return void
+ * @since 1.7.0
*/
function unregister_service_handler($handler) {
global $CONFIG;
- if (isset($CONFIG->servicehandler) && isset($CONFIG->servicehandler[$handler])) {
+
+ if (isset($CONFIG->servicehandler, $CONFIG->servicehandler[$handler])) {
unset($CONFIG->servicehandler[$handler]);
}
}
@@ -1310,6 +1347,9 @@ function unregister_service_handler($handler) {
* REST API handler
*
* @return void
+ * @access private
+ *
+ * @throws SecurityException|APIException
*/
function rest_handler() {
global $CONFIG;
@@ -1364,15 +1404,17 @@ function rest_handler() {
/**
* Unit tests for API
*
- * @param sting $hook unit_test
+ * @param string $hook unit_test
* @param string $type system
* @param mixed $value Array of tests
* @param mixed $params Params
*
* @return array
+ * @access private
*/
function api_unit_test($hook, $type, $value, $params) {
global $CONFIG;
+
$value[] = $CONFIG->path . 'engine/tests/services/api.php';
return $value;
}
@@ -1381,6 +1423,7 @@ function api_unit_test($hook, $type, $value, $params) {
* Initialise the API subsystem.
*
* @return void
+ * @access private
*/
function api_init() {
// Register a page handler, so we can have nice URLs
@@ -1393,15 +1436,18 @@ function api_init() {
elgg_echo("system.api.list"), "GET", false, false);
// The authentication token api
- expose_function("auth.gettoken",
- "auth_gettoken", array(
- 'username' => array ('type' => 'string'),
- 'password' => array ('type' => 'string'),
- ),
- elgg_echo('auth.gettoken'),
- 'POST',
- false,
- false);
+ expose_function(
+ "auth.gettoken",
+ "auth_gettoken",
+ array(
+ 'username' => array ('type' => 'string'),
+ 'password' => array ('type' => 'string'),
+ ),
+ elgg_echo('auth.gettoken'),
+ 'POST',
+ false,
+ false
+ );
}
diff --git a/engine/lib/widgets.php b/engine/lib/widgets.php
index cc3cf20e4..699462a1b 100644
--- a/engine/lib/widgets.php
+++ b/engine/lib/widgets.php
@@ -257,6 +257,7 @@ function elgg_get_widget_types($context = "", $exact = false) {
* Regsiter entity of object, widget as ElggWidget objects
*
* @return void
+ * @access private
*/
function elgg_widget_run_once() {
add_subtype("object", "widget", "ElggWidget");
@@ -266,6 +267,7 @@ function elgg_widget_run_once() {
* Function to initialize widgets functionality
*
* @return void
+ * @access private
*/
function elgg_widgets_init() {
elgg_register_action('widgets/save');
@@ -281,7 +283,26 @@ function elgg_widgets_init() {
* Gets a list of events to create default widgets for and
* register menu items for default widgets with the admin section.
*
+ * A plugin that wants to register a new context for default widgets should
+ * register for the plugin hook 'get_list', 'default_widgets'. The handler
+ * can register the new type of default widgets by adding an associate array to
+ * the return value array like this:
+ * array(
+ * 'name' => elgg_echo('profile'),
+ * 'widget_context' => 'profile',
+ * 'widget_columns' => 3,
+ *
+ * 'event' => 'create',
+ * 'entity_type' => 'user',
+ * 'entity_subtype' => ELGG_ENTITIES_ANY_VALUE,
+ * );
+ *
+ * The first set of keys define information about the new type of default
+ * widgets and the second set determine what event triggers the creation of the
+ * new widgets.
+ *
* @return void
+ * @access private
*/
function elgg_default_widgets_init() {
global $CONFIG;
@@ -295,77 +316,85 @@ function elgg_default_widgets_init() {
// override permissions for creating widget on logged out / just created entities
elgg_register_plugin_hook_handler('container_permissions_check', 'object', 'elgg_default_widgets_permissions_override');
+ // only register the callback once per event
+ $events = array();
foreach ($default_widgets as $info) {
- elgg_register_event_handler($info['event'], $info['entity_type'], 'elgg_default_widgets_hook');
+ $events[$info['event'] . ',' . $info['entity_type']] = $info;
+ }
+ foreach ($events as $info) {
+ elgg_register_event_handler($info['event'], $info['entity_type'], 'elgg_create_default_widgets');
}
}
}
/**
- * Checks for plugins who have registered default widgets and
- * hooks into events to save.
+ * Creates default widgets
+ *
+ * This plugin hook handler is registered for events based on what kinds of
+ * default widgets have been registered. See elgg_default_widgets_init() for
+ * information on registering new default widget contexts.
*
* @param string $event The event
* @param string $type The type of object
- * @param object $object The object
- * @return null
+ * @param ElggEntity $entity The entity being created
+ * @return void
+ * @access private
*/
-function elgg_default_widgets_hook($event, $type, $object) {
+function elgg_create_default_widgets($event, $type, $entity) {
$default_widget_info = elgg_get_config('default_widget_info');
- if (!$default_widget_info) {
- return null;
+ if (!$default_widget_info || !$entity) {
+ return;
}
- $subtype = $object->getSubtype();
+ $type = $entity->getType();
+ $subtype = $entity->getSubtype();
// event is already guaranteed by the hook registration.
// need to check subtype and type.
- foreach ($default_widget_info as $temp) {
- if ($temp['entity_type'] == $type && $temp['entity_subtype'] == $subtype) {
- $info = $temp;
- break;
- }
- }
-
- // need to be able to access everything
- $old_ia = elgg_get_ignore_access(true);
- elgg_push_context('create_default_widgets');
-
- // pull in by widget context with widget owners as the site
- // not using elgg_get_widgets() because it sorts by columns and we don't care right now.
- $options = array(
- 'type' => 'object',
- 'subtype' => 'widget',
- 'owner_guid' => elgg_get_site_entity()->guid,
- 'private_setting_name' => 'context',
- 'private_setting_value' => $info['context'],
- 'limit' => 0
- );
-
- $widgets = elgg_get_entities_from_private_settings($options);
-
- foreach ($widgets as $widget) {
- // change the container and owner
- $new_widget = clone $widget;
- $new_widget->container_guid = $object->guid;
- $new_widget->owner_guid = $object->guid;
-
- // pull in settings
- $settings = get_all_private_settings($widget->guid);
-
- foreach ($settings as $name => $value) {
- $new_widget->$name = $value;
+ foreach ($default_widget_info as $info) {
+ if ($info['entity_type'] == $type) {
+ if ($info['entity_subtype'] == ELGG_ENTITIES_ANY_VALUE || $info['entity_subtype'] == $subtype) {
+
+ // need to be able to access everything
+ $old_ia = elgg_set_ignore_access(true);
+ elgg_push_context('create_default_widgets');
+
+ // pull in by widget context with widget owners as the site
+ // not using elgg_get_widgets() because it sorts by columns and we don't care right now.
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => 'widget',
+ 'owner_guid' => elgg_get_site_entity()->guid,
+ 'private_setting_name' => 'context',
+ 'private_setting_value' => $info['widget_context'],
+ 'limit' => 0
+ );
+
+ $widgets = elgg_get_entities_from_private_settings($options);
+ /* @var ElggWidget[] $widgets */
+
+ foreach ($widgets as $widget) {
+ // change the container and owner
+ $new_widget = clone $widget;
+ $new_widget->container_guid = $entity->guid;
+ $new_widget->owner_guid = $entity->guid;
+
+ // pull in settings
+ $settings = get_all_private_settings($widget->guid);
+
+ foreach ($settings as $name => $value) {
+ $new_widget->$name = $value;
+ }
+
+ $new_widget->save();
+ }
+
+ elgg_set_ignore_access($old_ia);
+ elgg_pop_context();
+ }
}
-
- $new_widget->save();
}
-
- elgg_get_ignore_access($old_ia);
- elgg_pop_context();
-
- // failure here shouldn't stop the event.
- return null;
}
/**
@@ -376,6 +405,7 @@ function elgg_default_widgets_hook($event, $type, $object) {
* @param string $return Value
* @param mixed $params Params
* @return true|null
+ * @access private
*/
function elgg_default_widgets_permissions_override($hook, $type, $return, $params) {
if ($type == 'object' && $params['subtype'] == 'widget') {
@@ -387,4 +417,4 @@ function elgg_default_widgets_permissions_override($hook, $type, $return, $param
elgg_register_event_handler('init', 'system', 'elgg_widgets_init');
// register default widget hooks from plugins
-elgg_register_event_handler('ready', 'system', 'elgg_default_widgets_init'); \ No newline at end of file
+elgg_register_event_handler('ready', 'system', 'elgg_default_widgets_init');
diff --git a/engine/lib/xml-rpc.php b/engine/lib/xml-rpc.php
index b63d626df..bfe1a8645 100644
--- a/engine/lib/xml-rpc.php
+++ b/engine/lib/xml-rpc.php
@@ -15,6 +15,7 @@
* @param array $parameters An array of params
*
* @return array
+ * @access private
*/
function xmlrpc_parse_params($parameters) {
$result = array();
@@ -32,6 +33,7 @@ function xmlrpc_parse_params($parameters) {
* @param XMLObject $object And object
*
* @return mixed
+ * @access private
*/
function xmlrpc_scalar_value($object) {
if ($object->name == 'param') {
@@ -110,6 +112,7 @@ function register_xmlrpc_handler($method, $handler) {
* @param XMLRPCCall $parameters The call and parameters.
*
* @return XMLRPCCall
+ * @access private
*/
function trigger_xmlrpc_handler(XMLRPCCall $parameters) {
global $XML_RPC_HANDLERS;
@@ -148,6 +151,7 @@ function trigger_xmlrpc_handler(XMLRPCCall $parameters) {
* @param array $vars Vars
*
* @return void
+ * @access private
*/
function _php_xmlrpc_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
$error = date("Y-m-d H:i:s (T)") . ": \"" . $errmsg . "\" in file "
@@ -177,6 +181,7 @@ function _php_xmlrpc_error_handler($errno, $errmsg, $filename, $linenum, $vars)
* @param Exception $exception The exception
*
* @return void
+ * @access private
*/
function _php_xmlrpc_exception_handler($exception) {
diff --git a/engine/lib/xml.php b/engine/lib/xml.php
index 813bc4ee0..497459d83 100644
--- a/engine/lib/xml.php
+++ b/engine/lib/xml.php
@@ -101,47 +101,11 @@ function serialise_array_to_xml(array $data, $n = 0) {
/**
* Parse an XML file into an object.
- * Based on code from http://de.php.net/manual/en/function.xml-parse-into-struct.php by
- * efredricksen at gmail dot com
*
* @param string $xml The XML
*
- * @return object
+ * @return ElggXMLElement
*/
function xml_to_object($xml) {
- $parser = xml_parser_create();
-
- // Parse $xml into a structure
- xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
- xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
- xml_parse_into_struct($parser, $xml, $tags);
-
- xml_parser_free($parser);
-
- $elements = array();
- $stack = array();
-
- foreach ($tags as $tag) {
- $index = count($elements);
-
- if ($tag['type'] == "complete" || $tag['type'] == "open") {
- $elements[$index] = new XmlElement;
- $elements[$index]->name = $tag['tag'];
- $elements[$index]->attributes = elgg_extract('attributes', $tag, '');
- $elements[$index]->content = elgg_extract('value', $tag, '');
-
- if ($tag['type'] == "open") {
- $elements[$index]->children = array();
- $stack[count($stack)] = &$elements;
- $elements = &$elements[$index]->children;
- }
- }
-
- if ($tag['type'] == "close") {
- $elements = &$stack[count($stack) - 1];
- unset($stack[count($stack) - 1]);
- }
- }
-
- return $elements[0];
+ return new ElggXMLElement($xml);
}