diff options
Diffstat (limited to 'engine/lib')
31 files changed, 1271 insertions, 326 deletions
diff --git a/engine/lib/access.php b/engine/lib/access.php index dba1e1ec6..6be252c6a 100644 --- a/engine/lib/access.php +++ b/engine/lib/access.php @@ -671,8 +671,10 @@ function add_user_to_access_collection($user_guid, $collection_id) { 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}"; + SET access_collection_id = $collection_id, user_guid = $user_guid + ON DUPLICATE KEY UPDATE user_guid = user_guid"; $result = insert_data($q); return $result !== false; diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php index 5049d455b..f32dee0f0 100644 --- a/engine/lib/annotations.php +++ b/engine/lib/annotations.php @@ -209,9 +209,11 @@ 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 + * @return mixed Null if the metadata name is invalid. Bool on success or fail. * @since 1.8.0 */ function elgg_delete_annotations(array $options) { diff --git a/engine/lib/cache.php b/engine/lib/cache.php index e71ef332d..c117b9ec9 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,36 +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; } /** - * Reset the file path cache. + * Reset the system cache by deleting the caches * - * @return bool + * @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 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); } @@ -64,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) { @@ -85,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 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 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() { + return 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() { + return elgg_enable_system_cache(); +} +/** + * @access private + */ +function elgg_disable_filepath_cache() { + return elgg_disable_system_cache(); } /* Simplecache */ @@ -333,7 +369,7 @@ function elgg_invalidate_simplecache() { $return = true; while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { - $return = $return && unlink($CONFIG->dataroot . 'views_simplecache/' . $file); + $return &= unlink($CONFIG->dataroot . 'views_simplecache/' . $file); } } closedir($handle); @@ -346,9 +382,70 @@ function elgg_invalidate_simplecache() { } foreach ($viewtypes as $viewtype) { - $return = $return && datalist_set("simplecache_lastupdate_$viewtype", 0); - $return = $return && datalist_set("simplecache_lastcached_$viewtype", 0); + $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) { + foreach ($CONFIG->translations as $lang => $map) { + elgg_save_system_cache("$lang.php", serialize($map)); + } + } +} + +elgg_register_event_handler('ready', 'system', '_elgg_cache_init'); diff --git a/engine/lib/calendar.php b/engine/lib/calendar.php new file mode 100644 index 000000000..9a06c5292 --- /dev/null +++ b/engine/lib/calendar.php @@ -0,0 +1,571 @@ +<?php +/** + * Elgg calendar / entity / event functions. + * + * @package Elgg.Core + * @subpackage Calendar + * + * @todo Implement or remove + */ + +/** + * 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 + */ +function get_day_start($day = null, $month = null, $year = null) { + 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 + */ +function get_day_end($day = null, $month = null, $year = null) { + 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 + */ +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) { + 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 + */ +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) { + + 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 + */ +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) { + + 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 + */ +function get_todays_entities($type = "", $subtype = "", $owner_guid = 0, $order_by = "", +$limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null) { + + $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 + */ +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) { + + $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 + */ +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) { + + $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 + */ +function list_notable_entities($start_time, $end_time, $type= "", $subtype = "", $owner_guid = 0, +$limit = 10, $fullview = true, $listtypetoggle = false, $navigation = true) { + + $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 + */ +function list_todays_entities($type= "", $subtype = "", $owner_guid = 0, $limit = 10, +$fullview = true, $listtypetoggle = false, $navigation = true) { + + $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/configuration.php b/engine/lib/configuration.php index 3fade8155..9bf1529d6 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 @@ -302,7 +303,7 @@ function datalist_set($name, $value) { . " set name = '{$sanitised_name}', value = '{$sanitised_value}'" . " ON DUPLICATE KEY UPDATE value='{$sanitised_value}'"); - if ($success) { + if ($success !== FALSE) { $DATALIST_CACHE[$name] = $value; return true; } else { @@ -517,10 +518,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; @@ -533,37 +534,49 @@ 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(); +} + +/** + * 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/", - 'wwwroot' => $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/", - 'sitename' => 'New Elgg site', ); foreach ($defaults as $name => $value) { @@ -572,25 +585,6 @@ function set_default_config() { } } - $CONFIG->context = array(); - - 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 - * @access private - */ -function configuration_boot() { - global $CONFIG; - $path = datalist_get('path'); if (!empty($path)) { $CONFIG->path = $path; @@ -605,22 +599,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; + $CONFIG->system_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->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(); + + // 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; -elgg_register_event_handler('boot', 'system', 'configuration_boot', 10); + $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/database.php b/engine/lib/database.php index 444bb7cc4..cc2b99f6a 100644 --- a/engine/lib/database.php +++ b/engine/lib/database.php @@ -189,22 +189,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 - * @access private - */ -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 @@ -757,6 +741,13 @@ function sanitize_int($int, $signed = true) { } /** - * @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.8.php b/engine/lib/deprecated-1.8.php index e1866498b..4b9d41543 100644 --- a/engine/lib/deprecated-1.8.php +++ b/engine/lib/deprecated-1.8.php @@ -1674,7 +1674,7 @@ 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 Use elgg_generate_plugin_entities() and elgg_set_plugin_priorities() * @@ -1841,7 +1841,7 @@ 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 Use ElggPlugin->activate() * @@ -1882,7 +1882,7 @@ 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 Use ElggPlugin->deactivate() * diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index 9035d95f2..b55958a6c 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -995,7 +995,8 @@ function elgg_trigger_plugin_hook($hook, $type, $params = null, $returnvalue = n * @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(); @@ -1011,7 +1012,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(); @@ -1959,7 +1970,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) { @@ -2010,8 +2021,14 @@ function elgg_walled_garden_index() { elgg_load_css('elgg.walled_garden'); elgg_load_js('elgg.walled_garden'); - $body = elgg_view('core/walled_garden/body'); + $content = elgg_view('core/walled_garden/login'); + $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 @@ -2019,6 +2036,24 @@ function elgg_walled_garden_index() { } /** + * 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. * @@ -2038,6 +2073,8 @@ function elgg_walled_garden() { 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(); @@ -2045,6 +2082,36 @@ function elgg_walled_garden() { } /** + * 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(); + + register_translations(dirname(dirname(dirname(__FILE__))) . "/languages/"); + + _elgg_load_site_config(); + + _elgg_load_cache(); +} + +/** * Elgg's main init. * * Handles core actions for comments, the JS pagehandler, and the shutdown function. @@ -2167,6 +2234,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 82452fba1..4875b2c2f 100644 --- a/engine/lib/entities.php +++ b/engine/lib/entities.php @@ -738,6 +738,7 @@ 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 @@ -960,8 +961,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(); @@ -1378,6 +1379,10 @@ function disable_entity($guid, $reason = "", $recursive = true) { } if ($recursive) { + $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 @@ -1391,6 +1396,8 @@ function disable_entity($guid, $reason = "", $recursive = true) { $e->disable($reason); } } + access_show_hidden_entities($hidden); + elgg_set_ignore_access($ia); } $entity->disableMetadata(); @@ -1514,18 +1521,23 @@ function delete_entity($guid, $recursive = true) { $entity_disable_override = 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", 'entity_row_to_elggstar'); - if ($sub_entities) { - foreach ($sub_entities as $e) { - // check for equality so that an entity that is its own - // owner or container does not cause infinite loop - if ($e->guid != $guid) { - $e->delete(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); @@ -1959,7 +1971,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; } @@ -1994,7 +2006,7 @@ 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; } @@ -2162,31 +2174,8 @@ function elgg_list_registered_entities(array $options = array()) { $entities = array(); } - 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. - * - * @return bool - * @elgg_plugin_hook_handler permissions_check all - * @elgg_plugin_hook_handler permissions_check:metadata all - * @access private - */ -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; - } - - // consult next function - return NULL; + $options['count'] = $count; + return elgg_view_entity_list($entities, $options); } /** @@ -2303,11 +2292,6 @@ function entities_init() { 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'); } diff --git a/engine/lib/group.php b/engine/lib/group.php index 29330eeca..feb1f1e7f 100644 --- a/engine/lib/group.php +++ b/engine/lib/group.php @@ -261,16 +261,24 @@ function group_gatekeeper($forward = true) { 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; - } + if (!$group->isPublicMembership()) { + // closed group so must be member or an admin + + if (!elgg_is_logged_in()) { + $allowed = false; + if ($forward == true) { + $_SESSION['last_forward_from'] = current_page_url(); + register_error(elgg_echo('loggedinrequired')); + forward('', 'login'); + } + } else if (!$group->isMember(elgg_get_logged_in_user_entity())) { + $allowed = false; + } - // Admin override - if (elgg_is_admin_logged_in()) { - $allowed = true; + // Admin override + if (elgg_is_admin_logged_in()) { + $allowed = true; + } } } } diff --git a/engine/lib/languages.php b/engine/lib/languages.php index 0400843af..bf6829a39 100644 --- a/engine/lib/languages.php +++ b/engine/lib/languages.php @@ -145,9 +145,16 @@ function elgg_echo($message_key, $args = array(), $language = "") { function register_translations($path, $load_all = false) { global $CONFIG; + static $load_from_cache; + static $cache_loaded_langs; + if (!isset($load_from_cache)) { + $load_from_cache = $CONFIG->system_cache_enabled; + $cache_loaded_langs = array(); + } + $path = sanitise_filepath($path); - // Make a note of this path just incase we need to register this language later + // Make a note of this path just in case we need to register this language later if (!isset($CONFIG->language_paths)) { $CONFIG->language_paths = array(); } @@ -155,7 +162,6 @@ function register_translations($path, $load_all = false) { // Get the current language based on site defaults and user preference $current_language = get_current_language(); - elgg_log("Translations loaded from: $path"); // only load these files unless $load_all is true. $load_language_files = array( @@ -165,6 +171,32 @@ function register_translations($path, $load_all = false) { $load_language_files = array_unique($load_language_files); + if ($load_from_cache && !$load_all) { + // load language files from cache + $data = array(); + foreach ($load_language_files as $lang_file) { + $lang = substr($lang_file, 0, strpos($lang_file, '.')); + if (!isset($cache_loaded_langs[$lang])) { + $data[$lang] = elgg_load_system_cache($lang_file); + if ($data[$lang]) { + $cache_loaded_langs[$lang] = true; + } else { + // this language file not cached yet + $load_from_cache = false; + } + } + } + + // are we still suppose to load from cache + if ($load_from_cache) { + foreach ($data as $lang => $map) { + add_translation($lang, unserialize($map)); + } + $CONFIG->i18n_loaded_from_cache = true; + return true; + } + } + $handle = opendir($path); if (!$handle) { elgg_log("Could not open language path: $path", 'ERROR'); @@ -186,6 +218,11 @@ function register_translations($path, $load_all = false) { } } + elgg_log("Translations loaded from: $path"); + + // make sure caching code saves language data if system cache is on + $CONFIG->i18n_loaded_from_cache = false; + return $return; } @@ -311,5 +348,3 @@ function elgg_languages_init() { } elgg_register_event_handler('init', 'system', 'elgg_languages_init'); - -register_translations(dirname(dirname(dirname(__FILE__))) . "/languages/"); diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php index 19e8aa3c8..34a36d86e 100644 --- a/engine/lib/metadata.php +++ b/engine/lib/metadata.php @@ -294,11 +294,11 @@ 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 + * @param array $options An options array. {@see elgg_get_metadata()} + * @return mixed Null if the metadata name is invalid. Bool on success or fail. * @since 1.8.0 */ function elgg_delete_metadata(array $options) { @@ -307,7 +307,8 @@ function elgg_delete_metadata(array $options) { } $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'); + return $result; } /** @@ -745,7 +746,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 * @@ -754,12 +755,7 @@ 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'); return $ar; } diff --git a/engine/lib/metastrings.php b/engine/lib/metastrings.php index 62b60e279..d7cc4e0bc 100644 --- a/engine/lib/metastrings.php +++ b/engine/lib/metastrings.php @@ -727,38 +727,11 @@ function elgg_batch_metastring_based_objects(array $options, $callback) { return false; } - switch($options['metastring_type']) { - case 'metadata': - $objects = elgg_get_metadata($options); - break; - - case 'annotations': - $objects = elgg_get_annotations($options); - break; - - default: - return false; - } - - if (!is_array($objects)) { - $r = false; - } elseif (empty($objects)) { - // ElggBatch returns null if the results are an empty array - $r = null; - } else { - $r = true; - foreach($objects as $object) { - $r = $r && $callback($object); - } - } + // @todo restore once ElggBatch supports callbacks that delete rows. + $batch = new ElggBatch('elgg_get_metastring_based_objects', $options, $callback, 50, false); + $r = $batch->callbackResult; return $r; - -// // @todo restore once ElggBatch supports callbacks that delete rows. -// $batch = new ElggBatch('elgg_get_metastring_based_objects', $options, $callback); -// $r = $batch->callbackResult; -// -// return $r; } /** diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php index dcbd7b397..a7984ce5a 100644 --- a/engine/lib/navigation.php +++ b/engine/lib/navigation.php @@ -78,7 +78,11 @@ * 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 diff --git a/engine/lib/output.php b/engine/lib/output.php index b96cf354c..b1245a924 100644 --- a/engine/lib/output.php +++ b/engine/lib/output.php @@ -310,15 +310,19 @@ function elgg_get_friendly_title($title) { return $result; } + // @todo not using this because of locale concerns //$title = iconv('UTF-8', 'ASCII//TRANSLIT', $title); + // @todo this uses a utf8 character class. can use if + // we want to support utf8 in the url. + //$title = preg_replace('/[^\p{L}\- ]/u', '', $title); + // use A-Za-z0-9_ instead of \w because \w is locale sensitive - $title = preg_replace("/[^A-Za-z0-9_ ]/", "", $title); - $title = preg_replace("/[^\w ]/", "", $title); + $title = preg_replace("/[^A-Za-z0-9_\- ]/", "", $title); $title = str_replace(" ", "-", $title); $title = str_replace("--", "-", $title); $title = trim($title); - $title = strtolower($title); + $title = elgg_strtolower($title); return $title; } diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php index 7968f4a6e..123fb18d8 100644 --- a/engine/lib/plugins.php +++ b/engine/lib/plugins.php @@ -62,7 +62,7 @@ function elgg_get_plugin_ids_in_dir($dir = null) { $dir = elgg_get_plugins_path(); } - $plugin_idss = array(); + $plugin_ids = array(); $handle = opendir($dir); if ($handle) { @@ -298,19 +298,13 @@ 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; } @@ -332,12 +326,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; } diff --git a/engine/lib/relationships.php b/engine/lib/relationships.php index fabe2d2d6..f50c4a485 100644 --- a/engine/lib/relationships.php +++ b/engine/lib/relationships.php @@ -290,7 +290,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); } diff --git a/engine/lib/sessions.php b/engine/lib/sessions.php index 97a05e2e8..419d36707 100644 --- a/engine/lib/sessions.php +++ b/engine/lib/sessions.php @@ -127,6 +127,10 @@ 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 @@ -355,7 +359,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; @@ -379,7 +383,7 @@ function logout() { * @return bool * @access private */ -function session_init($event, $object_type, $object) { +function _elgg_session_boot($event, $object_type, $object) { global $DB_PREFIX, $CONFIG; // Use database for sessions @@ -444,8 +448,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'); @@ -655,4 +659,4 @@ function _elgg_session_gc($maxlifetime) { return true; } -elgg_register_event_handler("boot", "system", "session_init", 20); +elgg_register_event_handler('boot', 'system', '_elgg_session_boot', 2); diff --git a/engine/lib/sites.php b/engine/lib/sites.php index 337b2d180..850092cad 100644 --- a/engine/lib/sites.php +++ b/engine/lib/sites.php @@ -231,43 +231,6 @@ 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 - * @access private - */ -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 @@ -283,3 +246,6 @@ function sites_test($hook, $type, $value, $params) { $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 7c170f3bb..e1f95ed97 100644 --- a/engine/lib/statistics.php +++ b/engine/lib/statistics.php @@ -95,14 +95,12 @@ function get_number_users($show_deactivated = false) { * @return string */ function get_online_users() { - $offset = get_input('offset', 0); $count = find_active_users(600, 10, $offset, true); $objects = find_active_users(600, 10, $offset); if ($objects) { return elgg_view_entity_list($objects, array( 'count' => $count, - 'offset' => $offset, 'limit' => 10 )); } diff --git a/engine/lib/system_log.php b/engine/lib/system_log.php index fd5644135..28d90be56 100644 --- a/engine/lib/system_log.php +++ b/engine/lib/system_log.php @@ -11,6 +11,7 @@ * Retrieve the system log based on a number of parameters. * * @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 +22,12 @@ * @param int $timebefore Lower time limit * @param int $timeafter Upper time limit * @param int $object_id GUID of an object - * + * @param str $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) { +$limit = 10, $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $object_id = 0, +$ip_address = false) { global $CONFIG; @@ -37,16 +39,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 +79,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 +98,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 { @@ -171,6 +179,7 @@ function system_log($object, $event) { $object_subtype = $object->getSubtype(); $event = sanitise_string($event); $time = time(); + $ip_address = sanitise_string($_SERVER['REMOTE_ADDR']); $performed_by = elgg_get_logged_in_user_guid(); if (isset($object->access_id)) { @@ -194,10 +203,10 @@ 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); diff --git a/engine/lib/upgrades/2011010101.php b/engine/lib/upgrades/2011010101.php index b063c249b..a1ee92622 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'); 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..07732f261 --- /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 http://trac.elgg.org/ticket/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/user_settings.php b/engine/lib/user_settings.php index af30d8f0d..e4069fb53 100644 --- a/engine/lib/user_settings.php +++ b/engine/lib/user_settings.php @@ -33,9 +33,9 @@ function users_settings_save() { * @access private */ function elgg_set_user_password() { - $current_password = get_input('current_password'); - $password = get_input('password'); - $password2 = get_input('password2'); + $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_guid) { diff --git a/engine/lib/users.php b/engine/lib/users.php index c38bb676e..6a881777e 100644 --- a/engine/lib/users.php +++ b/engine/lib/users.php @@ -497,20 +497,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, + )); } /** @@ -606,11 +612,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; @@ -963,8 +969,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()); } } } diff --git a/engine/lib/views.php b/engine/lib/views.php index e59edac96..ca0ce7196 100644 --- a/engine/lib/views.php +++ b/engine/lib/views.php @@ -560,7 +560,7 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie * * @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 = '') { @@ -969,12 +969,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; } @@ -1330,21 +1325,18 @@ 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 false; } /** @@ -1671,5 +1663,5 @@ function elgg_views_boot() { } } -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 07be76ec6..da3ed76a9 100644 --- a/engine/lib/web_services.php +++ b/engine/lib/web_services.php @@ -1165,7 +1165,7 @@ function list_all_apis() { * @access private */ function auth_gettoken($username, $password) { - if (elgg_authenticate($username, $password)) { + if (true === elgg_authenticate($username, $password)) { $token = create_user_token($username); if ($token) { return $token; diff --git a/engine/lib/xml-rpc.php b/engine/lib/xml-rpc.php new file mode 100644 index 000000000..bfe1a8645 --- /dev/null +++ b/engine/lib/xml-rpc.php @@ -0,0 +1,203 @@ +<?php +/** + * Elgg XML-RPC library. + * Contains functions and classes to handle XML-RPC services, currently only server only. + * + * @package Elgg.Core + * @subpackage XMLRPC + */ + +/** + * parse XMLRPCCall parameters + * + * Convert an XMLRPCCall result array into native data types + * + * @param array $parameters An array of params + * + * @return array + * @access private + */ +function xmlrpc_parse_params($parameters) { + $result = array(); + + foreach ($parameters as $parameter) { + $result[] = xmlrpc_scalar_value($parameter); + } + + return $result; +} + +/** + * Extract the scalar value of an XMLObject type result array + * + * @param XMLObject $object And object + * + * @return mixed + * @access private + */ +function xmlrpc_scalar_value($object) { + if ($object->name == 'param') { + $object = $object->children[0]->children[0]; + } + + switch ($object->name) { + case 'string': + return $object->content; + + case 'array': + foreach ($object->children[0]->children as $child) { + $value[] = xmlrpc_scalar_value($child); + } + return $value; + + case 'struct': + foreach ($object->children as $child) { + if (isset($child->children[1]->children[0])) { + $value[$child->children[0]->content] = xmlrpc_scalar_value($child->children[1]->children[0]); + } else { + $value[$child->children[0]->content] = $child->children[1]->content; + } + } + return $value; + + case 'boolean': + return (boolean) $object->content; + + case 'i4': + case 'int': + return (int) $object->content; + + case 'double': + return (double) $object->content; + + case 'dateTime.iso8601': + return (int) strtotime($object->content); + + case 'base64': + return base64_decode($object->content); + + case 'value': + return xmlrpc_scalar_value($object->children[0]); + + default: + // @todo unsupported, throw an error + return false; + } +} + +// Functions for adding handlers ////////////////////////////////////////////////////////// + +/** XML-RPC Handlers */ +global $XML_RPC_HANDLERS; +$XML_RPC_HANDLERS = array(); + +/** + * Register a method handler for a given XML-RPC method. + * + * @param string $method Method parameter. + * @param string $handler The handler function. This function accepts + * one XMLRPCCall object and must return a XMLRPCResponse object. + * + * @return bool + */ +function register_xmlrpc_handler($method, $handler) { + global $XML_RPC_HANDLERS; + + $XML_RPC_HANDLERS[$method] = $handler; +} + +/** + * Trigger a method call and pass the relevant parameters to the funciton. + * + * @param XMLRPCCall $parameters The call and parameters. + * + * @return XMLRPCCall + * @access private + */ +function trigger_xmlrpc_handler(XMLRPCCall $parameters) { + global $XML_RPC_HANDLERS; + + // Go through and see if we have a handler + if (isset($XML_RPC_HANDLERS[$parameters->getMethodName()])) { + $handler = $XML_RPC_HANDLERS[$parameters->getMethodName()]; + $result = $handler($parameters); + + if (!($result instanceof XMLRPCResponse)) { + $msg = elgg_echo('InvalidParameterException:UnexpectedReturnFormat', + array($parameters->getMethodName())); + throw new InvalidParameterException($msg); + } + + // Result in right format, return it. + return $result; + } + + // if no handler then throw exception + $msg = elgg_echo('NotImplementedException:XMLRPCMethodNotImplemented', + array($parameters->getMethodName())); + throw new NotImplementedException($msg); +} + +/** + * PHP Error handler function. + * This function acts as a wrapper to catch and report PHP error messages. + * + * @see http://uk3.php.net/set-error-handler + * + * @param int $errno Error number + * @param string $errmsg Human readable message + * @param string $filename Filename + * @param int $linenum Line number + * @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 " + . $filename . " (line " . $linenum . ")"; + + switch ($errno) { + case E_USER_ERROR: + error_log("ERROR: " . $error); + + // Since this is a fatal error, we want to stop any further execution but do so gracefully. + throw new Exception("ERROR: " . $error); + break; + + case E_WARNING : + case E_USER_WARNING : + error_log("WARNING: " . $error); + break; + + default: + error_log("DEBUG: " . $error); + } +} + +/** + * PHP Exception handler for XMLRPC. + * + * @param Exception $exception The exception + * + * @return void + * @access private + */ +function _php_xmlrpc_exception_handler($exception) { + + error_log("*** FATAL EXCEPTION (XML-RPC) *** : " . $exception); + + $code = $exception->getCode(); + + if ($code == 0) { + $code = -32400; + } + + $result = new XMLRPCErrorResponse($exception->getMessage(), $code); + + $vars = array('result' => $result); + + $content = elgg_view("xml-rpc/output", $vars); + + echo elgg_view_page($exception->getMessage(), $content); +} |