From 2c7fe16e6d8d135109c6da60739e4ffad99876d5 Mon Sep 17 00:00:00 2001 From: Paweł Sroka Date: Wed, 6 Mar 2013 19:04:35 +0100 Subject: Refs #5199 - Adds additional info to locate output start in case of headers already sent exception --- engine/lib/elgglib.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engine') diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index 74b70f9fb..2ae307392 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -128,7 +128,7 @@ function elgg_load_library($name) { * @throws SecurityException */ function forward($location = "", $reason = 'system') { - if (!headers_sent()) { + if (!headers_sent($file, $line)) { if ($location === REFERER) { $location = $_SERVER['HTTP_REFERER']; } @@ -147,7 +147,7 @@ function forward($location = "", $reason = 'system') { exit; } } else { - throw new SecurityException(elgg_echo('SecurityException:ForwardFailedToRedirect')); + throw new SecurityException(elgg_echo('SecurityException:ForwardFailedToRedirect', array($file, $line))); } } -- cgit v1.2.3 From 4cd8bc8d68008f509ce97b2e31e1e5ccfec7bdf0 Mon Sep 17 00:00:00 2001 From: Cash Costello Date: Fri, 15 Mar 2013 08:22:32 -0400 Subject: fixed some coding standards issues as detected by code sniffer --- engine/classes/ElggPriorityList.php | 13 +++++++++---- engine/classes/ElggTranslit.php | 18 ++++++++++-------- 2 files changed, 19 insertions(+), 12 deletions(-) (limited to 'engine') diff --git a/engine/classes/ElggPriorityList.php b/engine/classes/ElggPriorityList.php index b5f8fe163..416df885c 100644 --- a/engine/classes/ElggPriorityList.php +++ b/engine/classes/ElggPriorityList.php @@ -165,9 +165,9 @@ class ElggPriorityList /** * Move an existing element to a new priority. * - * @param mixed $element The element to move - * @param int $new_priority The new priority for the element - * @param bool $strict Whether to check the type of the element match + * @param mixed $element The element to move + * @param int $new_priority The new priority for the element + * @param bool $strict Whether to check the type of the element match * @return bool */ public function move($element, $new_priority, $strict = false) { @@ -354,7 +354,12 @@ class ElggPriorityList return ($key !== NULL && $key !== FALSE); } - // Countable + /** + * Countable interface + * + * @see Countable::count() + * @return int + */ public function count() { return count($this->elements); } diff --git a/engine/classes/ElggTranslit.php b/engine/classes/ElggTranslit.php index 676c59fc8..79116fc01 100644 --- a/engine/classes/ElggTranslit.php +++ b/engine/classes/ElggTranslit.php @@ -20,11 +20,10 @@ * and is licensed under the LGPL. For more information, see * . * - * @author Konsta Vesterinen - * @author Jonathan H. Wage - * - * @author Steve Clay - * @package Elgg.Core + * @package Elgg.Core + * @author Konsta Vesterinen + * @author Jonathan H. Wage + * @author Steve Clay * * @access private Plugin authors should not use this directly */ @@ -32,8 +31,9 @@ class ElggTranslit { /** * Create a version of a string for embedding in a URL - * @param string $string a UTF-8 string - * @param string $separator + * + * @param string $string A UTF-8 string + * @param string $separator The character to separate words with * @return string */ static public function urlize($string, $separator = '-') { @@ -98,6 +98,7 @@ class ElggTranslit { /** * Transliterate Western multibyte chars to ASCII + * * @param string $utf8 a UTF-8 string * @return string */ @@ -247,6 +248,7 @@ class ElggTranslit { /** * Tests that "normalizer_normalize" exists and works + * * @return bool */ static public function hasNormalizerSupport() { @@ -255,7 +257,7 @@ class ElggTranslit { $form_c = "\xC3\x85"; // 'LATIN CAPITAL LETTER A WITH RING ABOVE' (U+00C5) $form_d = "A\xCC\x8A"; // A followed by 'COMBINING RING ABOVE' (U+030A) $ret = (function_exists('normalizer_normalize') - && $form_c === normalizer_normalize($form_d)); + && $form_c === normalizer_normalize($form_d)); } return $ret; } -- cgit v1.2.3 From a2ecf54d56d9f877e6f0f8ac6d841cee6187aac4 Mon Sep 17 00:00:00 2001 From: cash Date: Fri, 15 Mar 2013 11:18:05 -0400 Subject: more coding standard fixes --- engine/classes/ElggEntity.php | 11 +++++------ engine/classes/ElggGroup.php | 9 +++------ engine/classes/ElggMenuBuilder.php | 12 ++++++------ engine/classes/ElggObject.php | 9 +++------ engine/classes/ElggSite.php | 12 ++++-------- engine/classes/ElggTranslit.php | 26 +++++++++++++------------- engine/classes/ElggUser.php | 12 ++++-------- engine/lib/configuration.php | 4 ++-- engine/lib/elgglib.php | 6 +++--- engine/lib/languages.php | 3 +++ engine/lib/location.php | 2 +- engine/lib/metadata.php | 4 ++-- engine/lib/plugins.php | 2 +- engine/lib/relationships.php | 2 +- engine/lib/views.php | 20 +++++++++++--------- 15 files changed, 62 insertions(+), 72 deletions(-) (limited to 'engine') diff --git a/engine/classes/ElggEntity.php b/engine/classes/ElggEntity.php index f44e73023..5a63c7b15 100644 --- a/engine/classes/ElggEntity.php +++ b/engine/classes/ElggEntity.php @@ -375,12 +375,11 @@ abstract class ElggEntity extends ElggData implements } return $result; - } - - // unsaved entity. store in temp array - // returning single entries instead of an array of 1 element is decided in - // getMetaData(), just like pulling from the db. - else { + } else { + // unsaved entity. store in temp array + // returning single entries instead of an array of 1 element is decided in + // getMetaData(), just like pulling from the db. + // // if overwrite, delete first if (!$multiple || !isset($this->temp_metadata[$name])) { $this->temp_metadata[$name] = array(); diff --git a/engine/classes/ElggGroup.php b/engine/classes/ElggGroup.php index 61f699f1a..7ab0bfa48 100644 --- a/engine/classes/ElggGroup.php +++ b/engine/classes/ElggGroup.php @@ -48,21 +48,18 @@ class ElggGroup extends ElggEntity $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid)); throw new IOException($msg); } - - // Is $guid is an ElggGroup? Use a copy constructor } else if ($guid instanceof ElggGroup) { + // $guid is an ElggGroup so this is a copy constructor elgg_deprecated_notice('This type of usage of the ElggGroup constructor was deprecated. Please use the clone method.', 1.7); foreach ($guid->attributes as $key => $value) { $this->attributes[$key] = $value; } - - // Is this is an ElggEntity but not an ElggGroup = ERROR! } else if ($guid instanceof ElggEntity) { + // @todo why separate from else throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggGroup')); - - // Is it a GUID } else if (is_numeric($guid)) { + // $guid is a GUID so load entity if (!$this->load($guid)) { throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid))); } diff --git a/engine/classes/ElggMenuBuilder.php b/engine/classes/ElggMenuBuilder.php index 639e34755..198018f3c 100644 --- a/engine/classes/ElggMenuBuilder.php +++ b/engine/classes/ElggMenuBuilder.php @@ -235,8 +235,8 @@ class ElggMenuBuilder { /** * Compare two menu items by their display text * - * @param ElggMenuItem $a - * @param ElggMenuItem $b + * @param ElggMenuItem $a Menu item + * @param ElggMenuItem $b Menu item * @return bool */ public static function compareByText($a, $b) { @@ -253,8 +253,8 @@ class ElggMenuBuilder { /** * Compare two menu items by their identifiers * - * @param ElggMenuItem $a - * @param ElggMenuItem $b + * @param ElggMenuItem $a Menu item + * @param ElggMenuItem $b Menu item * @return bool */ public static function compareByName($a, $b) { @@ -271,8 +271,8 @@ class ElggMenuBuilder { /** * Compare two menu items by their priority * - * @param ElggMenuItem $a - * @param ElggMenuItem $b + * @param ElggMenuItem $a Menu item + * @param ElggMenuItem $b Menu item * @return bool * * @todo change name to compareByPriority diff --git a/engine/classes/ElggObject.php b/engine/classes/ElggObject.php index 6263f84f6..3cb76ffaf 100644 --- a/engine/classes/ElggObject.php +++ b/engine/classes/ElggObject.php @@ -66,21 +66,18 @@ class ElggObject extends ElggEntity { $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid)); throw new IOException($msg); } - - // Is $guid is an ElggObject? Use a copy constructor } else if ($guid instanceof ElggObject) { + // $guid is an ElggObject so this is a copy constructor elgg_deprecated_notice('This type of usage of the ElggObject constructor was deprecated. Please use the clone method.', 1.7); foreach ($guid->attributes as $key => $value) { $this->attributes[$key] = $value; } - - // Is this is an ElggEntity but not an ElggObject = ERROR! } else if ($guid instanceof ElggEntity) { + // @todo remove - do not need separate exception throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggObject')); - - // Is it a GUID } else if (is_numeric($guid)) { + // $guid is a GUID so load if (!$this->load($guid)) { throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid))); } diff --git a/engine/classes/ElggSite.php b/engine/classes/ElggSite.php index 1a34df195..deba5087e 100644 --- a/engine/classes/ElggSite.php +++ b/engine/classes/ElggSite.php @@ -77,28 +77,24 @@ class ElggSite extends ElggEntity { $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid)); throw new IOException($msg); } - - // Is $guid is an ElggSite? Use a copy constructor } else if ($guid instanceof ElggSite) { + // $guid is an ElggSite so this is a copy constructor elgg_deprecated_notice('This type of usage of the ElggSite constructor was deprecated. Please use the clone method.', 1.7); foreach ($guid->attributes as $key => $value) { $this->attributes[$key] = $value; } - - // Is this is an ElggEntity but not an ElggSite = ERROR! } else if ($guid instanceof ElggEntity) { + // @todo remove and just use else clause throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggSite')); - - // See if this is a URL } else if (strpos($guid, "http") !== false) { + // url so retrieve by url $guid = get_site_by_url($guid); foreach ($guid->attributes as $key => $value) { $this->attributes[$key] = $value; } - - // Is it a GUID } else if (is_numeric($guid)) { + // $guid is a GUID so load if (!$this->load($guid)) { throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid))); } diff --git a/engine/classes/ElggTranslit.php b/engine/classes/ElggTranslit.php index 79116fc01..601965c11 100644 --- a/engine/classes/ElggTranslit.php +++ b/engine/classes/ElggTranslit.php @@ -58,15 +58,15 @@ class ElggTranslit { // remove all ASCII except 0-9a-zA-Z, hyphen, underscore, and whitespace // note: "x" modifier did not work with this pattern. $string = preg_replace('~[' - . '\x00-\x08' # control chars - . '\x0b\x0c' # vert tab, form feed - . '\x0e-\x1f' # control chars - . '\x21-\x2c' # ! ... , - . '\x2e\x2f' # . slash - . '\x3a-\x40' # : ... @ - . '\x5b-\x5e' # [ ... ^ - . '\x60' # ` - . '\x7b-\x7f' # { ... DEL + . '\x00-\x08' // control chars + . '\x0b\x0c' // vert tab, form feed + . '\x0e-\x1f' // control chars + . '\x21-\x2c' // ! ... , + . '\x2e\x2f' // . slash + . '\x3a-\x40' // : ... @ + . '\x5b-\x5e' // [ ... ^ + . '\x60' // ` + . '\x7b-\x7f' // { ... DEL . ']~', '', $string); $string = strtr($string, '', ''); @@ -80,10 +80,10 @@ class ElggTranslit { // note: we cannot use [^0-9a-zA-Z] because that matches multibyte chars. // note: "x" modifier did not work with this pattern. $pattern = '~[' - . '\x00-\x2f' # controls ... slash - . '\x3a-\x40' # : ... @ - . '\x5b-\x60' # [ ... ` - . '\x7b-\x7f' # { ... DEL + . '\x00-\x2f' // controls ... slash + . '\x3a-\x40' // : ... @ + . '\x5b-\x60' // [ ... ` + . '\x7b-\x7f' // { ... DEL . ']+~x'; // ['internationalization', 'and', '日本語'] diff --git a/engine/classes/ElggUser.php b/engine/classes/ElggUser.php index 6c1cdc1de..b80065b27 100644 --- a/engine/classes/ElggUser.php +++ b/engine/classes/ElggUser.php @@ -65,30 +65,26 @@ class ElggUser extends ElggEntity $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid)); throw new IOException($msg); } - - // See if this is a username } else if (is_string($guid)) { + // $guid is a username $user = get_user_by_username($guid); if ($user) { foreach ($user->attributes as $key => $value) { $this->attributes[$key] = $value; } } - - // Is $guid is an ElggUser? Use a copy constructor } else if ($guid instanceof ElggUser) { + // $guid is an ElggUser so this is a copy constructor elgg_deprecated_notice('This type of usage of the ElggUser constructor was deprecated. Please use the clone method.', 1.7); foreach ($guid->attributes as $key => $value) { $this->attributes[$key] = $value; } - - // Is this is an ElggEntity but not an ElggUser = ERROR! } else if ($guid instanceof ElggEntity) { + // @todo why have a special case here throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggUser')); - - // Is it a GUID } else if (is_numeric($guid)) { + // $guid is a GUID so load entity if (!$this->load($guid)) { throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid))); } diff --git a/engine/lib/configuration.php b/engine/lib/configuration.php index a0f297f0c..55e5bbd36 100644 --- a/engine/lib/configuration.php +++ b/engine/lib/configuration.php @@ -486,9 +486,9 @@ function get_config($name, $site_guid = 0) { // @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"; + // $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 diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index 74b70f9fb..281b23535 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -1383,8 +1383,8 @@ function elgg_http_build_url(array $parts, $html_encode = TRUE) { * add tokens to the action. The form view automatically handles * tokens. * - * @param string $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 string URL with action tokens * @since 1.7.0 @@ -1446,7 +1446,7 @@ function elgg_http_remove_url_query_element($url, $element) { * Adds an element or elements to a URL's query string. * * @param string $url The URL - * @param array $elements Key/value pairs to add to the URL + * @param array $elements Key/value pairs to add to the URL * * @return string The new URL with the query strings added * @since 1.7.0 diff --git a/engine/lib/languages.php b/engine/lib/languages.php index 17db14d98..61ba91ddb 100644 --- a/engine/lib/languages.php +++ b/engine/lib/languages.php @@ -139,6 +139,9 @@ function get_language() { return false; } +/** + * @access private + */ function _elgg_load_translations() { global $CONFIG; diff --git a/engine/lib/location.php b/engine/lib/location.php index b319bb3bb..1534c7d7b 100644 --- a/engine/lib/location.php +++ b/engine/lib/location.php @@ -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/metadata.php b/engine/lib/metadata.php index 305e9918b..a1ebfa5f1 100644 --- a/engine/lib/metadata.php +++ b/engine/lib/metadata.php @@ -920,8 +920,8 @@ function elgg_get_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 + * @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 diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php index f281b1416..6fc000cf9 100644 --- a/engine/lib/plugins.php +++ b/engine/lib/plugins.php @@ -865,7 +865,7 @@ function elgg_set_plugin_user_setting($name, $value, $user_guid = null, $plugin_ * Unsets a user-specific plugin setting * * @param string $name Name of the setting - * @param int $user_guid Defaults to logged in user + * @param int $user_guid Defaults to logged in user * @param string $plugin_id Defaults to contextual plugin name * * @return bool diff --git a/engine/lib/relationships.php b/engine/lib/relationships.php index fe0b8364d..b0cd627fc 100644 --- a/engine/lib/relationships.php +++ b/engine/lib/relationships.php @@ -363,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() diff --git a/engine/lib/views.php b/engine/lib/views.php index 7d8347863..c4b349fc6 100644 --- a/engine/lib/views.php +++ b/engine/lib/views.php @@ -1107,7 +1107,7 @@ function elgg_view_entity_annotations(ElggEntity $entity, $full_view = true) { * This is a shortcut for {@elgg_view page/elements/title}. * * @param string $title The page title - * @param array $vars View variables (was submenu be displayed? (deprecated)) + * @param array $vars View variables (was submenu be displayed? (deprecated)) * * @return string The HTML (etc) */ @@ -1179,7 +1179,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 array $vars Additional parameters for the view + * @param array $vars Additional parameters for the view * * @return string * @since 1.8.0 @@ -1236,15 +1236,17 @@ function elgg_view_river_item($item, array $vars = array()) { // subject is disabled or subject/object deleted return ''; } + + // @todo this needs to be cleaned up // Don't hide objects in closed groups that a user can see. // see http://trac.elgg.org/ticket/4789 -// else { -// // hide based on object's container -// $visibility = ElggGroupItemVisibility::factory($object->container_guid); -// if ($visibility->shouldHideItems) { -// return ''; -// } -// } + // else { + // // hide based on object's container + // $visibility = ElggGroupItemVisibility::factory($object->container_guid); + // if ($visibility->shouldHideItems) { + // return ''; + // } + // } $vars['item'] = $item; -- cgit v1.2.3 From ea4ce20b3632a3c55ffedfad1ad53845db5a7e12 Mon Sep 17 00:00:00 2001 From: cash Date: Sat, 16 Mar 2013 12:03:21 -0400 Subject: coding standards --- engine/classes/ElggAccess.php | 4 ++++ engine/classes/ElggCache.php | 4 ++++ engine/classes/ElggData.php | 2 ++ engine/classes/ElggFileCache.php | 4 ++++ engine/classes/ElggXMLElement.php | 8 ++++++++ 5 files changed, 22 insertions(+) (limited to 'engine') diff --git a/engine/classes/ElggAccess.php b/engine/classes/ElggAccess.php index 6f8d9bb4b..0aed477fc 100644 --- a/engine/classes/ElggAccess.php +++ b/engine/classes/ElggAccess.php @@ -16,6 +16,7 @@ class ElggAccess { */ private $ignore_access; + // @codingStandardsIgnoreStart /** * Get current ignore access setting. * @@ -26,6 +27,7 @@ class ElggAccess { elgg_deprecated_notice('ElggAccess::get_ignore_access() is deprecated by ElggAccess::getIgnoreAccess()', 1.8); return $this->getIgnoreAccess(); } + // @codingStandardsIgnoreEnd /** * Get current ignore access setting. @@ -36,6 +38,7 @@ class ElggAccess { return $this->ignore_access; } + // @codingStandardsIgnoreStart /** * Set ignore access. * @@ -49,6 +52,7 @@ class ElggAccess { elgg_deprecated_notice('ElggAccess::set_ignore_access() is deprecated by ElggAccess::setIgnoreAccess()', 1.8); return $this->setIgnoreAccess($ignore); } + // @codingStandardsIgnoreEnd /** * Set ignore access. diff --git a/engine/classes/ElggCache.php b/engine/classes/ElggCache.php index 4317f4be9..909eab39b 100644 --- a/engine/classes/ElggCache.php +++ b/engine/classes/ElggCache.php @@ -21,6 +21,7 @@ abstract class ElggCache implements ArrayAccess { $this->variables = array(); } + // @codingStandardsIgnoreStart /** * Set a cache variable. * @@ -35,6 +36,7 @@ abstract class ElggCache implements ArrayAccess { elgg_deprecated_notice('ElggCache::set_variable() is deprecated by ElggCache::setVariable()', 1.8); $this->setVariable($variable, $value); } + // @codingStandardsIgnoreEnd /** * Set a cache variable. @@ -52,6 +54,7 @@ abstract class ElggCache implements ArrayAccess { $this->variables[$variable] = $value; } + // @codingStandardsIgnoreStart /** * Get variables for this cache. * @@ -65,6 +68,7 @@ abstract class ElggCache implements ArrayAccess { elgg_deprecated_notice('ElggCache::get_variable() is deprecated by ElggCache::getVariable()', 1.8); return $this->getVariable($variable); } + // @codingStandardsIgnoreEnd /** * Get variables for this cache. diff --git a/engine/classes/ElggData.php b/engine/classes/ElggData.php index 426248ca3..4f843cde4 100644 --- a/engine/classes/ElggData.php +++ b/engine/classes/ElggData.php @@ -26,6 +26,7 @@ abstract class ElggData implements */ protected $attributes = array(); + // @codingStandardsIgnoreStart /** * Initialise the attributes array. * @@ -44,6 +45,7 @@ abstract class ElggData implements elgg_deprecated_notice('initialise_attributes() is deprecated by initializeAttributes()', 1.8); } } + // @codingStandardsIgnoreEnd /** * Initialize the attributes array. diff --git a/engine/classes/ElggFileCache.php b/engine/classes/ElggFileCache.php index e654f1db2..94143f777 100644 --- a/engine/classes/ElggFileCache.php +++ b/engine/classes/ElggFileCache.php @@ -26,6 +26,7 @@ class ElggFileCache extends ElggCache { } } + // @codingStandardsIgnoreStart /** * Create and return a handle to a file. * @@ -41,6 +42,7 @@ class ElggFileCache extends ElggCache { return $this->createFile($filename, $rw); } + // @codingStandardsIgnoreEnd /** * Create and return a handle to a file. @@ -72,6 +74,7 @@ class ElggFileCache extends ElggCache { return fopen($path . $filename, $rw); } + // @codingStandardsIgnoreStart /** * Create a sanitised filename for the file. * @@ -86,6 +89,7 @@ class ElggFileCache extends ElggCache { return $filename; } + // @codingStandardsIgnoreEnd /** * Create a sanitised filename for the file. diff --git a/engine/classes/ElggXMLElement.php b/engine/classes/ElggXMLElement.php index 4e4b7e63c..d7e912035 100644 --- a/engine/classes/ElggXMLElement.php +++ b/engine/classes/ElggXMLElement.php @@ -76,6 +76,10 @@ class ElggXMLElement { return $result; } + /** + * @param string $name Property name + * @return mixed + */ function __get($name) { switch ($name) { case 'name': @@ -94,6 +98,10 @@ class ElggXMLElement { return null; } + /** + * @param string $name Property name + * @return boolean + */ function __isset($name) { switch ($name) { case 'name': -- cgit v1.2.3 From 00819122111a081c17f1ae4c53974b0deb50757c Mon Sep 17 00:00:00 2001 From: cash Date: Sat, 16 Mar 2013 12:41:16 -0400 Subject: more coding standard fixes --- engine/classes/ElggAttributeLoader.php | 30 ++++++++- engine/classes/ElggAutoP.php | 24 +++++--- engine/classes/ElggDiskFilestore.php | 9 +++ engine/classes/ElggVolatileMetadataCache.php | 92 +++++++++++++++------------- engine/classes/ElggXMLElement.php | 4 ++ engine/lib/opendd.php | 4 ++ 6 files changed, 110 insertions(+), 53 deletions(-) (limited to 'engine') diff --git a/engine/classes/ElggAttributeLoader.php b/engine/classes/ElggAttributeLoader.php index 2d1c1abde..d1e15008e 100644 --- a/engine/classes/ElggAttributeLoader.php +++ b/engine/classes/ElggAttributeLoader.php @@ -4,6 +4,9 @@ * Loads ElggEntity attributes from DB or validates those passed in via constructor * * @access private + * + * @package Elgg.Core + * @subpackage DataModel */ class ElggAttributeLoader { @@ -65,9 +68,11 @@ class ElggAttributeLoader { public $full_loader = ''; /** - * @param string $class class of object being loaded - * @param string $required_type entity type this is being used to populate - * @param array $initialized_attrs attributes after initializeAttributes() has been run + * Constructor + * + * @param string $class class of object being loaded + * @param string $required_type entity type this is being used to populate + * @param array $initialized_attrs attributes after initializeAttributes() has been run * @throws InvalidArgumentException */ public function __construct($class, $required_type, array $initialized_attrs) { @@ -87,14 +92,33 @@ class ElggAttributeLoader { $this->secondary_attr_names = array_diff($all_attr_names, self::$primary_attr_names); } + /** + * Get primary attributes missing that are missing + * + * @param stdClass $row Database row + * @return array + */ protected function isMissingPrimaries($row) { return array_diff(self::$primary_attr_names, array_keys($row)) !== array(); } + /** + * Get secondary attributes that are missing + * + * @param stdClass $row Database row + * @return array + */ protected function isMissingSecondaries($row) { return array_diff($this->secondary_attr_names, array_keys($row)) !== array(); } + /** + * Check that the type is correct + * + * @param stdClass $row Database row + * @return void + * @throws InvalidClassException + */ protected function checkType($row) { if ($row['type'] !== $this->required_type) { $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($row['guid'], $this->class)); diff --git a/engine/classes/ElggAutoP.php b/engine/classes/ElggAutoP.php index f3c7cc972..71536c433 100644 --- a/engine/classes/ElggAutoP.php +++ b/engine/classes/ElggAutoP.php @@ -7,6 +7,9 @@ * * In DIV elements, Ps are only added when there would be at * least two of them. + * + * @package Elgg.Core + * @subpackage Output */ class ElggAutoP { @@ -51,8 +54,12 @@ class ElggAutoP { protected $_alterList = 'article aside blockquote body details div footer header section'; + /** @var string */ protected $_unique = ''; + /** + * Constructor + */ public function __construct() { $this->_blocks = preg_split('@\\s+@', $this->_blocks); $this->_descendList = preg_split('@\\s+@', $this->_descendList); @@ -98,7 +105,7 @@ class ElggAutoP { $html = str_replace('&', $this->_unique . 'AMP', $html); $this->_doc = new DOMDocument(); - + // parse to DOM, suppressing loadHTML warnings // http://www.php.net/manual/en/domdocument.loadhtml.php#95463 libxml_use_internal_errors(true); @@ -112,7 +119,7 @@ class ElggAutoP { $this->_xpath = new DOMXPath($this->_doc); // start processing recursively at the BODY element $nodeList = $this->_xpath->query('//body[1]'); - $this->_addParagraphs($nodeList->item(0)); + $this->addParagraphs($nodeList->item(0)); // serialize back to HTML $html = $this->_doc->saveHTML(); @@ -187,15 +194,16 @@ class ElggAutoP { /** * Add P and BR elements as necessary * - * @param DOMElement $el + * @param DOMElement $el DOM element + * @return void */ - protected function _addParagraphs(DOMElement $el) { + protected function addParagraphs(DOMElement $el) { // no need to call recursively, just queue up $elsToProcess = array($el); $inlinesToProcess = array(); while ($el = array_shift($elsToProcess)) { // if true, we can alter all child nodes, if not, we'll just call - // _addParagraphs on each element in the descendInto list + // addParagraphs on each element in the descendInto list $alterInline = in_array($el->nodeName, $this->_alterList); // inside affected elements, we want to trim leading whitespace from @@ -229,8 +237,8 @@ class ElggAutoP { if ($alterInline) { $isText = ($node->nodeType === XML_TEXT_NODE); $isLastInline = (! $node->nextSibling - || ($node->nextSibling->nodeType === XML_ELEMENT_NODE - && in_array($node->nextSibling->nodeName, $this->_blocks))); + || ($node->nextSibling->nodeType === XML_ELEMENT_NODE + && in_array($node->nextSibling->nodeName, $this->_blocks))); if ($isElement) { $isFollowingBr = ($node->nodeName === 'br'); } @@ -263,7 +271,7 @@ class ElggAutoP { if ($isBlock) { if (in_array($node->nodeName, $this->_descendList)) { $elsToProcess[] = $node; - //$this->_addParagraphs($node); + //$this->addParagraphs($node); } } $openP = true; diff --git a/engine/classes/ElggDiskFilestore.php b/engine/classes/ElggDiskFilestore.php index 7374aad35..29547d83b 100644 --- a/engine/classes/ElggDiskFilestore.php +++ b/engine/classes/ElggDiskFilestore.php @@ -254,6 +254,7 @@ class ElggDiskFilestore extends ElggFilestore { } } + // @codingStandardsIgnoreStart /** * Create a directory $dirroot * @@ -268,6 +269,7 @@ class ElggDiskFilestore extends ElggFilestore { return $this->makeDirectoryRoot($dirroot); } + // @codingStandardsIgnoreEnd /** * Create a directory $dirroot @@ -287,6 +289,7 @@ class ElggDiskFilestore extends ElggFilestore { return true; } + // @codingStandardsIgnoreStart /** * Multibyte string tokeniser. * @@ -318,7 +321,9 @@ class ElggDiskFilestore extends ElggFilestore { return str_split($string); } } + // @codingStandardsIgnoreEnd + // @codingStandardsIgnoreStart /** * Construct a file path matrix for an entity. * @@ -332,6 +337,7 @@ class ElggDiskFilestore extends ElggFilestore { return $this->makefileMatrix($identifier); } + // @codingStandardsIgnoreEnd /** * Construct a file path matrix for an entity. @@ -351,7 +357,9 @@ class ElggDiskFilestore extends ElggFilestore { return "$time_created/$entity->guid/"; } + // @codingStandardsIgnoreEnd + // @codingStandardsIgnoreStart /** * Construct a filename matrix. * @@ -370,6 +378,7 @@ class ElggDiskFilestore extends ElggFilestore { return $this->makeFileMatrix($guid); } + // @codingStandardsIgnoreEnd /** * Returns a list of attributes to save to the database when saving diff --git a/engine/classes/ElggVolatileMetadataCache.php b/engine/classes/ElggVolatileMetadataCache.php index 8a33c198d..4acda7cee 100644 --- a/engine/classes/ElggVolatileMetadataCache.php +++ b/engine/classes/ElggVolatileMetadataCache.php @@ -33,9 +33,11 @@ class ElggVolatileMetadataCache { protected $ignoreAccess = null; /** - * @param int $entity_guid - * - * @param array $values + * Cache metadata for an entity + * + * @param int $entity_guid The GUID of the entity + * @param array $values The metadata values to cache + * @return void */ public function saveAll($entity_guid, array $values) { if (!$this->getIgnoreAccess()) { @@ -45,8 +47,9 @@ class ElggVolatileMetadataCache { } /** - * @param int $entity_guid - * + * Get the metadata for an entity + * + * @param int $entity_guid The GUID of the entity * @return array */ public function loadAll($entity_guid) { @@ -61,15 +64,17 @@ class ElggVolatileMetadataCache { * Declare that there may be fetch-able metadata names in storage that this * cache doesn't know about * - * @param int $entity_guid + * @param int $entity_guid The GUID of the entity + * @return void */ public function markOutOfSync($entity_guid) { unset($this->isSynchronized[$entity_guid]); } /** - * @param $entity_guid - * + * Have all the metadata for this entity been cached? + * + * @param int $entity_guid The GUID of the entity * @return bool */ public function isSynchronized($entity_guid) { @@ -77,13 +82,15 @@ class ElggVolatileMetadataCache { } /** - * @param int $entity_guid - * - * @param string $name - * - * @param array|int|string|null $value null means it is known that there is no - * fetch-able metadata under this name - * @param bool $allow_multiple + * Cache a piece of metadata + * + * @param int $entity_guid The GUID of the entity + * @param string $name The metadata name + * @param array|int|string|null $value The metadata value. null means it is + * known that there is no fetch-able + * metadata under this name + * @param bool $allow_multiple Can the metadata be an array + * @return void */ public function save($entity_guid, $name, $value, $allow_multiple = false) { if ($this->getIgnoreAccess()) { @@ -115,10 +122,8 @@ class ElggVolatileMetadataCache { * function's return value should be trusted (otherwise a null return value * is ambiguous). * - * @param int $entity_guid - * - * @param string $name - * + * @param int $entity_guid The GUID of the entity + * @param string $name The metadata name * @return array|string|int|null null = value does not exist */ public function load($entity_guid, $name) { @@ -133,9 +138,9 @@ class ElggVolatileMetadataCache { * Forget about this metadata entry. We don't want to try to guess what the * next fetch from storage will return * - * @param int $entity_guid - * - * @param string $name + * @param int $entity_guid The GUID of the entity + * @param string $name The metadata name + * @return void */ public function markUnknown($entity_guid, $name) { unset($this->values[$entity_guid][$name]); @@ -145,10 +150,8 @@ class ElggVolatileMetadataCache { /** * If true, load() will return an accurate value for this name * - * @param int $entity_guid - * - * @param string $name - * + * @param int $entity_guid The GUID of the entity + * @param string $name The metadata name * @return bool */ public function isKnown($entity_guid, $name) { @@ -163,10 +166,8 @@ class ElggVolatileMetadataCache { /** * Declare that metadata under this name is known to be not fetch-able from storage * - * @param int $entity_guid - * - * @param string $name - * + * @param int $entity_guid The GUID of the entity + * @param string $name The metadata name * @return array */ public function markEmpty($entity_guid, $name) { @@ -176,7 +177,8 @@ class ElggVolatileMetadataCache { /** * Forget about all metadata for an entity * - * @param int $entity_guid + * @param int $entity_guid The GUID of the entity + * @return void */ public function clear($entity_guid) { $this->values[$entity_guid] = array(); @@ -185,6 +187,8 @@ class ElggVolatileMetadataCache { /** * Clear entire cache and mark all entities as out of sync + * + * @return void */ public function flush() { $this->values = array(); @@ -197,7 +201,8 @@ class ElggVolatileMetadataCache { * * This setting makes this component a little more loosely-coupled. * - * @param bool $ignore + * @param bool $ignore Whether to ignore access or not + * @return void */ public function setIgnoreAccess($ignore) { $this->ignoreAccess = (bool) $ignore; @@ -205,12 +210,16 @@ class ElggVolatileMetadataCache { /** * Tell the cache to call elgg_get_ignore_access() to determing access status. + * + * @return void */ public function unsetIgnoreAccess() { $this->ignoreAccess = null; } /** + * Get the ignore access value + * * @return bool */ protected function getIgnoreAccess() { @@ -225,12 +234,10 @@ class ElggVolatileMetadataCache { * Invalidate based on options passed to the global *_metadata functions * * @param string $action Action performed on metadata. "delete", "disable", or "enable" - * - * @param array $options Options passed to elgg_(delete|disable|enable)_metadata - * - * "guid" if given, invalidation will be limited to this entity - * - * "metadata_name" if given, invalidation will be limited to metadata with this name + * @param array $options Options passed to elgg_(delete|disable|enable)_metadata + * "guid" if given, invalidation will be limited to this entity + * "metadata_name" if given, invalidation will be limited to metadata with this name + * @return void */ public function invalidateByOptions($action, array $options) { // remove as little as possible, optimizing for common cases @@ -254,7 +261,10 @@ class ElggVolatileMetadataCache { } /** - * @param int|array $guids + * Populate the cache from a set of entities + * + * @param int|array $guids Array of or single GUIDs + * @return void */ public function populateFromEntities($guids) { if (empty($guids)) { @@ -318,9 +328,7 @@ class ElggVolatileMetadataCache { * cache if RAM usage becomes an issue. * * @param array $guids GUIDs of entities to examine - * - * @param int $limit Limit in characters of all metadata (with ints casted to strings) - * + * @param int $limit Limit in characters of all metadata (with ints casted to strings) * @return array */ public function filterMetadataHeavyEntities(array $guids, $limit = 1024000) { diff --git a/engine/classes/ElggXMLElement.php b/engine/classes/ElggXMLElement.php index d7e912035..6f2633e25 100644 --- a/engine/classes/ElggXMLElement.php +++ b/engine/classes/ElggXMLElement.php @@ -77,6 +77,8 @@ class ElggXMLElement { } /** + * Override -> + * * @param string $name Property name * @return mixed */ @@ -99,6 +101,8 @@ class ElggXMLElement { } /** + * Override isset + * * @param string $name Property name * @return boolean */ diff --git a/engine/lib/opendd.php b/engine/lib/opendd.php index f00ea6aab..7d635a295 100644 --- a/engine/lib/opendd.php +++ b/engine/lib/opendd.php @@ -7,6 +7,8 @@ * @version 0.4 */ +// @codingStandardsIgnoreStart + /** * Attempt to construct an ODD object out of a XmlElement or sub-elements. * @@ -103,3 +105,5 @@ function ODD_Import($xml) { function ODD_Export(ODDDocument $document) { return "$document"; } + +// @codingStandardsIgnoreEnd -- cgit v1.2.3 From c79f4894d5e4bf88023e286dc03259cfa3f98414 Mon Sep 17 00:00:00 2001 From: cash Date: Sat, 16 Mar 2013 12:43:12 -0400 Subject: fixed extra ignore --- engine/classes/ElggDiskFilestore.php | 1 - 1 file changed, 1 deletion(-) (limited to 'engine') diff --git a/engine/classes/ElggDiskFilestore.php b/engine/classes/ElggDiskFilestore.php index 29547d83b..ded653436 100644 --- a/engine/classes/ElggDiskFilestore.php +++ b/engine/classes/ElggDiskFilestore.php @@ -357,7 +357,6 @@ class ElggDiskFilestore extends ElggFilestore { return "$time_created/$entity->guid/"; } - // @codingStandardsIgnoreEnd // @codingStandardsIgnoreStart /** -- cgit v1.2.3 From 36755bea9aefd7e8bf54deab7b29902f8733f9aa Mon Sep 17 00:00:00 2001 From: cash Date: Sat, 16 Mar 2013 13:32:02 -0400 Subject: engine now is standards compliant --- engine/classes/ElggPlugin.php | 4 ++-- engine/lib/plugins.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'engine') diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php index ae447bddb..c1c46f272 100644 --- a/engine/classes/ElggPlugin.php +++ b/engine/classes/ElggPlugin.php @@ -649,8 +649,8 @@ class ElggPlugin extends ElggObject { // Note: this will not run re-run the init hooks! if ($return) { if ($this->canReadFile('activate.php')) { - $flags = ELGG_PLUGIN_INCLUDE_START | ELGG_PLUGIN_REGISTER_CLASSES - | ELGG_PLUGIN_REGISTER_LANGUAGES | ELGG_PLUGIN_REGISTER_VIEWS; + $flags = ELGG_PLUGIN_INCLUDE_START | ELGG_PLUGIN_REGISTER_CLASSES | + ELGG_PLUGIN_REGISTER_LANGUAGES | ELGG_PLUGIN_REGISTER_VIEWS; $this->start($flags); diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php index 6fc000cf9..74bce45fd 100644 --- a/engine/lib/plugins.php +++ b/engine/lib/plugins.php @@ -312,10 +312,10 @@ function elgg_is_active_plugin($plugin_id, $site_guid = null) { */ function elgg_load_plugins() { $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; -- cgit v1.2.3 From cb8a932702a66a8d8ec69982441e71bde8fd1b5c Mon Sep 17 00:00:00 2001 From: cash Date: Sat, 30 Mar 2013 12:04:19 -0400 Subject: Fixes #4867 handling boolean false values as metadata pair value --- engine/lib/metadata.php | 2 ++ engine/tests/api/metadata.php | 14 ++++++++++++++ 2 files changed, 16 insertions(+) (limited to 'engine') diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php index a1ebfa5f1..ad926a49a 100644 --- a/engine/lib/metadata.php +++ b/engine/lib/metadata.php @@ -619,6 +619,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(); diff --git a/engine/tests/api/metadata.php b/engine/tests/api/metadata.php index 825290d80..0862341c1 100644 --- a/engine/tests/api/metadata.php +++ b/engine/tests/api/metadata.php @@ -123,6 +123,20 @@ class ElggCoreMetadataAPITest extends ElggCoreUnitTest { $e->delete(); } + /** + * https://github.com/Elgg/Elgg/issues/4867 + */ + public function testElggGetEntityMetadataWhereSqlWithFalseValue() { + $pair = array('name' => 'test' , 'value' => false); + $result = elgg_get_entity_metadata_where_sql('e', 'metadata', null, null, $pair); + $where = preg_replace( '/\s+/', ' ', $result['wheres'][0]); + $this->assertTrue(strpos($where, "msn1.string = 'test' AND BINARY msv1.string = 0") > 0); + + $result = elgg_get_entity_metadata_where_sql('e', 'metadata', array('test'), array(false)); + $where = preg_replace( '/\s+/', ' ', $result['wheres'][0]); + $this->assertTrue(strpos($where, "msn.string IN ('test')) AND ( BINARY msv.string IN ('0')")); + } + // Make sure metadata with multiple values is correctly deleted when re-written // by another user // http://trac.elgg.org/ticket/2776 -- cgit v1.2.3 From bc2bc90bd5282d08ed87dc374f4135d8182c931b Mon Sep 17 00:00:00 2001 From: cash Date: Sat, 30 Mar 2013 12:15:23 -0400 Subject: Refs #4356 do not display elgg_dump() messages on js or css requests --- engine/lib/elgglib.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'engine') diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index f4b1a0a3e..a49b620ac 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -1185,6 +1185,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 '
';
 		print_r($value);
-- 
cgit v1.2.3


From 62ebd8ff12086b6f7aaaba846264e43169ab5c8c Mon Sep 17 00:00:00 2001
From: cash 
Date: Sat, 30 Mar 2013 12:50:30 -0400
Subject: Fixes #4378 prevent loading same library name twice

---
 engine/lib/elgglib.php | 9 +++++++++
 1 file changed, 9 insertions(+)

(limited to 'engine')

diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php
index a49b620ac..fb652a141 100644
--- a/engine/lib/elgglib.php
+++ b/engine/lib/elgglib.php
@@ -93,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();
 	}
@@ -113,6 +120,8 @@ function elgg_load_library($name) {
 		);
 		throw new InvalidParameterException($error);
 	}
+
+	$loaded_libraries[] = $name;
 }
 
 /**
-- 
cgit v1.2.3


From bb0a69ba571744697fd89ffbc97577a734b38d2f Mon Sep 17 00:00:00 2001
From: Paweł Sroka 
Date: Sat, 30 Mar 2013 19:16:41 +0100
Subject: Fixes #5302 - Automatically registers view to simplecache on
 elgg_get_simplecache_url call

---
 engine/lib/cache.php | 1 +
 1 file changed, 1 insertion(+)

(limited to 'engine')

diff --git a/engine/lib/cache.php b/engine/lib/cache.php
index 59359124e..3116c1a9b 100644
--- a/engine/lib/cache.php
+++ b/engine/lib/cache.php
@@ -208,6 +208,7 @@ 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()) {
 		$url = elgg_get_site_url() . "cache/$type/$viewtype/$view.$lastcache.$type";
 	} else {
-- 
cgit v1.2.3


From a4874cba03660c3c2169c71c1d32e5474304d984 Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Sun, 31 Mar 2013 20:22:53 -0400
Subject: Fixes #5297: Improve error message in cases of suspected cross-domain
 login

---
 engine/lib/actions.php | 73 ++++++++++++++++++++++++++++++++++----------------
 htaccess_dist          |  8 ++++++
 languages/en.php       |  1 +
 3 files changed, 59 insertions(+), 23 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/actions.php b/engine/lib/actions.php
index f78ca63df..56936f582 100644
--- a/engine/lib/actions.php
+++ b/engine/lib/actions.php
@@ -74,8 +74,7 @@ function action($action, $forwarder = "") {
 	);
 
 	if (!in_array($action, $exceptions)) {
-		// All actions require a token.
-		action_gatekeeper();
+		action_gatekeeper($action);
 	}
 
 	$forwarder = str_replace(elgg_get_site_url(), "", $forwarder);
@@ -187,6 +186,26 @@ function elgg_unregister_action($action) {
 	}
 }
 
+/**
+ * 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.
  *
@@ -205,8 +224,6 @@ function elgg_unregister_action($action) {
  * @access private
  */
 function validate_action_token($visibleerrors = TRUE, $token = NULL, $ts = NULL) {
-	global $CONFIG;
-
 	if (!$token) {
 		$token = get_input('__elgg_token');
 	}
@@ -215,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(
@@ -293,12 +299,33 @@ function validate_action_token($visibleerrors = TRUE, $token = NULL, $ts = NULL)
  * 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() {
-	if (validate_action_token()) {
-		return TRUE;
+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');
diff --git a/htaccess_dist b/htaccess_dist
index 898fa22fb..44d129475 100644
--- a/htaccess_dist
+++ b/htaccess_dist
@@ -112,6 +112,14 @@ RewriteEngine on
 #
 #RewriteBase /
 
+
+# If your users receive the message "Sorry, logging in from a different domain is not permitted"
+# you must make sure your login form is served from the same hostname as your site pages.
+# See http://docs.elgg.org/wiki/Login_token_mismatch_error for more info.
+#
+# If you must add RewriteRules to change hostname, add them directly below (above all the others)
+
+
 # In for backwards compatibility
 RewriteRule ^pg\/([A-Za-z0-9\_\-]+)$ engine/handlers/page_handler.php?handler=$1&%{QUERY_STRING} [L]
 RewriteRule ^pg\/([A-Za-z0-9\_\-]+)\/(.*)$ engine/handlers/page_handler.php?handler=$1&page=$2&%{QUERY_STRING} [L]
diff --git a/languages/en.php b/languages/en.php
index 501855f02..a3c6cf2bf 100644
--- a/languages/en.php
+++ b/languages/en.php
@@ -1193,6 +1193,7 @@ You cannot reply to this email.",
 	'actiongatekeeper:timeerror' => 'The page you were using has expired. Please refresh and try again.',
 	'actiongatekeeper:pluginprevents' => 'A extension has prevented this form from being submitted.',
 	'actiongatekeeper:uploadexceeded' => 'The size of file(s) uploaded exceeded the limit set by your site administrator',
+	'actiongatekeeper:crosssitelogin' => "Sorry, logging in from a different domain is not permitted.",
 
 
 /**
-- 
cgit v1.2.3


From 5ccc0540fd28cc1620ffca10e3aed92319e78794 Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Sun, 31 Mar 2013 21:09:07 -0400
Subject: Fixes #4972: More robust friendly titles implementation

---
 engine/classes/ElggTranslit.php       | 15 ++++++++++++---
 engine/lib/output.php                 |  8 +++-----
 engine/tests/regression/trac_bugs.php | 16 +++++++++-------
 3 files changed, 24 insertions(+), 15 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggTranslit.php b/engine/classes/ElggTranslit.php
index 601965c11..4ae1d2479 100644
--- a/engine/classes/ElggTranslit.php
+++ b/engine/classes/ElggTranslit.php
@@ -49,10 +49,19 @@ class ElggTranslit {
 		// Internationalization, AND 日本語!
 		$string = self::transliterateAscii($string);
 
-		// more translation
+		// allow HTML tags in titles
+		$string = preg_replace('~<([a-zA-Z][^>]*)>~', ' $1 ', $string);
+
+		// more substitutions
+		// @todo put these somewhere else
 		$string = strtr($string, array(
-			// Euro/GBP
-			"\xE2\x82\xAC" /* € */ => 'E', "\xC2\xA3" /* £ */ => 'GBP',
+			// currency
+			"\xE2\x82\xAC" /* € */ => ' E ',
+			"\xC2\xA3" /* £ */ => ' GBP ',
+			
+			"&" => ' and ',
+			">" => ' greater than ',
+			"<" => ' less than ',
 		));
 
 		// remove all ASCII except 0-9a-zA-Z, hyphen, underscore, and whitespace
diff --git a/engine/lib/output.php b/engine/lib/output.php
index da8e1ab86..c5a04989b 100644
--- a/engine/lib/output.php
+++ b/engine/lib/output.php
@@ -284,11 +284,9 @@ function elgg_get_friendly_title($title) {
 		return $result;
 	}
 
-	// handle some special cases
-	$title = str_replace('&', 'and', $title);
-	// quotes and angle brackets stored in the database as html encoded
-	$title = htmlspecialchars_decode($title);
-
+	// titles are often stored HTML encoded
+	$title = html_entity_decode($title, ENT_QUOTES, 'UTF-8');
+	
 	$title = ElggTranslit::urlize($title);
 
 	return $title;
diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php
index 691433a41..58444dd39 100644
--- a/engine/tests/regression/trac_bugs.php
+++ b/engine/tests/regression/trac_bugs.php
@@ -206,21 +206,23 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest {
 	 */
 	public function test_friendly_title() {
 		$cases = array(
+			// acid test
+			"B&N > Amazon, OK?  'hey!' $34"
+			=> "b-and-n-greater-than-amazon-ok-bold-hey-34",
+
 			// hyphen, underscore and ASCII whitespace replaced by separator,
 			// other non-alphanumeric ASCII removed
-			"a-a_a a\na\ra\ta\va!a\"a#a\$a%a&a'a(a)a*a+a,a.a/a:a;aa?a@a[a\\a]a^a`a{a|a}a~a"
-			=> "a-a-a-a-a-a-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
-
+			"a-a_a a\na\ra\ta\va!a\"a#a\$a%a&a'a(a)a*a+a,a.a/a:a;a=a?a@a[a\\a]a^a`a{a|a}a~a"
+			=> "a-a-a-a-a-a-aaaaaaa-and-aaaaaaaaaaaaaaaaaaaaaaa",
+			
 			// separators trimmed
-			"-_ hello _-" => "hello",
+			"-_ hello _-" 
+			=> "hello",
 
 			// accents removed, lower case, other multibyte chars are URL encoded
 			"I\xC3\xB1t\xC3\xABrn\xC3\xA2ti\xC3\xB4n\xC3\xA0liz\xC3\xA6ti\xC3\xB8n, AND \xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E"
 				// Iñtërnâtiônàlizætiøn, AND 日本語
 			=> 'internationalizaetion-and-%E6%97%A5%E6%9C%AC%E8%AA%9E',
-
-			// some HTML entity replacements
-			"Me & You" => 'me-and-you',
 		);
 
 		// where available, string is converted to NFC before transliteration
-- 
cgit v1.2.3


From c1af06ed4faa8e1b0a84d6d7efbfcd0ed4c6598f Mon Sep 17 00:00:00 2001
From: cash 
Date: Sat, 13 Apr 2013 13:08:56 -0400
Subject: documentation updates

---
 engine/classes/ElggStaticVariableCache.php | 6 +++---
 engine/lib/database.php                    | 4 ++++
 2 files changed, 7 insertions(+), 3 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggStaticVariableCache.php b/engine/classes/ElggStaticVariableCache.php
index 17d849400..9c14fdfba 100644
--- a/engine/classes/ElggStaticVariableCache.php
+++ b/engine/classes/ElggStaticVariableCache.php
@@ -11,7 +11,7 @@ class ElggStaticVariableCache extends ElggSharedMemoryCache {
 	/**
 	 * The cache.
 	 *
-	 * @var unknown_type
+	 * @var array
 	 */
 	private static $__cache;
 
@@ -22,7 +22,7 @@ class ElggStaticVariableCache extends ElggSharedMemoryCache {
 	 * memory, optionally with a given namespace (to avoid overlap).
 	 *
 	 * @param string $namespace The namespace for this cache to write to.
-	 * @note namespaces of the same name are shared!
+	 * @warning namespaces of the same name are shared!
 	 */
 	function __construct($namespace = 'default') {
 		$this->setNamespace($namespace);
@@ -80,7 +80,7 @@ class ElggStaticVariableCache extends ElggSharedMemoryCache {
 	}
 
 	/**
-	 * This was probably meant to delete everything?
+	 * Clears the cache for a particular namespace
 	 *
 	 * @return void
 	 */
diff --git a/engine/lib/database.php b/engine/lib/database.php
index 2b348366d..18235149d 100644
--- a/engine/lib/database.php
+++ b/engine/lib/database.php
@@ -20,6 +20,7 @@
  * @warning be array this var may be an array or ElggStaticVariableCache depending on when called :(
  *
  * @global ElggStaticVariableCache|array $DB_QUERY_CACHE
+ * @access private
  */
 global $DB_QUERY_CACHE;
 $DB_QUERY_CACHE = array();
@@ -40,6 +41,7 @@ $DB_QUERY_CACHE = array();
  * 
  *
  * @global array $DB_DELAYED_QUERIES
+ * @access private
  */
 global $DB_DELAYED_QUERIES;
 $DB_DELAYED_QUERIES = array();
@@ -51,6 +53,7 @@ $DB_DELAYED_QUERIES = array();
  * $dblink as $dblink[$name] => resource.  Use get_db_link($name) to retrieve it.
  *
  * @global resource[] $dblink
+ * @access private
  */
 global $dblink;
 $dblink = array();
@@ -61,6 +64,7 @@ $dblink = array();
  * Each call to the database increments this counter.
  *
  * @global integer $dbcalls
+ * @access private
  */
 global $dbcalls;
 $dbcalls = 0;
-- 
cgit v1.2.3


From f461006377263b4a3cfe6b5f0c50f0df9e4fe35d Mon Sep 17 00:00:00 2001
From: cash 
Date: Sat, 13 Apr 2013 13:15:25 -0400
Subject: removed remnants of db profiling

---
 engine/lib/upgrades/2009102801.php | 4 ++--
 engine/lib/upgrades/2010061501.php | 4 ++--
 engine/lib/upgrades/2010071001.php | 4 ++--
 engine/lib/upgrades/2010071002.php | 4 ++--
 engine/lib/upgrades/2011052801.php | 4 ++--
 5 files changed, 10 insertions(+), 10 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/upgrades/2009102801.php b/engine/lib/upgrades/2009102801.php
index cab9a6835..b91b99d95 100644
--- a/engine/lib/upgrades/2009102801.php
+++ b/engine/lib/upgrades/2009102801.php
@@ -203,14 +203,14 @@ function user_file_matrix($guid) {
 	return "$time_created/$user->guid/";
 }
 
-global $DB_QUERY_CACHE, $DB_PROFILE, $ENTITY_CACHE;
+global $DB_QUERY_CACHE, $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();
+	$DB_QUERY_CACHE = $ENTITY_CACHE = array();
 
 	$to = $CONFIG->dataroot . user_file_matrix($user->guid);
 	foreach (array('1_0', '1_1', '1_6') as $version) {
diff --git a/engine/lib/upgrades/2010061501.php b/engine/lib/upgrades/2010061501.php
index 9ff7d3102..b23ad0820 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 $DB_QUERY_CACHE, $ENTITY_CACHE;
 
 		/**
 			Upgrade file locations
@@ -60,7 +60,7 @@ 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();
+			$DB_QUERY_CACHE = $ENTITY_CACHE = array();
 
 			$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..34f5a773e 100644
--- a/engine/lib/upgrades/2010071001.php
+++ b/engine/lib/upgrades/2010071001.php
@@ -30,11 +30,11 @@ function user_file_matrix_2010071001($guid) {
 
 $sizes = array('large', 'medium', 'small', 'tiny', 'master', 'topbar');
 
-global $DB_QUERY_CACHE, $DB_PROFILE, $ENTITY_CACHE, $CONFIG;
+global $DB_QUERY_CACHE, $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();
+	$DB_QUERY_CACHE = $ENTITY_CACHE = array();
 
 	$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..d1c74ed48 100644
--- a/engine/lib/upgrades/2010071002.php
+++ b/engine/lib/upgrades/2010071002.php
@@ -4,12 +4,12 @@
  */
 
 // loop through all users checking collections and notifications
-global $DB_QUERY_CACHE, $DB_PROFILE, $ENTITY_CACHE, $CONFIG;
+global $DB_QUERY_CACHE, $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();
+	$DB_QUERY_CACHE = $ENTITY_CACHE = array();
 
 	$user = get_entity($user->guid);
 	foreach ($NOTIFICATION_HANDLERS as $method => $foo) {
diff --git a/engine/lib/upgrades/2011052801.php b/engine/lib/upgrades/2011052801.php
index 8084bc06c..d68e0118e 100644
--- a/engine/lib/upgrades/2011052801.php
+++ b/engine/lib/upgrades/2011052801.php
@@ -2,7 +2,7 @@
 /**
  * Make sure all users have the relationship member_of_site
  */
-global $DB_QUERY_CACHE, $DB_PROFILE, $ENTITY_CACHE, $CONFIG;
+global $DB_QUERY_CACHE, $ENTITY_CACHE;
 $db_prefix = get_config('dbprefix');
 
 $limit = 100;
@@ -17,7 +17,7 @@ $q = "SELECT e.* FROM {$db_prefix}entities e
 $users = get_data($q);
 
 while ($users) {
-	$DB_QUERY_CACHE = $DB_PROFILE = $ENTITY_CACHE = array();
+	$DB_QUERY_CACHE = $ENTITY_CACHE = array();
 
 	// do manually to not trigger any events because these aren't new users.
 	foreach ($users as $user) {
-- 
cgit v1.2.3


From 25de363c7c89e04391bea72eaef0f5913cf485c0 Mon Sep 17 00:00:00 2001
From: cash 
Date: Sat, 13 Apr 2013 13:28:18 -0400
Subject: cleanup of entity caching code

---
 engine/classes/ElggEntity.php      |  6 ++--
 engine/classes/ElggGroup.php       |  2 +-
 engine/classes/ElggObject.php      |  2 +-
 engine/classes/ElggSite.php        |  2 +-
 engine/classes/ElggUser.php        |  2 +-
 engine/lib/entities.php            | 59 +++++++++++---------------------------
 engine/lib/river.php               |  6 ++--
 engine/lib/users.php               | 12 ++++----
 mod/pages/actions/pages/delete.php |  2 +-
 9 files changed, 34 insertions(+), 59 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggEntity.php b/engine/classes/ElggEntity.php
index 5a63c7b15..8b3ceb551 100644
--- a/engine/classes/ElggEntity.php
+++ b/engine/classes/ElggEntity.php
@@ -1270,7 +1270,7 @@ abstract class ElggEntity extends ElggData implements
 	public function save() {
 		$guid = $this->getGUID();
 		if ($guid > 0) {
-			cache_entity($this);
+			_elgg_cache_entity($this);
 
 			return update_entity(
 				$guid,
@@ -1320,7 +1320,7 @@ abstract class ElggEntity extends ElggData implements
 			$this->attributes['subtype'] = get_subtype_id($this->attributes['type'],
 				$this->attributes['subtype']);
 
-			cache_entity($this);
+			_elgg_cache_entity($this);
 
 			return $this->attributes['guid'];
 		}
@@ -1362,7 +1362,7 @@ abstract class ElggEntity extends ElggData implements
 
 			// Cache object handle
 			if ($this->attributes['guid']) {
-				cache_entity($this);
+				_elgg_cache_entity($this);
 			}
 
 			return true;
diff --git a/engine/classes/ElggGroup.php b/engine/classes/ElggGroup.php
index 7ab0bfa48..61f9163d5 100644
--- a/engine/classes/ElggGroup.php
+++ b/engine/classes/ElggGroup.php
@@ -335,7 +335,7 @@ class ElggGroup extends ElggEntity
 
 		$this->attributes = $attrs;
 		$this->attributes['tables_loaded'] = 2;
-		cache_entity($this);
+		_elgg_cache_entity($this);
 
 		return true;
 	}
diff --git a/engine/classes/ElggObject.php b/engine/classes/ElggObject.php
index 3cb76ffaf..d54752dca 100644
--- a/engine/classes/ElggObject.php
+++ b/engine/classes/ElggObject.php
@@ -107,7 +107,7 @@ class ElggObject extends ElggEntity {
 
 		$this->attributes = $attrs;
 		$this->attributes['tables_loaded'] = 2;
-		cache_entity($this);
+		_elgg_cache_entity($this);
 
 		return true;
 	}
diff --git a/engine/classes/ElggSite.php b/engine/classes/ElggSite.php
index deba5087e..dd996fe98 100644
--- a/engine/classes/ElggSite.php
+++ b/engine/classes/ElggSite.php
@@ -124,7 +124,7 @@ class ElggSite extends ElggEntity {
 
 		$this->attributes = $attrs;
 		$this->attributes['tables_loaded'] = 2;
-		cache_entity($this);
+		_elgg_cache_entity($this);
 
 		return true;
 	}
diff --git a/engine/classes/ElggUser.php b/engine/classes/ElggUser.php
index b80065b27..6d9f10b57 100644
--- a/engine/classes/ElggUser.php
+++ b/engine/classes/ElggUser.php
@@ -112,7 +112,7 @@ class ElggUser extends ElggEntity
 
 		$this->attributes = $attrs;
 		$this->attributes['tables_loaded'] = 2;
-		cache_entity($this);
+		_elgg_cache_entity($this);
 
 		return true;
 	}
diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index 156eec040..cb972b282 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -30,10 +30,10 @@ $SUBTYPE_CACHE = null;
  *
  * @param int $guid The entity guid
  *
- * @return null
+ * @return void
  * @access private
  */
-function invalidate_cache_for_entity($guid) {
+function _elgg_invalidate_cache_for_entity($guid) {
 	global $ENTITY_CACHE;
 
 	$guid = (int)$guid;
@@ -50,13 +50,13 @@ function invalidate_cache_for_entity($guid) {
  *
  * @param ElggEntity $entity Entity to cache
  *
- * @return null
- * @see retrieve_cached_entity()
- * @see invalidate_cache_for_entity()
+ * @return void
+ * @see _elgg_retrieve_cached_entity()
+ * @see _elgg_invalidate_cache_for_entity()
  * @access private
- * TODO(evan): Use an ElggCache object
+ * @todo Use an ElggCache object
  */
-function cache_entity(ElggEntity $entity) {
+function _elgg_cache_entity(ElggEntity $entity) {
 	global $ENTITY_CACHE;
 
 	// Don't cache non-plugin entities while access control is off, otherwise they could be
@@ -66,7 +66,7 @@ function cache_entity(ElggEntity $entity) {
 	}
 
 	// Don't store too many or we'll have memory problems
-	// TODO(evan): Pick a less arbitrary limit
+	// @todo Pick a less arbitrary limit
 	if (count($ENTITY_CACHE) > 256) {
 		$random_guid = array_rand($ENTITY_CACHE);
 
@@ -88,11 +88,11 @@ function cache_entity(ElggEntity $entity) {
  * @param int $guid The guid
  *
  * @return ElggEntity|bool false if entity not cached, or not fully loaded
- * @see cache_entity()
- * @see invalidate_cache_for_entity()
+ * @see _elgg_cache_entity()
+ * @see _elgg_invalidate_cache_for_entity()
  * @access private
  */
-function retrieve_cached_entity($guid) {
+function _elgg_retrieve_cached_entity($guid) {
 	global $ENTITY_CACHE;
 
 	if (isset($ENTITY_CACHE[$guid])) {
@@ -104,31 +104,6 @@ function retrieve_cached_entity($guid) {
 	return false;
 }
 
-/**
- * As retrieve_cached_entity, but returns the result as a stdClass
- * (compatible with load functions that expect a database row.)
- *
- * @param int $guid The guid
- *
- * @return mixed
- * @todo unused
- * @access private
- */
-function retrieve_cached_entity_row($guid) {
-	$obj = retrieve_cached_entity($guid);
-	if ($obj) {
-		$tmp = new stdClass;
-
-		foreach ($obj as $k => $v) {
-			$tmp->$k = $v;
-		}
-
-		return $tmp;
-	}
-
-	return false;
-}
-
 /**
  * Return the id for a given subtype.
  *
@@ -745,7 +720,7 @@ function get_entity($guid) {
 	}
 	
 	// Check local cache first
-	$new_entity = retrieve_cached_entity($guid);
+	$new_entity = _elgg_retrieve_cached_entity($guid);
 	if ($new_entity) {
 		return $new_entity;
 	}
@@ -782,7 +757,7 @@ function get_entity($guid) {
 	}
 
 	if ($new_entity) {
-		cache_entity($new_entity);
+		_elgg_cache_entity($new_entity);
 	}
 	return $new_entity;
 }
@@ -1037,7 +1012,7 @@ function elgg_get_entities(array $options = 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) {
-					cache_entity($item);
+					_elgg_cache_entity($item);
 					// plugins usually have only settings
 					if (!$item instanceof ElggPlugin) {
 						$guids[] = $item->guid;
@@ -1102,7 +1077,7 @@ function _elgg_fetch_entities_from_sql($sql) {
 		if (empty($row->guid) || empty($row->type)) {
 			throw new LogicException('Entity row missing guid or type');
 		}
-		if ($entity = retrieve_cached_entity($row->guid)) {
+		if ($entity = _elgg_retrieve_cached_entity($row->guid)) {
 			$rows[$i] = $entity;
 			continue;
 		}
@@ -1628,7 +1603,7 @@ function disable_entity($guid, $reason = "", $recursive = true) {
 
 				$entity->disableMetadata();
 				$entity->disableAnnotations();
-				invalidate_cache_for_entity($guid);
+				_elgg_invalidate_cache_for_entity($guid);
 
 				$res = update_data("UPDATE {$CONFIG->dbprefix}entities
 					SET enabled = 'no'
@@ -1726,7 +1701,7 @@ 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
diff --git a/engine/lib/river.php b/engine/lib/river.php
index f2ec1e101..4926a85c4 100644
--- a/engine/lib/river.php
+++ b/engine/lib/river.php
@@ -380,10 +380,10 @@ function _elgg_prefetch_river_entities(array $river_items) {
 	// prefetch objects and subjects
 	$guids = array();
 	foreach ($river_items as $item) {
-		if ($item->subject_guid && !retrieve_cached_entity($item->subject_guid)) {
+		if ($item->subject_guid && !_elgg_retrieve_cached_entity($item->subject_guid)) {
 			$guids[$item->subject_guid] = true;
 		}
-		if ($item->object_guid && !retrieve_cached_entity($item->object_guid)) {
+		if ($item->object_guid && !_elgg_retrieve_cached_entity($item->object_guid)) {
 			$guids[$item->object_guid] = true;
 		}
 	}
@@ -402,7 +402,7 @@ function _elgg_prefetch_river_entities(array $river_items) {
 	$guids = array();
 	foreach ($river_items as $item) {
 		$object = $item->getObjectEntity();
-		if ($object->container_guid && !retrieve_cached_entity($object->container_guid)) {
+		if ($object->container_guid && !_elgg_retrieve_cached_entity($object->container_guid)) {
 			$guids[$object->container_guid] = true;
 		}
 	}
diff --git a/engine/lib/users.php b/engine/lib/users.php
index 4a585c07f..868cd7815 100644
--- a/engine/lib/users.php
+++ b/engine/lib/users.php
@@ -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;
 		}
 
@@ -558,8 +558,8 @@ function get_user_by_username($username) {
 
 	// 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
@@ -592,9 +592,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
diff --git a/mod/pages/actions/pages/delete.php b/mod/pages/actions/pages/delete.php
index c99f15fbf..fd5791e4d 100644
--- a/mod/pages/actions/pages/delete.php
+++ b/mod/pages/actions/pages/delete.php
@@ -40,7 +40,7 @@ if (elgg_instanceof($page, 'object', 'page') || elgg_instanceof($page, 'object',
 						'metadata_name' => 'parent_guid',
 					));
 
-					invalidate_cache_for_entity($child_guid);
+					_elgg_invalidate_cache_for_entity($child_guid);
 					if ($newentity_cache) {
 						$newentity_cache->delete($child_guid);
 					}
-- 
cgit v1.2.3


From 5dd3d179f43b47231dab5dab5d5d9482a9810ef7 Mon Sep 17 00:00:00 2001
From: cash 
Date: Sat, 13 Apr 2013 13:36:56 -0400
Subject: removed query cache reset from unit test of acl. If this is needed,
 is bug in elgg core

---
 engine/tests/api/access_collections.php | 3 ---
 1 file changed, 3 deletions(-)

(limited to 'engine')

diff --git a/engine/tests/api/access_collections.php b/engine/tests/api/access_collections.php
index ebcd7d318..4acfae596 100644
--- a/engine/tests/api/access_collections.php
+++ b/engine/tests/api/access_collections.php
@@ -54,7 +54,6 @@ class ElggCoreAccessCollectionsTest extends ElggCoreUnitTest {
 	}
 
 	public function testCreateGetDeleteACL() {
-		global $DB_QUERY_CACHE;
 		
 		$acl_name = 'test access collection';
 		$acl_id = create_access_collection($acl_name);
@@ -67,8 +66,6 @@ class ElggCoreAccessCollectionsTest extends ElggCoreUnitTest {
 		$this->assertEqual($acl->id, $acl_id);
 
 		if ($acl) {
-			$DB_QUERY_CACHE = array();
-			
 			$this->assertEqual($acl->name, $acl_name);
 
 			$result = delete_access_collection($acl_id);
-- 
cgit v1.2.3


From 726007e5730f83340ea8ab294a9f5951586f42fc Mon Sep 17 00:00:00 2001
From: cash 
Date: Sat, 13 Apr 2013 14:10:02 -0400
Subject: introduces _elgg_invalidate_query_cache() to dry up the db query
 cache code

---
 engine/classes/ElggBatch.php                       |  5 +--
 engine/lib/database.php                            | 38 +++++++++-------------
 engine/lib/upgrade.php                             | 16 ++++-----
 engine/lib/upgrades/2009102801.php                 |  5 +--
 engine/lib/upgrades/2010061501.php                 |  6 ++--
 engine/lib/upgrades/2010071001.php                 |  5 +--
 engine/lib/upgrades/2010071002.php                 |  5 +--
 engine/lib/upgrades/2011052801.php                 |  5 +--
 ....8.13-update_user_location-8999eb8bf1bdd9a3.php |  4 +--
 9 files changed, 42 insertions(+), 47 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggBatch.php b/engine/classes/ElggBatch.php
index 5d59425d0..1912f89a2 100644
--- a/engine/classes/ElggBatch.php
+++ b/engine/classes/ElggBatch.php
@@ -229,8 +229,9 @@ class ElggBatch
 	private function getNextResultsChunk() {
 		// reset memory caches after first chunk load
 		if ($this->chunkIndex > 0) {
-			global $DB_QUERY_CACHE, $ENTITY_CACHE;
-			$DB_QUERY_CACHE = $ENTITY_CACHE = array();
+			global $ENTITY_CACHE;
+			$ENTITY_CACHE = array();
+			_elgg_invalidate_query_cache();
 		}
 
 		// always reset results.
diff --git a/engine/lib/database.php b/engine/lib/database.php
index 18235149d..b41eb4cda 100644
--- a/engine/lib/database.php
+++ b/engine/lib/database.php
@@ -460,19 +460,12 @@ function elgg_query_runner($query, $callback = null, $single = false) {
  * @access private
  */
 function insert_data($query) {
-	global $DB_QUERY_CACHE;
 
 	elgg_log("DB query $query", 'NOTICE');
 	
 	$dblink = get_db_link('write');
 
-	// Invalidate query cache
-	if ($DB_QUERY_CACHE) {
-		/* @var ElggStaticVariableCache $DB_QUERY_CACHE */
-		$DB_QUERY_CACHE->clear();
-	}
-
-	elgg_log("Query cache invalidated", 'NOTICE');
+	_elgg_invalidate_query_cache();
 
 	if (execute_query("$query", $dblink)) {
 		return mysql_insert_id($dblink);
@@ -492,18 +485,12 @@ function insert_data($query) {
  * @access private
  */
 function update_data($query) {
-	global $DB_QUERY_CACHE;
 
 	elgg_log("DB query $query", 'NOTICE');
 
 	$dblink = get_db_link('write');
 
-	// Invalidate query cache
-	if ($DB_QUERY_CACHE) {
-		/* @var ElggStaticVariableCache $DB_QUERY_CACHE */
-		$DB_QUERY_CACHE->clear();
-		elgg_log("Query cache invalidated", 'NOTICE');
-	}
+	_elgg_invalidate_query_cache();
 
 	if (execute_query("$query", $dblink)) {
 		return TRUE;
@@ -523,18 +510,12 @@ function update_data($query) {
  * @access private
  */
 function delete_data($query) {
-	global $DB_QUERY_CACHE;
 
 	elgg_log("DB query $query", 'NOTICE');
 
 	$dblink = get_db_link('write');
 
-	// Invalidate query cache
-	if ($DB_QUERY_CACHE) {
-		/* @var ElggStaticVariableCache $DB_QUERY_CACHE */
-		$DB_QUERY_CACHE->clear();
-		elgg_log("Query cache invalidated", 'NOTICE');
-	}
+	_elgg_invalidate_query_cache();
 
 	if (execute_query("$query", $dblink)) {
 		return mysql_affected_rows($dblink);
@@ -543,6 +524,19 @@ 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) {
+		/* @var ElggStaticVariableCache $DB_QUERY_CACHE */
+		$DB_QUERY_CACHE->clear();
+		elgg_log("Query cache invalidated", 'NOTICE');
+	}
+}
 
 /**
  * Return tables matching the database prefix {@link $CONFIG->dbprefix}% in the currently
diff --git a/engine/lib/upgrade.php b/engine/lib/upgrade.php
index d684af862..0cc1e64dc 100644
--- a/engine/lib/upgrade.php
+++ b/engine/lib/upgrade.php
@@ -354,16 +354,12 @@ function _elgg_upgrade_unlock() {
  * @access private
  */
 function _elgg_upgrade_is_locked() {
-	global $CONFIG, $DB_QUERY_CACHE;
-	
+	global $CONFIG;
+
 	$is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}upgrade_lock'"));
-	
-	// Invalidate query cache
-	if ($DB_QUERY_CACHE) {
-		/* @var ElggStaticVariableCache $DB_QUERY_CACHE */
-		$DB_QUERY_CACHE->clear();
-		elgg_log("Query cache invalidated", 'NOTICE');
-	}
-	
+
+	// @todo why?
+	_elgg_invalidate_query_cache();
+
 	return $is_locked;
 }
diff --git a/engine/lib/upgrades/2009102801.php b/engine/lib/upgrades/2009102801.php
index b91b99d95..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, $ENTITY_CACHE, $CONFIG;
+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 = $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/2010061501.php b/engine/lib/upgrades/2010061501.php
index b23ad0820..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, $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 = $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 34f5a773e..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, $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 = $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 d1c74ed48..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, $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 = $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/2011052801.php b/engine/lib/upgrades/2011052801.php
index d68e0118e..b5a8e1018 100644
--- a/engine/lib/upgrades/2011052801.php
+++ b/engine/lib/upgrades/2011052801.php
@@ -2,7 +2,7 @@
 /**
  * Make sure all users have the relationship member_of_site
  */
-global $DB_QUERY_CACHE, $ENTITY_CACHE;
+global $ENTITY_CACHE;
 $db_prefix = get_config('dbprefix');
 
 $limit = 100;
@@ -17,7 +17,8 @@ $q = "SELECT e.* FROM {$db_prefix}entities e
 $users = get_data($q);
 
 while ($users) {
-	$DB_QUERY_CACHE = $ENTITY_CACHE = array();
+	$ENTITY_CACHE = array();
+	_elgg_invalidate_query_cache();
 
 	// do manually to not trigger any events because these aren't new users.
 	foreach ($users as $user) {
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
index b38eb5100..8eccf05e2 100644
--- 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
@@ -7,8 +7,6 @@
  * This script turns that back into a string.
  */
 
-global $DB_QUERY_CACHE;
-
 $ia = elgg_set_ignore_access(true);
 $options = array(
 	'type' => 'user',
@@ -17,7 +15,7 @@ $options = array(
 $batch = new ElggBatch('elgg_get_entities', $options);
 
 foreach ($batch as $entity) {
-	$DB_QUERY_CACHE = array();
+	_elgg_invalidate_query_cache();
 	
 	if (is_array($entity->location)) {
 		$entity->location = implode(', ', $entity->location);
-- 
cgit v1.2.3


From 53b226d0e3d81c0cf45b2b39b506275a7a149ebe Mon Sep 17 00:00:00 2001
From: cash 
Date: Sat, 13 Apr 2013 14:28:01 -0400
Subject: adds LRU cache

---
 engine/classes/ElggLRUCache.php | 132 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 132 insertions(+)
 create mode 100644 engine/classes/ElggLRUCache.php

(limited to 'engine')

diff --git a/engine/classes/ElggLRUCache.php b/engine/classes/ElggLRUCache.php
new file mode 100644
index 000000000..add78ecb4
--- /dev/null
+++ b/engine/classes/ElggLRUCache.php
@@ -0,0 +1,132 @@
+maximumSize = $size;
+	}
+
+	/**
+	 * Get the value cached with this key
+	 *
+	 * @param int|string $key     The key. Strings that are ints are cast to ints.
+	 * @param mixed      $default The value to be returned if key not found. (Optional)
+	 * @return mixed
+	 */
+	public function get($key, $default = null) {
+		if (isset($this->data[$key])) {
+			$this->recordAccess($key);
+			return $this->data[$key];
+		} else {
+			return $default;
+		}
+	}
+
+	/**
+	 * Put something in the cache
+	 *
+	 * @param int|string $key   The key. Strings that are ints are cast to ints.
+	 * @param mixed      $value The value to cache
+	 * @return void
+	 */
+	public function put($key, $value) {
+		if (isset($this->data[$key])) {
+			$this->data[$key] = $value;
+			$this->recordAccess($key);
+		} else {
+			$this->data[$key] = $value;
+			if ($this->size() > $this->maximumSize) {
+				// remove least recently used element (front of array)
+				reset($this->data);
+				unset($this->data[key($this->data)]);
+			}
+		}
+	}
+
+	/**
+	 * Get the number of elements in the cache
+	 *
+	 * @return int
+	 */
+	public function size() {
+		return count($this->data);
+	}
+
+	/**
+	 * Does the cache contain an element with this key
+	 *
+	 * @param int|string $key The key
+	 * @return boolean
+	 */
+	public function containsKey($key) {
+		return isset($this->data[$key]);
+	}
+
+	/**
+	 * Remove the element with this key.
+	 *
+	 * @param int|string $key The key
+	 * @return mixed Value or null if not set
+	 */
+	public function remove($key) {
+		if (isset($this->data[$key])) {
+			$value = $this->data[$key];
+			unset($this->data[$key]);
+			return $value;
+		} else {
+			return null;
+		}
+	}
+
+	/**
+	 * Clear the cache
+	 * 
+	 * @return void
+	 */
+	public function clear() {
+		$this->data = array();
+	}
+
+	/**
+	 * Moves the element from current position to end of array
+	 * 
+	 * @param int|string $key The key
+	 * @return void
+	 */
+	protected function recordAccess($key) {
+		$value = $this->data[$key];
+		unset($this->data[$key]);
+		$this->data[$key] = $value;
+	}
+}
-- 
cgit v1.2.3


From fc9a1e985b0b20c74a913f22ec9ea7e0c16848a7 Mon Sep 17 00:00:00 2001
From: cash 
Date: Sat, 13 Apr 2013 14:35:24 -0400
Subject: updated lru cache so easier to integrate

---
 engine/classes/ElggLRUCache.php | 55 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 52 insertions(+), 3 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggLRUCache.php b/engine/classes/ElggLRUCache.php
index add78ecb4..90e63bb61 100644
--- a/engine/classes/ElggLRUCache.php
+++ b/engine/classes/ElggLRUCache.php
@@ -13,7 +13,7 @@
  * @package    Elgg.Core
  * @subpackage Cache
  */
-class ElggLRUCache {
+class ElggLRUCache implements ArrayAccess {
 	/** @var int */
 	protected $maximumSize;
 
@@ -54,13 +54,13 @@ class ElggLRUCache {
 	}
 
 	/**
-	 * Put something in the cache
+	 * Add something to the cache
 	 *
 	 * @param int|string $key   The key. Strings that are ints are cast to ints.
 	 * @param mixed      $value The value to cache
 	 * @return void
 	 */
-	public function put($key, $value) {
+	public function set($key, $value) {
 		if (isset($this->data[$key])) {
 			$this->data[$key] = $value;
 			$this->recordAccess($key);
@@ -129,4 +129,53 @@ class ElggLRUCache {
 		unset($this->data[$key]);
 		$this->data[$key] = $value;
 	}
+
+	/**
+	 * Assigns a value for the specified key
+	 *
+	 * @see ArrayAccess::offsetSet()
+	 *
+	 * @param int|string $key   The key to assign the value to.
+	 * @param mixed      $value The value to set.
+	 * @return void
+	 */
+	function offsetSet($key, $value) {
+		$this->set($key, $value);
+	}
+
+	/**
+	 * Get the value for specified key
+	 *
+	 * @see ArrayAccess::offsetGet()
+	 *
+	 * @param int|string $key The key to retrieve.
+	 * @return mixed
+	 */
+	function offsetGet($key) {
+		return $this->get($key);
+	}
+
+	/**
+	 * Unsets a key.
+	 *
+	 * @see ArrayAccess::offsetUnset()
+	 *
+	 * @param int|string $key The key to unset.
+	 * @return void
+	 */
+	function offsetUnset($key) {
+		$this->remove($key);
+	}
+
+	/**
+	 * Does key exist?
+	 *
+	 * @see ArrayAccess::offsetExists()
+	 *
+	 * @param int|string $key A key to check for.
+	 * @return boolean
+	 */
+	function offsetExists($key) {
+		return $this->containsKey($key);
+	}
 }
-- 
cgit v1.2.3


From 21c92cf39d719a913cd9e29474c04781e9cd72ef Mon Sep 17 00:00:00 2001
From: cash 
Date: Sat, 13 Apr 2013 15:05:40 -0400
Subject: Fixes #4978 integrates LRU cache for db query cache

---
 engine/classes/ElggLRUCache.php |  8 ++++----
 engine/lib/database.php         | 29 +++++++++++++++--------------
 2 files changed, 19 insertions(+), 18 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggLRUCache.php b/engine/classes/ElggLRUCache.php
index 90e63bb61..f51af2ed7 100644
--- a/engine/classes/ElggLRUCache.php
+++ b/engine/classes/ElggLRUCache.php
@@ -139,7 +139,7 @@ class ElggLRUCache implements ArrayAccess {
 	 * @param mixed      $value The value to set.
 	 * @return void
 	 */
-	function offsetSet($key, $value) {
+	public function offsetSet($key, $value) {
 		$this->set($key, $value);
 	}
 
@@ -151,7 +151,7 @@ class ElggLRUCache implements ArrayAccess {
 	 * @param int|string $key The key to retrieve.
 	 * @return mixed
 	 */
-	function offsetGet($key) {
+	public function offsetGet($key) {
 		return $this->get($key);
 	}
 
@@ -163,7 +163,7 @@ class ElggLRUCache implements ArrayAccess {
 	 * @param int|string $key The key to unset.
 	 * @return void
 	 */
-	function offsetUnset($key) {
+	public function offsetUnset($key) {
 		$this->remove($key);
 	}
 
@@ -175,7 +175,7 @@ class ElggLRUCache implements ArrayAccess {
 	 * @param int|string $key A key to check for.
 	 * @return boolean
 	 */
-	function offsetExists($key) {
+	public function offsetExists($key) {
 		return $this->containsKey($key);
 	}
 }
diff --git a/engine/lib/database.php b/engine/lib/database.php
index b41eb4cda..3553d787d 100644
--- a/engine/lib/database.php
+++ b/engine/lib/database.php
@@ -12,18 +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:
  * 
- * $DB_QUERY_CACHE[$query] => array(result1, result2, ... resultN)
+ * $DB_QUERY_CACHE[query hash] => array(result1, result2, ... resultN)
  * 
+ * @see elgg_query_runner() for details on the hash.
  *
- * @warning be array this var may be an array or ElggStaticVariableCache depending on when called :(
+ * @warning Elgg used to set this as an empty array to turn off the cache
  *
- * @global ElggStaticVariableCache|array $DB_QUERY_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.
@@ -127,9 +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)) {
-		// @todo everywhere else this is assigned to array(), making it dangerous to call
-		// object methods on this. We should consider making this an plain array
-		$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);		
 	}
 }
 
@@ -404,11 +404,9 @@ function elgg_query_runner($query, $callback = null, $single = false) {
 
 	// Is cached?
 	if ($DB_QUERY_CACHE) {
-		$cached_query = $DB_QUERY_CACHE[$hash];
-
-		if ($cached_query !== FALSE) {
+		if (isset($DB_QUERY_CACHE[$hash])) {
 			elgg_log("DB query $query results returned from cache (hash: $hash)", 'NOTICE');
-			return $cached_query;
+			return $DB_QUERY_CACHE[$hash];			
 		}
 	}
 
@@ -531,10 +529,13 @@ function delete_data($query) {
  */
 function _elgg_invalidate_query_cache() {
 	global $DB_QUERY_CACHE;
-	if ($DB_QUERY_CACHE) {
-		/* @var ElggStaticVariableCache $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');
 	}
 }
 
-- 
cgit v1.2.3


From 037cce80328318f7151c498d48f983cabd886505 Mon Sep 17 00:00:00 2001
From: cash 
Date: Sun, 14 Apr 2013 19:59:30 -0400
Subject: entity and query cache are size limited so don't need cache clearing
 in ElggBatch

---
 engine/classes/ElggBatch.php | 6 ------
 1 file changed, 6 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggBatch.php b/engine/classes/ElggBatch.php
index 1912f89a2..eb93b0f5d 100644
--- a/engine/classes/ElggBatch.php
+++ b/engine/classes/ElggBatch.php
@@ -227,12 +227,6 @@ class ElggBatch
 	 * @return bool
 	 */
 	private function getNextResultsChunk() {
-		// reset memory caches after first chunk load
-		if ($this->chunkIndex > 0) {
-			global $ENTITY_CACHE;
-			$ENTITY_CACHE = array();
-			_elgg_invalidate_query_cache();
-		}
 
 		// always reset results.
 		$this->results = array();
-- 
cgit v1.2.3


From 21d8d10c3a3e974f1dfc110ad55e09a1d4db98c9 Mon Sep 17 00:00:00 2001
From: cash 
Date: Tue, 16 Apr 2013 19:27:18 -0400
Subject: Fixes #5362 correctly getting user on user plugin settings page

---
 engine/lib/user_settings.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/lib/user_settings.php b/engine/lib/user_settings.php
index 3466c25f9..0e36dc46d 100644
--- a/engine/lib/user_settings.php
+++ b/engine/lib/user_settings.php
@@ -308,7 +308,7 @@ function usersettings_page_handler($page) {
 		$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);
 	}
 
-- 
cgit v1.2.3


From f1d0a8e62f25002644c7b0394d5a8940d4ac7e5b Mon Sep 17 00:00:00 2001
From: Cash Costello 
Date: Fri, 19 Apr 2013 08:05:25 -0400
Subject: Fixes #5367 returning all groups that a user belongs to - need to
 deprecate this function

---
 engine/lib/group.php | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/lib/group.php b/engine/lib/group.php
index 624029d98..359bc59c2 100644
--- a/engine/lib/group.php
+++ b/engine/lib/group.php
@@ -242,7 +242,8 @@ function get_users_membership($user_guid) {
 	$options = array(
 		'relationship' => 'member',
 		'relationship_guid' => $user_guid,
-		'inverse_relationship' => FALSE
+		'inverse_relationship' => false,
+		'limit' => false,
 	);
 	return elgg_get_entities_from_relationship($options);
 }
-- 
cgit v1.2.3


From aa409144fcac454c8f6e2566606e0fb206d933d7 Mon Sep 17 00:00:00 2001
From: cash 
Date: Fri, 19 Apr 2013 20:00:47 -0400
Subject: Fixes #5233 password reset uses entity save so memcache is cleared

---
 engine/lib/users.php | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/users.php b/engine/lib/users.php
index 868cd7815..9a5194896 100644
--- a/engine/lib/users.php
+++ b/engine/lib/users.php
@@ -705,18 +705,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) {
-		$salt = generate_random_cleartext_password(); // Reset the salt
-		$user->salt = $salt;
+		$ia = elgg_set_ignore_access();
 
-		$hash = generate_user_password($user, $password);
+		$user->salt = generate_random_cleartext_password();
+		$hash = generate_user_password($user, $password);		
+		$user->password = $hash;
+		$result = (bool)$user->save();
 
-		$query = "UPDATE {$CONFIG->dbprefix}users_entity
-			set password='$hash', salt='$salt' where guid=$user_guid";
-		return update_data($query);
+		elgg_set_ignore_access($ia);
+
+		return $result;
 	}
 
 	return false;
-- 
cgit v1.2.3


From 49ee96be289ce087462edf70a021f38ae87761a8 Mon Sep 17 00:00:00 2001
From: cash 
Date: Fri, 19 Apr 2013 21:18:11 -0400
Subject: Fixes #4530 not caching 0 as page owner

---
 engine/lib/pageowner.php | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/lib/pageowner.php b/engine/lib/pageowner.php
index 7e8e6e430..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;
 }
-- 
cgit v1.2.3


From 39886afeec37309963be57551699c7bfc3f6c37b Mon Sep 17 00:00:00 2001
From: Cash Costello 
Date: Sat, 20 Apr 2013 09:15:59 -0400
Subject: Fixes #5004 fixed some documentation in database lib

---
 engine/lib/database.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/database.php b/engine/lib/database.php
index 3553d787d..37dfb8f8d 100644
--- a/engine/lib/database.php
+++ b/engine/lib/database.php
@@ -473,7 +473,7 @@ 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}.
  *
@@ -498,7 +498,7 @@ 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}.
  *
-- 
cgit v1.2.3


From 834c4ad0bf82f28949b108eb6c957fde3c18e1ce Mon Sep 17 00:00:00 2001
From: Cash Costello 
Date: Sat, 20 Apr 2013 11:07:44 -0400
Subject: Fixes #5369 allows ! in urls and adds unit tests

---
 engine/lib/output.php                 | 25 ++++++++++-------
 engine/tests/regression/trac_bugs.php | 52 +++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 10 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/output.php b/engine/lib/output.php
index c5a04989b..fe5bbcaaf 100644
--- a/engine/lib/output.php
+++ b/engine/lib/output.php
@@ -13,28 +13,33 @@
  * @param string $text The input string
  *
  * @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 
 	// must be in  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('/(?"\'\!\(\),]+)/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('/(?"\'\!\(\),]+)/i',
+	$r = preg_replace_callback('/(?"\'\(\)]+)/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("/", "/", $url);
-			return "$urltext$period";
+			return "$urltext$punc";
 		'
 	), $text);
 
diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php
index 58444dd39..83b78bc6b 100644
--- a/engine/tests/regression/trac_bugs.php
+++ b/engine/tests/regression/trac_bugs.php
@@ -236,4 +236,56 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest {
 			$this->assertIdentical($expected, $friendly_title);
 		}
 	}
+
+	/**
+	 * Test #5369 -- parse_urls()
+	 * https://github.com/Elgg/Elgg/issues/5369
+	 */
+	public function test_parse_urls() {
+
+		$cases = array(
+			'no.link.here' =>
+				'no.link.here',
+			'simple link http://example.org test' =>
+				'simple link http://example.org test',
+			'non-ascii http://ñew.org/ test' =>
+				'non-ascii http://ñew.org/ test',
+
+			// section 2.1
+			'percent encoded http://example.org/a%20b test' =>
+				'percent encoded http://example.org/a%20b test',
+			// section 2.2: skipping single quote and parenthese
+			'reserved characters http://example.org/:/?#[]@!$&*+,;= test' =>
+				'reserved characters http://example.org/:/?#[]@!$&*+,;= test',
+			// section 2.3
+			'unreserved characters http://example.org/a1-._~ test' =>
+				'unreserved characters http://example.org/a1-._~ test',
+
+			'parameters http://example.org/?val[]=1&val[]=2 test' =>
+				'parameters http://example.org/?val[]=1&val[]=2 test',
+			'port http://example.org:80/ test' =>
+				'port http://example.org:80/ test',
+
+			'parentheses (http://www.google.com) test' =>
+				'parentheses (http://www.google.com) test',
+			'comma http://elgg.org, test' =>
+				'comma http://elgg.org, test',
+			'period http://elgg.org. test' =>
+				'period http://elgg.org. test',
+			'exclamation http://elgg.org! test' =>
+				'exclamation http://elgg.org! test',
+
+			'already anchor twitter test' =>
+				'already anchor twitter test',
+
+			'ssl https://example.org/ test' =>
+				'ssl https://example.org/ test',
+			'ftp ftp://example.org/ test' =>
+				'ftp ftp://example.org/ test',
+
+		);
+		foreach ($cases as $input => $output) {
+			$this->assertEqual($output, parse_urls($input));
+		}
+	}
 }
-- 
cgit v1.2.3


From 164ff10b46d5917c7ab6ad068abf10e492464691 Mon Sep 17 00:00:00 2001
From: cash 
Date: Sat, 20 Apr 2013 12:08:27 -0400
Subject: Fixes #5244 adds nofollow to anchor tags created by parse_urls()

---
 engine/lib/output.php                 |  2 +-
 engine/tests/regression/trac_bugs.php | 26 +++++++++++++-------------
 2 files changed, 14 insertions(+), 14 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/output.php b/engine/lib/output.php
index fe5bbcaaf..6905b9b71 100644
--- a/engine/lib/output.php
+++ b/engine/lib/output.php
@@ -39,7 +39,7 @@ function parse_urls($text) {
 				$url = rtrim($url, ".!,");
 			}
 			$urltext = str_replace("/", "/", $url);
-			return "$urltext$punc";
+			return "$urltext$punc";
 		'
 	), $text);
 
diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php
index 83b78bc6b..4de9c306b 100644
--- a/engine/tests/regression/trac_bugs.php
+++ b/engine/tests/regression/trac_bugs.php
@@ -247,41 +247,41 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest {
 			'no.link.here' =>
 				'no.link.here',
 			'simple link http://example.org test' =>
-				'simple link http://example.org test',
+				'simple link http://example.org test',
 			'non-ascii http://ñew.org/ test' =>
-				'non-ascii http://ñew.org/ test',
+				'non-ascii http://ñew.org/ test',
 
 			// section 2.1
 			'percent encoded http://example.org/a%20b test' =>
-				'percent encoded http://example.org/a%20b test',
+				'percent encoded http://example.org/a%20b test',
 			// section 2.2: skipping single quote and parenthese
 			'reserved characters http://example.org/:/?#[]@!$&*+,;= test' =>
-				'reserved characters http://example.org/:/?#[]@!$&*+,;= test',
+				'reserved characters http://example.org/:/?#[]@!$&*+,;= test',
 			// section 2.3
 			'unreserved characters http://example.org/a1-._~ test' =>
-				'unreserved characters http://example.org/a1-._~ test',
+				'unreserved characters http://example.org/a1-._~ test',
 
 			'parameters http://example.org/?val[]=1&val[]=2 test' =>
-				'parameters http://example.org/?val[]=1&val[]=2 test',
+				'parameters http://example.org/?val[]=1&val[]=2 test',
 			'port http://example.org:80/ test' =>
-				'port http://example.org:80/ test',
+				'port http://example.org:80/ test',
 
 			'parentheses (http://www.google.com) test' =>
-				'parentheses (http://www.google.com) test',
+				'parentheses (http://www.google.com) test',
 			'comma http://elgg.org, test' =>
-				'comma http://elgg.org, test',
+				'comma http://elgg.org, test',
 			'period http://elgg.org. test' =>
-				'period http://elgg.org. test',
+				'period http://elgg.org. test',
 			'exclamation http://elgg.org! test' =>
-				'exclamation http://elgg.org! test',
+				'exclamation http://elgg.org! test',
 
 			'already anchor twitter test' =>
 				'already anchor twitter test',
 
 			'ssl https://example.org/ test' =>
-				'ssl https://example.org/ test',
+				'ssl https://example.org/ test',
 			'ftp ftp://example.org/ test' =>
-				'ftp ftp://example.org/ test',
+				'ftp ftp://example.org/ test',
 
 		);
 		foreach ($cases as $input => $output) {
-- 
cgit v1.2.3


From ed99f7b064a0749603f16644ba735de7ba93c17e Mon Sep 17 00:00:00 2001
From: Cash Costello 
Date: Sun, 21 Apr 2013 11:54:42 -0400
Subject: fixed typos on method name

---
 engine/classes/ElggDiskFilestore.php | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggDiskFilestore.php b/engine/classes/ElggDiskFilestore.php
index ded653436..663d33c02 100644
--- a/engine/classes/ElggDiskFilestore.php
+++ b/engine/classes/ElggDiskFilestore.php
@@ -213,7 +213,7 @@ class ElggDiskFilestore extends ElggFilestore {
 			throw new InvalidParameterException($msg);
 		}
 
-		return $this->dir_root . $this->makefileMatrix($owner_guid) . $file->getFilename();
+		return $this->dir_root . $this->makeFileMatrix($owner_guid) . $file->getFilename();
 	}
 
 	/**
@@ -248,7 +248,7 @@ class ElggDiskFilestore extends ElggFilestore {
 	 */
 	public function getSize($prefix = '', $container_guid) {
 		if ($container_guid) {
-			return get_dir_size($this->dir_root . $this->makefileMatrix($container_guid) . $prefix);
+			return get_dir_size($this->dir_root . $this->makeFileMatrix($container_guid) . $prefix);
 		} else {
 			return false;
 		}
@@ -335,7 +335,7 @@ class ElggDiskFilestore extends ElggFilestore {
 	protected function make_file_matrix($identifier) {
 		elgg_deprecated_notice('ElggDiskFilestore::make_file_matrix() is deprecated by ::makeFileMatrix()', 1.8);
 
-		return $this->makefileMatrix($identifier);
+		return $this->makeFileMatrix($identifier);
 	}
 	// @codingStandardsIgnoreEnd
 
-- 
cgit v1.2.3


From 6f3df999223874592b6cf4f8399b5f9a3fa5bbd1 Mon Sep 17 00:00:00 2001
From: Cash Costello 
Date: Sun, 21 Apr 2013 12:20:21 -0400
Subject: Fixes #5207 returning false if filename is not set

---
 engine/classes/ElggDiskFilestore.php | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggDiskFilestore.php b/engine/classes/ElggDiskFilestore.php
index 663d33c02..6e2354012 100644
--- a/engine/classes/ElggDiskFilestore.php
+++ b/engine/classes/ElggDiskFilestore.php
@@ -194,7 +194,9 @@ class ElggDiskFilestore extends ElggFilestore {
 	}
 
 	/**
-	 * Returns the filename as saved on disk for an ElggFile object
+	 * Get the filename as saved on disk for an ElggFile object
+	 *
+	 * Returns an empty string if no filename set
 	 *
 	 * @param ElggFile $file File object
 	 *
@@ -213,7 +215,12 @@ class ElggDiskFilestore extends ElggFilestore {
 			throw new InvalidParameterException($msg);
 		}
 
-		return $this->dir_root . $this->makeFileMatrix($owner_guid) . $file->getFilename();
+		$filename = $file->getFilename();
+		if (!$filename) {
+			return '';
+		}
+
+		return $this->dir_root . $this->makeFileMatrix($owner_guid) . $filename;
 	}
 
 	/**
@@ -221,7 +228,7 @@ class ElggDiskFilestore extends ElggFilestore {
 	 *
 	 * @param ElggFile $file File object
 	 *
-	 * @return mixed
+	 * @return string
 	 */
 	public function grabFile(ElggFile $file) {
 		return file_get_contents($file->getFilenameOnFilestore());
@@ -235,6 +242,9 @@ class ElggDiskFilestore extends ElggFilestore {
 	 * @return bool
 	 */
 	public function exists(ElggFile $file) {
+		if (!$file->getFilename()) {
+			return false;
+		}
 		return file_exists($this->getFilenameOnFilestore($file));
 	}
 
-- 
cgit v1.2.3


From cd7922c58f3f2d04b8ca4bcf336ecda2787c821e Mon Sep 17 00:00:00 2001
From: Jeff Tilson 
Date: Mon, 29 Apr 2013 13:38:42 -0400
Subject: Fixes #2057 (broken internet archive links)

---
 engine/lib/output.php                 | 2 +-
 engine/tests/regression/trac_bugs.php | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/lib/output.php b/engine/lib/output.php
index 6905b9b71..5adc01053 100644
--- a/engine/lib/output.php
+++ b/engine/lib/output.php
@@ -27,7 +27,7 @@ function parse_urls($text) {
 	// By default htmlawed rewrites tags to this format.
 	// if PHP supported conditional negative lookbehinds we could use this:
 	// $r = preg_replace_callback('/(?"\'\!\(\),]+)/i',
-	$r = preg_replace_callback('/(?"\'\(\)]+)/i',
+	$r = preg_replace_callback('/(?"\'\(\)]+)/i',
 	create_function(
 		'$matches',
 		'
diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php
index 4de9c306b..b791dcad3 100644
--- a/engine/tests/regression/trac_bugs.php
+++ b/engine/tests/regression/trac_bugs.php
@@ -288,4 +288,13 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest {
 			$this->assertEqual($output, parse_urls($input));
 		}
 	}
+
+	/**
+	 * Test #2057 -- parse_urls()
+	 * https://github.com/Elgg/Elgg/issues/2057
+	 */
+	public function test_archive_url() {
+		$input = 'google';
+		$this->assertEqual($input, parse_urls($input));
+	}
 }
-- 
cgit v1.2.3


From 003439fd46cb5e0dedfabf6e49110b3bdffbefe9 Mon Sep 17 00:00:00 2001
From: Jeff Tilson 
Date: Mon, 29 Apr 2013 14:06:18 -0400
Subject: Including internet archive url test in existing test_parse_url
 function

---
 engine/tests/regression/trac_bugs.php | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

(limited to 'engine')

diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php
index b791dcad3..cb3f20421 100644
--- a/engine/tests/regression/trac_bugs.php
+++ b/engine/tests/regression/trac_bugs.php
@@ -282,19 +282,12 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest {
 				'ssl https://example.org/ test',
 			'ftp ftp://example.org/ test' =>
 				'ftp ftp://example.org/ test',
+			'google' =>
+				'google'
 
 		);
 		foreach ($cases as $input => $output) {
 			$this->assertEqual($output, parse_urls($input));
 		}
 	}
-
-	/**
-	 * Test #2057 -- parse_urls()
-	 * https://github.com/Elgg/Elgg/issues/2057
-	 */
-	public function test_archive_url() {
-		$input = 'google';
-		$this->assertEqual($input, parse_urls($input));
-	}
 }
-- 
cgit v1.2.3


From f04fdceb5941df31e1ac94f7fb586c2688813da7 Mon Sep 17 00:00:00 2001
From: Jeff Tilson 
Date: Mon, 29 Apr 2013 14:42:24 -0400
Subject: Adding single quote anchor to parse_url unit test

---
 engine/tests/regression/trac_bugs.php | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

(limited to 'engine')

diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php
index cb3f20421..b7654a794 100644
--- a/engine/tests/regression/trac_bugs.php
+++ b/engine/tests/regression/trac_bugs.php
@@ -282,8 +282,12 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest {
 				'ssl https://example.org/ test',
 			'ftp ftp://example.org/ test' =>
 				'ftp ftp://example.org/ test',
-			'google' =>
-				'google'
+
+			'web archive anchor google' =>
+				'web archive anchor google',
+
+			'single quotes already anchor yahoo' => 
+				'single quotes already anchor yahoo'
 
 		);
 		foreach ($cases as $input => $output) {
-- 
cgit v1.2.3


From 459e8d04b88b8bf7914105b1723624d23a5b3669 Mon Sep 17 00:00:00 2001
From: cash 
Date: Thu, 2 May 2013 19:56:52 -0400
Subject: Fixes #5405 fixes fatal error

---
 engine/lib/admin.php | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/admin.php b/engine/lib/admin.php
index ec19a5476..243cdef46 100644
--- a/engine/lib/admin.php
+++ b/engine/lib/admin.php
@@ -468,14 +468,18 @@ function admin_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") || elgg_view_exists("plugins/{$page[1]}/settings"))) {
+	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]}");
-- 
cgit v1.2.3


From d785357ba7cb9e8a6bb7b2f91bf389e6bd1e636b Mon Sep 17 00:00:00 2001
From: cash 
Date: Thu, 2 May 2013 22:02:41 -0400
Subject: Fixes #5418 adds enabled clause for annotations

---
 engine/lib/metastrings.php       | 14 ++++++++------
 engine/tests/api/metastrings.php | 32 ++++++++++++++++++++++++++++++--
 2 files changed, 38 insertions(+), 8 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/metastrings.php b/engine/lib/metastrings.php
index f49b4a163..39a81c6d0 100644
--- a/engine/lib/metastrings.php
+++ b/engine/lib/metastrings.php
@@ -421,6 +421,8 @@ 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');
 	}
 
 	if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE) {
@@ -510,7 +512,7 @@ function elgg_get_metastring_sql($table, $names = null, $values = null,
 		&& !$ids
 		&& (!$pairs && $pairs !== 0)) {
 
-		return '';
+		return array();
 	}
 
 	$db_prefix = elgg_get_config('dbprefix');
@@ -520,8 +522,6 @@ function elgg_get_metastring_sql($table, $names = null, $values = null,
 	// only supported on values.
 	$binary = ($case_sensitive) ? ' BINARY ' : '';
 
-	$access = get_access_sql_suffix($table);
-
 	$return = array (
 		'joins' => array (),
 		'wheres' => array()
@@ -586,13 +586,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)";
 	}
diff --git a/engine/tests/api/metastrings.php b/engine/tests/api/metastrings.php
index 0a8945084..cfcfb6d07 100644
--- a/engine/tests/api/metastrings.php
+++ b/engine/tests/api/metastrings.php
@@ -55,8 +55,11 @@ class ElggCoreMetastringsTest extends ElggCoreUnitTest {
 	 * Called after each test method.
 	 */
 	public function tearDown() {
-		// do not allow SimpleTest to interpret Elgg notices as exceptions
-		$this->swallowErrors();
+		access_show_hidden_entities(true);
+		elgg_delete_annotations(array(
+			'guid' => $this->object->guid,
+		));
+		access_show_hidden_entities(false);
 	}
 
 	/**
@@ -98,6 +101,31 @@ class ElggCoreMetastringsTest extends ElggCoreUnitTest {
 		}
 	}
 
+	public function testGetMetastringObjectFromIDWithDisabledAnnotation() {
+		$name = 'test_annotation_name' . rand();
+		$value = 'test_annotation_value' . rand();
+		$id = create_annotation($this->object->guid, $name, $value);
+		$annotation = elgg_get_annotation_from_id($id);
+		$this->assertTrue($annotation->disable());
+
+		$test = elgg_get_metastring_based_object_from_id($id, 'annotation');
+		$this->assertEqual(false, $test);
+	}
+
+	public function testGetMetastringBasedObjectWithDisabledAnnotation() {
+		$name = 'test_annotation_name' . rand();
+		$value = 'test_annotation_value' . rand();
+		$id = create_annotation($this->object->guid, $name, $value);
+		$annotation = elgg_get_annotation_from_id($id);
+		$this->assertTrue($annotation->disable());
+
+		$test = elgg_get_metastring_based_objects(array(
+			'metastring_type' => 'annotations',
+			'guid' => $this->object->guid,
+		));
+		$this->assertEqual(array(), $test);
+	}
+
 	public function testEnableDisableByID() {
 		$db_prefix = elgg_get_config('dbprefix');
 		$annotations = $this->createAnnotations(1);
-- 
cgit v1.2.3


From 4c82412b8f20a17ecb87b495af5fbbc0700c28c3 Mon Sep 17 00:00:00 2001
From: cash 
Date: Thu, 2 May 2013 22:08:48 -0400
Subject: not sure what a flush() is doing there

---
 engine/tests/api/metastrings.php | 1 -
 1 file changed, 1 deletion(-)

(limited to 'engine')

diff --git a/engine/tests/api/metastrings.php b/engine/tests/api/metastrings.php
index cfcfb6d07..5efdab972 100644
--- a/engine/tests/api/metastrings.php
+++ b/engine/tests/api/metastrings.php
@@ -147,7 +147,6 @@ class ElggCoreMetastringsTest extends ElggCoreUnitTest {
 			// enable
 			$ashe = access_get_show_hidden_status();
 			access_show_hidden_entities(true);
-			flush();
 			$this->assertTrue(elgg_set_metastring_based_object_enabled_by_id($id, 'yes', $type));
 
 			$test = get_data($q);
-- 
cgit v1.2.3


From 8585af507a98ba1124220b9c266a8377aa490693 Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Sun, 5 May 2013 17:55:27 -0400
Subject: Fixes #5435: Allows upgrade to boot on old schemas

---
 engine/classes/ElggAttributeLoader.php | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggAttributeLoader.php b/engine/classes/ElggAttributeLoader.php
index d1e15008e..b91e4b88a 100644
--- a/engine/classes/ElggAttributeLoader.php
+++ b/engine/classes/ElggAttributeLoader.php
@@ -209,11 +209,8 @@ class ElggAttributeLoader {
 			}
 		}
 
-		// loading complete: re-check missing and check type
-		if (($was_missing_primaries && $this->isMissingPrimaries($row))
-				|| ($was_missing_secondaries && $this->isMissingSecondaries($row))) {
-			throw new LogicException('Attribute loaders failed to return proper attributes');
-		}
+		// Note: If there are still missing attributes, we're running on a 1.7 or earlier schema. We let
+		// this pass so the upgrades can run.
 
 		// guid needs to be an int  http://trac.elgg.org/ticket/4111
 		$row['guid'] = (int) $row['guid'];
-- 
cgit v1.2.3


From 4bd919e25319c75c199490f1f064643c5df799ff Mon Sep 17 00:00:00 2001
From: Cash Costello 
Date: Sat, 11 May 2013 08:35:38 -0400
Subject: Fixes #5441 deprecates the entity caching functions

---
 engine/lib/deprecated-1.8.php | 44 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

(limited to 'engine')

diff --git a/engine/lib/deprecated-1.8.php b/engine/lib/deprecated-1.8.php
index 2b4ffcc4f..6aa42a81d 100644
--- a/engine/lib/deprecated-1.8.php
+++ b/engine/lib/deprecated-1.8.php
@@ -4772,3 +4772,47 @@ function default_page_handler($page, $handler) {
 
 	return FALSE;
 }
+
+/**
+ * Invalidate this class's entry in the cache.
+ *
+ * @param int $guid The entity guid
+ *
+ * @return void
+ * @access private
+ * @deprecated 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);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * 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);
+}
-- 
cgit v1.2.3


From 4129637ba28113cea9b27a9644d51354f67e9f55 Mon Sep 17 00:00:00 2001
From: Cash Costello 
Date: Sat, 11 May 2013 09:59:12 -0400
Subject: Fixes #5419 adds tests for enabling/disabling annotations and fixes
 bug with deleting disabled annotations when deleting an entity

---
 engine/lib/annotations.php       | 24 +++++++-----
 engine/lib/entities.php          | 11 +++++-
 engine/lib/metadata.php          | 13 +++----
 engine/tests/api/annotations.php | 80 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 108 insertions(+), 20 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php
index bd5ea1a1f..81755f169 100644
--- a/engine/lib/annotations.php
+++ b/engine/lib/annotations.php
@@ -224,7 +224,7 @@ function elgg_get_annotations(array $options = array()) {
  *          annotation_name(s), annotation_value(s), or guid(s) must be set.
  *
  * @param array $options An options array. {@See elgg_get_annotations()}
- * @return mixed Null if the metadata name is invalid. Bool on success or fail.
+ * @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) {
@@ -242,7 +242,7 @@ 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
+ * @return bool|null true on success, false on failure, null if no annotations disabled.
  * @since 1.8.0
  */
 function elgg_disable_annotations(array $options) {
@@ -259,8 +259,11 @@ 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
+ * @return bool|null true on success, false on failure, null if no metadata enabled.
  * @since 1.8.0
  */
 function elgg_enable_annotations(array $options) {
@@ -532,15 +535,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;
 	}
 
diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index cb972b282..15ab1170e 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -1619,8 +1619,8 @@ 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 bool $recursive Recursively enable all entities disabled with the entity?
@@ -1748,6 +1748,10 @@ function delete_entity($guid, $recursive = true) {
 					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();
@@ -1755,6 +1759,9 @@ function delete_entity($guid, $recursive = true) {
 				$entity->deleteOwnedAnnotations();
 				$entity->deleteRelationships();
 
+				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);
diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php
index ad926a49a..43f7d5d6e 100644
--- a/engine/lib/metadata.php
+++ b/engine/lib/metadata.php
@@ -300,10 +300,8 @@ function elgg_get_metadata(array $options = array()) {
  *          This requires at least one constraint: metadata_owner_guid(s),
  *          metadata_name(s), metadata_value(s), or guid(s) must be set.
  *
- * @warning This returns null on no ops.
- *
  * @param array $options An options array. {@see elgg_get_metadata()}
- * @return mixed Null if the metadata name is invalid. Bool on success or fail.
+ * @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) {
@@ -325,10 +323,8 @@ function elgg_delete_metadata(array $options) {
  *
  * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
  *
- * @warning This returns null on no ops.
- *
  * @param array $options An options array. {@See elgg_get_metadata()}
- * @return mixed
+ * @return bool|null true on success, false on failure, null if no metadata disabled.
  * @since 1.8.0
  */
 function elgg_disable_metadata(array $options) {
@@ -347,10 +343,11 @@ function elgg_disable_metadata(array $options) {
  *
  * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
  *
- * @warning This returns null on no ops.
+ * @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
+ * @return bool|null true on success, false on failure, null if no metadata enabled.
  * @since 1.8.0
  */
 function elgg_enable_metadata(array $options) {
diff --git a/engine/tests/api/annotations.php b/engine/tests/api/annotations.php
index 947292970..c0b0687cc 100644
--- a/engine/tests/api/annotations.php
+++ b/engine/tests/api/annotations.php
@@ -65,6 +65,86 @@ class ElggCoreAnnotationAPITest extends ElggCoreUnitTest {
 		$annotations = elgg_get_annotations($options);
 		$this->assertTrue(empty($annotations));
 
+		// nothing to delete so null returned
+		$this->assertNull(elgg_delete_annotations($options));
+
+		$this->assertTrue($e->delete());
+	}
+
+	public function testElggDisableAnnotations() {
+		$e = new ElggObject();
+		$e->save();
+
+		for ($i=0; $i<30; $i++) {
+			$e->annotate('test_annotation', rand(0,10000));
+		}
+
+		$options = array(
+			'guid' => $e->getGUID(),
+			'limit' => 0
+		);
+
+		$this->assertTrue(elgg_disable_annotations($options));
+
+		$annotations = elgg_get_annotations($options);
+		$this->assertTrue(empty($annotations));
+
+		access_show_hidden_entities(true);
+		$annotations = elgg_get_annotations($options);
+		$this->assertIdentical(30, count($annotations));
+		access_show_hidden_entities(false);
+
+		$this->assertTrue($e->delete());
+	}
+
+	public function testElggEnableAnnotations() {
+		$e = new ElggObject();
+		$e->save();
+
+		for ($i=0; $i<30; $i++) {
+			$e->annotate('test_annotation', rand(0,10000));
+		}
+
+		$options = array(
+			'guid' => $e->getGUID(),
+			'limit' => 0
+		);
+
+		$this->assertTrue(elgg_disable_annotations($options));
+
+		// cannot see any annotations so returns null
+		$this->assertNull(elgg_enable_annotations($options));
+
+		access_show_hidden_entities(true);
+		$this->assertTrue(elgg_enable_annotations($options));
+		access_show_hidden_entities(false);
+
+		$annotations = elgg_get_annotations($options);
+		$this->assertIdentical(30, count($annotations));
+
+		$this->assertTrue($e->delete());
+	}
+
+	public function testElggAnnotationExists() {
+		$e = new ElggObject();
+		$e->save();
+		$guid = $e->getGUID();
+
+		$this->assertFalse(elgg_annotation_exists($guid, 'test_annotation'));
+
+		$e->annotate('test_annotation', rand(0, 10000));
+		$this->assertTrue(elgg_annotation_exists($guid, 'test_annotation'));
+		// this metastring should always exist but an annotation of this name should not
+		$this->assertFalse(elgg_annotation_exists($guid, 'email'));
+
+		$options = array(
+			'guid' => $guid,
+			'limit' => 0
+		);
+		$this->assertTrue(elgg_disable_annotations($options));
+		$this->assertTrue(elgg_annotation_exists($guid, 'test_annotation'));
+
 		$this->assertTrue($e->delete());
+		$this->assertFalse(elgg_annotation_exists($guid, 'test_annotation'));
 	}
 }
-- 
cgit v1.2.3


From 6fed48c68bd866149427c63782d5ce4db6ba80c4 Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Mon, 13 May 2013 22:39:42 -0400
Subject: Add test for = lookbehind

---
 engine/tests/regression/trac_bugs.php | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php
index b7654a794..7fdd51c27 100644
--- a/engine/tests/regression/trac_bugs.php
+++ b/engine/tests/regression/trac_bugs.php
@@ -287,8 +287,10 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest {
 				'web archive anchor google',
 
 			'single quotes already anchor yahoo' => 
-				'single quotes already anchor yahoo'
+				'single quotes already anchor yahoo',
 
+			'unquoted already anchor yahoo' =>
+				'unquoted already anchor yahoo',
 		);
 		foreach ($cases as $input => $output) {
 			$this->assertEqual($output, parse_urls($input));
-- 
cgit v1.2.3


From 4c45640a3327aea985b383dcbecc5a439674f97c Mon Sep 17 00:00:00 2001
From: cash 
Date: Fri, 17 May 2013 15:44:22 -0400
Subject: Fixes #5479 adds group full text index if missing

---
 ...15-add_missing_group_index-52a63a3a3ffaced2.php | 28 ++++++++++++++++++++++
 version.php                                        |  2 +-
 2 files changed, 29 insertions(+), 1 deletion(-)
 create mode 100644 engine/lib/upgrades/2013051700-1.8.15-add_missing_group_index-52a63a3a3ffaced2.php

(limited to 'engine')

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 @@
+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/version.php b/version.php
index c5fc817d4..ac554a945 100644
--- a/version.php
+++ b/version.php
@@ -11,7 +11,7 @@
 
 // YYYYMMDD = Elgg Date
 // XX = Interim incrementer
-$version = 2013030600;
+$version = 2013051700;
 
 // Human-friendly version name
 $release = '1.8.15';
-- 
cgit v1.2.3


From 2980014665c708d15c377b616d9fc3ca97386950 Mon Sep 17 00:00:00 2001
From: cash 
Date: Fri, 17 May 2013 16:34:50 -0400
Subject: Refs #5491 temporary fix for bad can_edit_extender() logic

---
 engine/lib/extender.php | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/extender.php b/engine/lib/extender.php
index 8756e051b..8323bd3ce 100644
--- a/engine/lib/extender.php
+++ b/engine/lib/extender.php
@@ -126,14 +126,20 @@ function import_extender_plugin_hook($hook, $entity_type, $returnvalue, $params)
  * @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 = "elgg_get_{$type}_from_id";
@@ -149,16 +155,16 @@ function can_edit_extender($extender_id, $type, $user_guid = 0) {
 	/* @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
+	// 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);
 }
-- 
cgit v1.2.3


From f49e7f3fbdf3173b4dc548eab568c5fae1b773d3 Mon Sep 17 00:00:00 2001
From: Brett Profitt 
Date: Thu, 23 May 2013 12:35:06 -0400
Subject: Fixes #5522. Only adding children elements to menu items if they
 haven't already been added.

---
 engine/classes/ElggMenuBuilder.php | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggMenuBuilder.php b/engine/classes/ElggMenuBuilder.php
index 198018f3c..26b0de734 100644
--- a/engine/classes/ElggMenuBuilder.php
+++ b/engine/classes/ElggMenuBuilder.php
@@ -128,8 +128,11 @@ class ElggMenuBuilder {
 					$parent_name = $menu_item->getParentName();
 					if (array_key_exists($parent_name, $current_gen)) {
 						$next_gen[$menu_item->getName()] = $menu_item;
-						$current_gen[$parent_name]->addChild($menu_item);
-						$menu_item->setParent($current_gen[$parent_name]);
+						$data = $current_gen[$parent_name]->getData();
+						if (!in_array($menu_item, $current_gen[$parent_name]->getData('children'))) {
+							$current_gen[$parent_name]->addChild($menu_item);
+							$menu_item->setParent($current_gen[$parent_name]);
+						}
 						unset($children[$index]);
 					}
 				}
-- 
cgit v1.2.3


From 59df7550f6e1f1dce4f3161682d9fb3000123d40 Mon Sep 17 00:00:00 2001
From: Brett Profitt 
Date: Thu, 23 May 2013 12:36:12 -0400
Subject: Refs #5522. Removed unused code.

---
 engine/classes/ElggMenuBuilder.php | 1 -
 1 file changed, 1 deletion(-)

(limited to 'engine')

diff --git a/engine/classes/ElggMenuBuilder.php b/engine/classes/ElggMenuBuilder.php
index 26b0de734..276cb6b2c 100644
--- a/engine/classes/ElggMenuBuilder.php
+++ b/engine/classes/ElggMenuBuilder.php
@@ -128,7 +128,6 @@ class ElggMenuBuilder {
 					$parent_name = $menu_item->getParentName();
 					if (array_key_exists($parent_name, $current_gen)) {
 						$next_gen[$menu_item->getName()] = $menu_item;
-						$data = $current_gen[$parent_name]->getData();
 						if (!in_array($menu_item, $current_gen[$parent_name]->getData('children'))) {
 							$current_gen[$parent_name]->addChild($menu_item);
 							$menu_item->setParent($current_gen[$parent_name]);
-- 
cgit v1.2.3


From c7572e614606396617cb1611653f6a759be0a058 Mon Sep 17 00:00:00 2001
From: Paweł Sroka 
Date: Mon, 27 May 2013 05:17:08 +0200
Subject: Refs #5538 - Added regression test

---
 engine/tests/regression/trac_bugs.php | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

(limited to 'engine')

diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php
index 7fdd51c27..180fb5112 100644
--- a/engine/tests/regression/trac_bugs.php
+++ b/engine/tests/regression/trac_bugs.php
@@ -296,4 +296,34 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest {
 			$this->assertEqual($output, parse_urls($input));
 		}
 	}
+	
+	/**
+	 * Checks if additional select columns does not leak to entity attributes.
+	 * 
+	 * https://github.com/Elgg/Elgg/issues/5538
+	 */
+	public function test_sql_selects_leak_to_attributes() {
+		global $ENTITY_CACHE;
+		//may not have groups in DB - let's create one	
+		$group = new ElggGroup();
+		$group->name = 'test_group';
+		$group->access_id = ACCESS_PUBLIC;
+		$this->assertTrue($group->save() !== false);
+		
+		//entity cache interferes with our test
+		$ENTITY_CACHE = array();
+		
+		foreach (array('site', 'user', 'group', 'object') as $type) {
+			$entities = elgg_get_entities(array(
+				'type' => $type,
+				'selects' => array('42 as added_col'),
+				'limit' => 1,
+			));
+			$entity = array_shift($entities);
+			$this->assertTrue($entity instanceof ElggEntity);
+			$this->assertEqual($entity->added_col, null, "Additional select columns are leaking to attributes for " . get_class($entity));
+		}
+		
+		$group->delete();
+	}
 }
-- 
cgit v1.2.3


From e630f8ceb980ab40fbab57145eae68f592034266 Mon Sep 17 00:00:00 2001
From: cash 
Date: Tue, 28 May 2013 18:17:36 -0400
Subject: Fixes #5337 properly checking if admin notice exists

---
 engine/lib/admin.php | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/admin.php b/engine/lib/admin.php
index 243cdef46..7f82108c0 100644
--- a/engine/lib/admin.php
+++ b/engine/lib/admin.php
@@ -134,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) {
@@ -158,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;
 }
-- 
cgit v1.2.3


From 371e64beb9d47e0b64ce74d83a8587a73908f7d5 Mon Sep 17 00:00:00 2001
From: cash 
Date: Tue, 28 May 2013 18:33:55 -0400
Subject: Fixes #5531 removes symbol interpretation from translit class

---
 engine/classes/ElggTranslit.php       | 4 ----
 engine/tests/regression/trac_bugs.php | 6 +++---
 2 files changed, 3 insertions(+), 7 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggTranslit.php b/engine/classes/ElggTranslit.php
index 4ae1d2479..b4bf87797 100644
--- a/engine/classes/ElggTranslit.php
+++ b/engine/classes/ElggTranslit.php
@@ -58,10 +58,6 @@ class ElggTranslit {
 			// currency
 			"\xE2\x82\xAC" /* € */ => ' E ',
 			"\xC2\xA3" /* £ */ => ' GBP ',
-			
-			"&" => ' and ',
-			">" => ' greater than ',
-			"<" => ' less than ',
 		));
 
 		// remove all ASCII except 0-9a-zA-Z, hyphen, underscore, and whitespace
diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php
index 7fdd51c27..051aa8d1b 100644
--- a/engine/tests/regression/trac_bugs.php
+++ b/engine/tests/regression/trac_bugs.php
@@ -208,12 +208,12 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest {
 		$cases = array(
 			// acid test
 			"B&N > Amazon, OK?  'hey!' $34"
-			=> "b-and-n-greater-than-amazon-ok-bold-hey-34",
+			=> "bn-amazon-ok-bold-hey-34",
 
 			// hyphen, underscore and ASCII whitespace replaced by separator,
 			// other non-alphanumeric ASCII removed
-			"a-a_a a\na\ra\ta\va!a\"a#a\$a%a&a'a(a)a*a+a,a.a/a:a;a=a?a@a[a\\a]a^a`a{a|a}a~a"
-			=> "a-a-a-a-a-a-aaaaaaa-and-aaaaaaaaaaaaaaaaaaaaaaa",
+			"a-a_a a\na\ra\ta\va!a\"a#a\$a%aa'a(a)a*a+a,a.a/a:a;a=a?a@a[a\\a]a^a`a{a|a}a~a"
+			=> "a-a-a-a-a-a-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
 			
 			// separators trimmed
 			"-_ hello _-" 
-- 
cgit v1.2.3


From 07d533b21c2433c43fe8b36504d38debcfdb3920 Mon Sep 17 00:00:00 2001
From: Cash Costello 
Date: Wed, 29 May 2013 07:52:19 -0400
Subject: Fixes #5551 removes corrupt entities from database

---
 engine/lib/entities.php | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index 15ab1170e..7b4e0e15a 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -2470,11 +2470,18 @@ function update_entity_last_action($guid, $posted = NULL) {
 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})");
 	}
 }
 
-- 
cgit v1.2.3


From 3247464f3be9ee7e731adaaec9d53c9d3088b8fa Mon Sep 17 00:00:00 2001
From: Jerome Bakker 
Date: Wed, 29 May 2013 16:16:49 +0200
Subject: changed: the system_log table can now store ipv6 addresses

---
 .../2013052900-1.8.15-ipv6_in_syslog-f5c2cc0196e9e731.php    | 12 ++++++++++++
 engine/schema/mysql.sql                                      |  2 +-
 version.php                                                  |  2 +-
 3 files changed, 14 insertions(+), 2 deletions(-)
 create mode 100644 engine/lib/upgrades/2013052900-1.8.15-ipv6_in_syslog-f5c2cc0196e9e731.php

(limited to 'engine')

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 @@
+
Date: Wed, 29 May 2013 16:45:03 +0200
Subject: fixed: pagination in online members overview

---
 engine/lib/statistics.php | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/statistics.php b/engine/lib/statistics.php
index 0c9a3c945..4cb0bb0b8 100644
--- a/engine/lib/statistics.php
+++ b/engine/lib/statistics.php
@@ -95,13 +95,17 @@ function get_number_users($show_deactivated = false) {
  * @return string
   */
 function get_online_users() {
-	$count = find_active_users(600, 10, 0, true);
-	$objects = find_active_users(600, 10);
+	$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, array(
 			'count' => $count,
-			'limit' => 10,
+			'limit' => $limit,
+			'offset' => $offset
 		));
 	}
 	return '';
-- 
cgit v1.2.3


From e984b7ed8d148bdda11381f9814434f7bb45b341 Mon Sep 17 00:00:00 2001
From: Jerome Bakker 
Date: Thu, 30 May 2013 11:25:40 +0200
Subject: fixed: only returning groups in get_user_membership (as documented)

---
 engine/lib/group.php | 1 +
 1 file changed, 1 insertion(+)

(limited to 'engine')

diff --git a/engine/lib/group.php b/engine/lib/group.php
index 359bc59c2..6ded8a825 100644
--- a/engine/lib/group.php
+++ b/engine/lib/group.php
@@ -240,6 +240,7 @@ 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,
-- 
cgit v1.2.3


From d90ddd2f9be750d3bf827679f49943166b486ad4 Mon Sep 17 00:00:00 2001
From: Jerome Bakker 
Date: Thu, 30 May 2013 16:48:33 +0200
Subject: ElggFile->delete() will return a correct state even for non saved
 entities

---
 engine/classes/ElggFile.php | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggFile.php b/engine/classes/ElggFile.php
index 3e9c24c17..23080834b 100644
--- a/engine/classes/ElggFile.php
+++ b/engine/classes/ElggFile.php
@@ -275,9 +275,14 @@ class ElggFile extends ElggObject {
 	 */
 	public function delete() {
 		$fs = $this->getFilestore();
-		if ($fs->delete($this)) {
-			return parent::delete();
+		
+		$result = $fs->delete($this);
+		
+		if ($this->getGUID() && $result) {
+			$result = parent::delete();
 		}
+		
+		return $result;
 	}
 
 	/**
-- 
cgit v1.2.3


From 4f783d420e2a74816265cb657f0c4961c8f2117f Mon Sep 17 00:00:00 2001
From: cash 
Date: Thu, 30 May 2013 19:19:25 -0400
Subject: Refs #5565 adds documentation on ACCESS_DEFAULT

---
 engine/lib/elgglib.php | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'engine')

diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php
index fb652a141..b5ef7e572 100644
--- a/engine/lib/elgglib.php
+++ b/engine/lib/elgglib.php
@@ -2247,6 +2247,9 @@ function elgg_api_test($hook, $type, $value, $params) {
 /**#@+
  * 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
  */
 define('ACCESS_DEFAULT', -1);
-- 
cgit v1.2.3


From a9709da4bd45ea04944d93e0d472aa4ee801e0f5 Mon Sep 17 00:00:00 2001
From: cash 
Date: Thu, 30 May 2013 19:31:45 -0400
Subject: Fixes #5567 throw exception when saving with ACCESS_DEFAULT

---
 engine/lib/entities.php | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index 7b4e0e15a..5cfeca6f8 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -407,7 +407,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) {
@@ -430,6 +430,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
@@ -556,7 +560,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;
@@ -565,6 +568,10 @@ $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_guid = elgg_get_logged_in_user_guid();
 	if (!can_write_to_container($user_guid, $owner_guid, $type, $subtype)) {
-- 
cgit v1.2.3


From bbf99434e13ebf304fb15a8c5b9d70c621f38c86 Mon Sep 17 00:00:00 2001
From: cash 
Date: Thu, 30 May 2013 21:04:09 -0400
Subject: Fixes #5564 count works with
 elgg_get_entities_from_annotation_calculation()

---
 engine/lib/annotations.php                   | 10 ++++++++--
 engine/lib/metastrings.php                   |  7 +++++--
 engine/tests/api/entity_getter_functions.php |  2 +-
 3 files changed, 14 insertions(+), 5 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php
index 81755f169..124e67e0f 100644
--- a/engine/lib/annotations.php
+++ b/engine/lib/annotations.php
@@ -419,8 +419,8 @@ function elgg_list_entities_from_annotations($options = array()) {
 function elgg_get_entities_from_annotation_calculation($options) {
 	$db_prefix = elgg_get_config('dbprefix');
 	$defaults = array(
-		'calculation'	=>	'sum',
-		'order_by'		=>	'annotation_calculation desc'
+		'calculation' => 'sum',
+		'order_by' => 'annotation_calculation desc'
 	);
 
 	$options = array_merge($defaults, $options);
@@ -457,6 +457,12 @@ 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');
 }
 
diff --git a/engine/lib/metastrings.php b/engine/lib/metastrings.php
index 39a81c6d0..57d876c06 100644
--- a/engine/lib/metastrings.php
+++ b/engine/lib/metastrings.php
@@ -425,7 +425,7 @@ function elgg_get_metastring_based_objects($options) {
 		$wheres[] = get_access_sql_suffix('n_table');
 	}
 
-	if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE) {
+	if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) {
 		$selects = array_unique($selects);
 		// evalutate selects
 		$select_str = '';
@@ -436,6 +436,9 @@ function elgg_get_metastring_based_objects($options) {
 		}
 
 		$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";
 	}
@@ -464,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']}";
diff --git a/engine/tests/api/entity_getter_functions.php b/engine/tests/api/entity_getter_functions.php
index 7bf8ef04a..0492b1fb0 100644
--- a/engine/tests/api/entity_getter_functions.php
+++ b/engine/tests/api/entity_getter_functions.php
@@ -2755,7 +2755,7 @@ class ElggCoreEntityGetterFunctionsTest extends ElggCoreUnitTest {
 			'calculation' => 'count',
 			'count' => true,
 		);
-		$count = (int)elgg_get_entities_from_annotation_calculation($options);
+		$count = elgg_get_entities_from_annotation_calculation($options);
 		$this->assertEqual(1, $count);
 	}
 
-- 
cgit v1.2.3


From 8d1e8f8c4cbb3e269d36c9867884eef2490dfc60 Mon Sep 17 00:00:00 2001
From: Cash Costello 
Date: Fri, 31 May 2013 17:39:15 -0400
Subject: Fixes #4912 custom site menu items are now matched

---
 engine/lib/navigation.php | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php
index 118a7214c..2831d418b 100644
--- a/engine/lib/navigation.php
+++ b/engine/lib/navigation.php
@@ -323,7 +323,8 @@ function elgg_site_menu_setup($hook, $type, $return, $params) {
 	}
 	
 	if (!$selected) {
-		// nothing selected, match name to context
+		// 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
@@ -332,6 +333,10 @@ function elgg_site_menu_setup($hook, $type, $return, $params) {
 						$return[$section_name][$key]->setSelected(true);
 						break 2;
 					}
+					if ($item->getHref() == $current_url) {
+						$return[$section_name][$key]->setSelected(true);
+						break 2;
+					}
 				}
 			}
 		}
-- 
cgit v1.2.3


From 2e979f75cd625c42ac5251140a3e7a797108f669 Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Sat, 1 Jun 2013 21:51:32 -0400
Subject: Add filtering for site entities, faster filtering

---
 engine/classes/ElggAttributeLoader.php | 30 ++++++++++++++++++++++++++++-
 engine/tests/regression/trac_bugs.php  | 35 ++++++++++++++++++----------------
 2 files changed, 48 insertions(+), 17 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggAttributeLoader.php b/engine/classes/ElggAttributeLoader.php
index b91e4b88a..0b770da75 100644
--- a/engine/classes/ElggAttributeLoader.php
+++ b/engine/classes/ElggAttributeLoader.php
@@ -24,7 +24,7 @@ class ElggAttributeLoader {
 		'time_created',
 		'time_updated',
 		'last_action',
-		'enabled'
+		'enabled',
 	);
 
 	/**
@@ -200,6 +200,8 @@ class ElggAttributeLoader {
 						// saved, these are stored w/ type "site", but with no sites_entity row. These
 						// are probably only created in the unit tests.
 						// @todo Don't save vanilla ElggEntities with type "site"
+
+						$row = $this->filterAddedColumns($row);
 						$row['guid'] = (int) $row['guid'];
 						return $row;
 					}
@@ -209,6 +211,8 @@ class ElggAttributeLoader {
 			}
 		}
 
+		$row = $this->filterAddedColumns($row);
+
 		// Note: If there are still missing attributes, we're running on a 1.7 or earlier schema. We let
 		// this pass so the upgrades can run.
 
@@ -217,4 +221,28 @@ class ElggAttributeLoader {
 
 		return $row;
 	}
+
+	/**
+	 * Filter out keys returned by the query which should not appear in the entity's attributes
+	 *
+	 * @param array $row All columns from the query
+	 * @return array Columns acceptable for the entity's attributes
+	 */
+	protected function filterAddedColumns($row) {
+		// make an array with keys as acceptable attribute names
+		$acceptable_attrs = self::$primary_attr_names;
+		array_splice($acceptable_attrs, count($acceptable_attrs), 0, $this->secondary_attr_names);
+		$acceptable_attrs = array_combine($acceptable_attrs, $acceptable_attrs);
+
+		// @todo remove these when #4584 is in place
+		$acceptable_attrs['tables_split'] = true;
+		$acceptable_attrs['tables_loaded'] = true;
+
+		foreach ($row as $key => $val) {
+			if (!isset($acceptable_attrs[$key])) {
+				unset($row[$key]);
+			}
+		}
+		return $row;
+	}
 }
diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php
index 180fb5112..d7bb20f3b 100644
--- a/engine/tests/regression/trac_bugs.php
+++ b/engine/tests/regression/trac_bugs.php
@@ -297,31 +297,34 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest {
 		}
 	}
 	
-	/**
-	 * Checks if additional select columns does not leak to entity attributes.
-	 * 
-	 * https://github.com/Elgg/Elgg/issues/5538
-	 */
-	public function test_sql_selects_leak_to_attributes() {
+	/**
+	 * Ensure additional select columns do not end up in entity attributes.
+	 * 
+	 * https://github.com/Elgg/Elgg/issues/5538
+	 */
+	public function test_extra_columns_dont_appear_in_attributes() {
 		global $ENTITY_CACHE;
-		//may not have groups in DB - let's create one	
+
+		// may not have groups in DB - let's create one
 		$group = new ElggGroup();
 		$group->name = 'test_group';
-		$group->access_id = ACCESS_PUBLIC;
-		$this->assertTrue($group->save() !== false);
+		$group->access_id = ACCESS_PUBLIC;
+		$this->assertTrue($group->save() !== false);
 		
-		//entity cache interferes with our test
+		// entity cache interferes with our test
 		$ENTITY_CACHE = array();
 		
 		foreach (array('site', 'user', 'group', 'object') as $type) {
 			$entities = elgg_get_entities(array(
-				'type' => $type,
-				'selects' => array('42 as added_col'),
-				'limit' => 1,
+				'type' => $type,
+				'selects' => array('1 as _nonexistent_test_column'),
+				'limit' => 1,
 			));
-			$entity = array_shift($entities);
-			$this->assertTrue($entity instanceof ElggEntity);
-			$this->assertEqual($entity->added_col, null, "Additional select columns are leaking to attributes for " . get_class($entity));
+			if (!$this->assertTrue($entities, "Query for '$type' did not return an entity.")) {
+				continue;
+			}
+			$entity = $entities[0];
+			$this->assertNull($entity->_nonexistent_test_column, "Additional select columns are leaking to attributes for '$type'");
 		}
 		
 		$group->delete();
-- 
cgit v1.2.3


From 50dee6fe09a1f600089b1684f6f8f91599c365a1 Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Sat, 1 Jun 2013 22:13:08 -0400
Subject: Refs #5538: Adds missing attributes to ElggUser and ElggCoreUserTest
 (by Paweł Sroka)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 engine/classes/ElggUser.php    | 3 +++
 engine/tests/objects/users.php | 3 +++
 2 files changed, 6 insertions(+)

(limited to 'engine')

diff --git a/engine/classes/ElggUser.php b/engine/classes/ElggUser.php
index 6d9f10b57..b2cada8ef 100644
--- a/engine/classes/ElggUser.php
+++ b/engine/classes/ElggUser.php
@@ -40,6 +40,9 @@ class ElggUser extends ElggEntity
 		$this->attributes['code'] = NULL;
 		$this->attributes['banned'] = "no";
 		$this->attributes['admin'] = 'no';
+		$this->attributes['prev_last_action'] = NULL;
+		$this->attributes['last_login'] = NULL;
+		$this->attributes['prev_last_login'] = NULL;
 		$this->attributes['tables_split'] = 2;
 	}
 
diff --git a/engine/tests/objects/users.php b/engine/tests/objects/users.php
index a3573acb6..dc9129326 100644
--- a/engine/tests/objects/users.php
+++ b/engine/tests/objects/users.php
@@ -65,6 +65,9 @@ class ElggCoreUserTest extends ElggCoreUnitTest {
 		$attributes['code'] = NULL;
 		$attributes['banned'] = 'no';
 		$attributes['admin'] = 'no';
+		$attributes['prev_last_action'] = NULL;
+		$attributes['last_login'] = NULL;
+		$attributes['prev_last_login'] = NULL;
 		ksort($attributes);
 
 		$entity_attributes = $this->user->expose_attributes();
-- 
cgit v1.2.3


From b5860b972c67be3b398d64e622bfd367b2a9825c Mon Sep 17 00:00:00 2001
From: cash 
Date: Sun, 2 Jun 2013 19:40:22 -0400
Subject: fixed a notice when accessing $CONFIG->icon_sizes

---
 engine/lib/views.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/lib/views.php b/engine/lib/views.php
index c4b349fc6..65ba20204 100644
--- a/engine/lib/views.php
+++ b/engine/lib/views.php
@@ -1638,7 +1638,7 @@ function elgg_views_boot() {
 	}
 
 	// set default icon sizes - can be overridden in settings.php or with plugin
-	if (!$CONFIG->icon_sizes) {
+	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),
-- 
cgit v1.2.3


From 35acc4a297de7660a191d4e7f9d3e8d55561885a Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Mon, 3 Jun 2013 17:02:33 -0400
Subject: Refs #5357: Introduces ElggBatch awareness of incomplete entities
 during fetch

---
 engine/classes/ElggBatch.php | 30 +++++++++++++++++++++------
 engine/lib/entities.php      | 14 ++++++++++---
 engine/tests/api/helpers.php | 48 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 83 insertions(+), 9 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggBatch.php b/engine/classes/ElggBatch.php
index eb93b0f5d..34520f2bc 100644
--- a/engine/classes/ElggBatch.php
+++ b/engine/classes/ElggBatch.php
@@ -149,6 +149,13 @@ class ElggBatch
 	 */
 	private $incrementOffset = true;
 
+	/**
+	 * Entities that could not be instantiated during a fetch
+	 *
+	 * @var stdClass[]
+	 */
+	private $incompleteEntities = array();
+
 	/**
 	 * Batches operations on any elgg_get_*() or compatible function that supports
 	 * an options array.
@@ -221,6 +228,17 @@ class ElggBatch
 		}
 	}
 
+	/**
+	 * Tell the process that an entity was incomplete during a fetch
+	 *
+	 * @param stdClass $row
+	 *
+	 * @access private
+	 */
+	public function reportIncompleteEntity(stdClass $row) {
+		$this->incompleteEntities[] = $row;
+	}
+
 	/**
 	 * Fetches the next chunk of results
 	 *
@@ -265,16 +283,16 @@ class ElggBatch
 
 		$current_options = array(
 			'limit' => $limit,
-			'offset' => $offset
+			'offset' => $offset,
+			'__ElggBatch' => $this,
 		);
 
 		$options = array_merge($this->options, $current_options);
-		$getter = $this->getter;
 
-		if (is_string($getter)) {
-			$this->results = $getter($options);
-		} else {
-			$this->results = call_user_func_array($getter, array($options));
+		$this->incompleteEntities = array();
+		$this->results = call_user_func_array($this->getter, array($options));
+		if ($this->incompleteEntities) {
+			// @todo what to do here?
 		}
 
 		if ($this->results) {
diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index 5cfeca6f8..b7f8c1466 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -891,6 +891,8 @@ function elgg_get_entities(array $options = array()) {
 		'joins'					=>	array(),
 
 		'callback'				=> 'entity_row_to_elggstar',
+
+		'__ElggBatch'			=> null,
 	);
 
 	$options = array_merge($defaults, $options);
@@ -1008,7 +1010,7 @@ function elgg_get_entities(array $options = array()) {
 		}
 
 		if ($options['callback'] === 'entity_row_to_elggstar') {
-			$dt = _elgg_fetch_entities_from_sql($query);
+			$dt = _elgg_fetch_entities_from_sql($query, $options['__ElggBatch']);
 		} else {
 			$dt = get_data($query, $options['callback']);
 		}
@@ -1043,13 +1045,14 @@ function elgg_get_entities(array $options = array()) {
 /**
  * Return entities from an SQL query generated by elgg_get_entities.
  *
- * @param string $sql
+ * @param string    $sql
+ * @param ElggBatch $batch
  * @return ElggEntity[]
  *
  * @access private
  * @throws LogicException
  */
-function _elgg_fetch_entities_from_sql($sql) {
+function _elgg_fetch_entities_from_sql($sql, ElggBatch $batch = null) {
 	static $plugin_subtype;
 	if (null === $plugin_subtype) {
 		$plugin_subtype = get_subtype_id('object', 'plugin');
@@ -1126,6 +1129,11 @@ function _elgg_fetch_entities_from_sql($sql) {
 			} 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);
+				}
 			}
 		}
 	}
diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php
index 62e4471e0..753d02915 100644
--- a/engine/tests/api/helpers.php
+++ b/engine/tests/api/helpers.php
@@ -578,6 +578,54 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
 		$this->assertEqual(11, $j);
 	}
 
+	public function testElggBatchHandlesBrokenEntities() {
+		$num_test_entities = 4;
+		$guids = array();
+		$now = time();
+		for ($i = $num_test_entities; $i > 0; $i--) {
+			$entity = new ElggObject();
+			$entity->type = 'object';
+			$entity->subtype = 'test_5357_subtype';
+			$entity->access_id = ACCESS_PUBLIC;
+			$entity->time_created = ($now - $i);
+			$entity->save();
+			$guids[] = $entity->guid;
+			_elgg_invalidate_cache_for_entity($entity->guid);
+		}
+
+		// break the second entity
+		$db_prefix = elgg_get_config('dbprefix');
+		delete_data("DELETE FROM {$db_prefix}objects_entity WHERE guid = {$guids[1]}");
+
+		$options = array(
+			'type' => 'object',
+			'subtype' => 'test_5357_subtype',
+			'order' => 'e.time_created ASC',
+		);
+
+		$entities_visited = array();
+
+		$batch = new ElggBatch('elgg_get_entities', $options, null, 2);
+		foreach ($batch as $entity) {
+			$entities_visited[$entity->guid] = true;
+		}
+
+		// All but the broken entity should have been visited
+		$this->assertEqual(count($entities_visited), $num_test_entities - 1);
+
+		// cleanup (including leftovers from previous tests)
+		$entity_rows = elgg_get_entities(array_merge($options, array(
+			'callback' => '',
+			'limit' => false,
+		)));
+		$guids = array();
+		foreach ($entity_rows as $row) {
+			$guids[] = $row->guid;
+		}
+		delete_data("DELETE FROM {$db_prefix}entities WHERE guid IN (" . implode(',', $guids) . ")");
+		delete_data("DELETE FROM {$db_prefix}objects_entity WHERE guid IN (" . implode(',', $guids) . ")");
+	}
+
 	static function elgg_batch_callback_test($options, $reset = false) {
 		static $count = 1;
 
-- 
cgit v1.2.3


From 708d2fcdc07986ee8bce5838f03f1375e8cd6d5e Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Tue, 4 Jun 2013 22:50:58 -0400
Subject: Fixes #5357: ElggBatch can now skip incomplete entities

---
 engine/classes/ElggBatch.php | 17 +++++++++++------
 engine/tests/api/helpers.php | 19 +++++++++++--------
 2 files changed, 22 insertions(+), 14 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggBatch.php b/engine/classes/ElggBatch.php
index 34520f2bc..83963ccee 100644
--- a/engine/classes/ElggBatch.php
+++ b/engine/classes/ElggBatch.php
@@ -291,14 +291,19 @@ class ElggBatch
 
 		$this->incompleteEntities = array();
 		$this->results = call_user_func_array($this->getter, array($options));
-		if ($this->incompleteEntities) {
-			// @todo what to do here?
-		}
 
-		if ($this->results) {
+		// If there were incomplete entities, we pretend they were at the beginning of the results,
+		// fool the local counter to think it's skipped by them already, and update the running
+		// total as if the results contained the incompletes.
+		if ($this->results || $this->incompleteEntities) {
 			$this->chunkIndex++;
-			$this->resultIndex = 0;
-			$this->retrievedResults += count($this->results);
+			$this->resultIndex = count($this->incompleteEntities);
+			$this->retrievedResults += (count($this->results) + count($this->incompleteEntities));
+			if (!$this->results) {
+				// This fetch was *all* incompletes! We need to fetch until we can either
+				// offer at least one row to iterate over, or give up.
+				return $this->getNextResultsChunk();
+			}
 			return true;
 		} else {
 			return false;
diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php
index 753d02915..43244636b 100644
--- a/engine/tests/api/helpers.php
+++ b/engine/tests/api/helpers.php
@@ -579,7 +579,7 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
 	}
 
 	public function testElggBatchHandlesBrokenEntities() {
-		$num_test_entities = 4;
+		$num_test_entities = 6;
 		$guids = array();
 		$now = time();
 		for ($i = $num_test_entities; $i > 0; $i--) {
@@ -593,25 +593,28 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
 			_elgg_invalidate_cache_for_entity($entity->guid);
 		}
 
-		// break the second entity
+		// break entities such that the first fetch has one incomplete
+		// and the second fetch has only incompletes!
 		$db_prefix = elgg_get_config('dbprefix');
-		delete_data("DELETE FROM {$db_prefix}objects_entity WHERE guid = {$guids[1]}");
+		delete_data("
+			DELETE FROM {$db_prefix}objects_entity
+			WHERE guid IN ({$guids[1]}, {$guids[2]}, {$guids[3]})
+		");
 
 		$options = array(
 			'type' => 'object',
 			'subtype' => 'test_5357_subtype',
-			'order' => 'e.time_created ASC',
+			'order_by' => 'e.time_created ASC',
 		);
 
 		$entities_visited = array();
-
 		$batch = new ElggBatch('elgg_get_entities', $options, null, 2);
 		foreach ($batch as $entity) {
-			$entities_visited[$entity->guid] = true;
+			$entities_visited[] = $entity->guid;
 		}
 
-		// All but the broken entity should have been visited
-		$this->assertEqual(count($entities_visited), $num_test_entities - 1);
+		// The broken entities should not have been visited
+		$this->assertEqual($entities_visited, array($guids[0], $guids[4], $guids[5]));
 
 		// cleanup (including leftovers from previous tests)
 		$entity_rows = elgg_get_entities(array_merge($options, array(
-- 
cgit v1.2.3


From d3703130652337583daec95e322f6f7d497a581d Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Fri, 7 Jun 2013 09:43:12 -0400
Subject: Add way to ban entities from the entity cache

---
 engine/lib/entities.php | 46 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index 5cfeca6f8..ac4b4d995 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -16,6 +16,15 @@
 global $ENTITY_CACHE;
 $ENTITY_CACHE = array();
 
+/**
+ * GUIDs of entities banned from the entity cache (during this request)
+ *
+ * @global array $ENTITY_CACHE_BANNED_GUIDS
+ * @access private
+ */
+global $ENTITY_CACHE_BANNED_GUIDS;
+$ENTITY_CACHE_BANNED_GUIDS = array();
+
 /**
  * Cache subtypes and related class names.
  *
@@ -25,6 +34,34 @@ $ENTITY_CACHE = array();
 global $SUBTYPE_CACHE;
 $SUBTYPE_CACHE = null;
 
+/**
+ * Ban this entity from the entity cache
+ *
+ * @param int $guid The entity guid
+ *
+ * @access private
+ * @todo this is a workaround until #5604 can be implemented
+ */
+function _elgg_ban_caching_for_entity($guid) {
+	global $ENTITY_CACHE_BANNED_GUIDS;
+
+	_elgg_invalidate_cache_for_entity($guid);
+	$ENTITY_CACHE_BANNED_GUIDS[$guid] = true;
+}
+
+/**
+ * Allow this entity to be stored in the entity cache
+ *
+ * @param int $guid The entity guid
+ *
+ * @access private
+ */
+function _elgg_unban_caching_for_entity($guid) {
+	global $ENTITY_CACHE_BANNED_GUIDS;
+
+	unset($ENTITY_CACHE_BANNED_GUIDS[$guid]);
+}
+
 /**
  * Invalidate this class's entry in the cache.
  *
@@ -57,7 +94,7 @@ function _elgg_invalidate_cache_for_entity($guid) {
  * @todo Use an ElggCache object
  */
 function _elgg_cache_entity(ElggEntity $entity) {
-	global $ENTITY_CACHE;
+	global $ENTITY_CACHE, $ENTITY_CACHE_BANNED_GUIDS;
 
 	// 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.
@@ -65,6 +102,11 @@ function _elgg_cache_entity(ElggEntity $entity) {
 		return;
 	}
 
+	$guid = $entity->getGUID();
+	if (isset($ENTITY_CACHE_BANNED_GUIDS[$guid])) {
+		return;
+	}
+
 	// Don't store too many or we'll have memory problems
 	// @todo Pick a less arbitrary limit
 	if (count($ENTITY_CACHE) > 256) {
@@ -79,7 +121,7 @@ function _elgg_cache_entity(ElggEntity $entity) {
 		elgg_get_metadata_cache()->clear($random_guid);
 	}
 
-	$ENTITY_CACHE[$entity->guid] = $entity;
+	$ENTITY_CACHE[$guid] = $entity;
 }
 
 /**
-- 
cgit v1.2.3


From e04a851de79007adfb1c2c7a81f0cece95ae6441 Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Fri, 7 Jun 2013 09:49:41 -0400
Subject: Rename ban/unban to disable/enable

---
 engine/lib/entities.php | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index ac4b4d995..d0d97aa95 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -19,11 +19,11 @@ $ENTITY_CACHE = array();
 /**
  * GUIDs of entities banned from the entity cache (during this request)
  *
- * @global array $ENTITY_CACHE_BANNED_GUIDS
+ * @global array $ENTITY_CACHE_DISABLED_GUIDS
  * @access private
  */
-global $ENTITY_CACHE_BANNED_GUIDS;
-$ENTITY_CACHE_BANNED_GUIDS = array();
+global $ENTITY_CACHE_DISABLED_GUIDS;
+$ENTITY_CACHE_DISABLED_GUIDS = array();
 
 /**
  * Cache subtypes and related class names.
@@ -35,18 +35,18 @@ global $SUBTYPE_CACHE;
 $SUBTYPE_CACHE = null;
 
 /**
- * Ban this entity from the entity cache
+ * 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_ban_caching_for_entity($guid) {
-	global $ENTITY_CACHE_BANNED_GUIDS;
+function _elgg_disable_caching_for_entity($guid) {
+	global $ENTITY_CACHE_DISABLED_GUIDS;
 
 	_elgg_invalidate_cache_for_entity($guid);
-	$ENTITY_CACHE_BANNED_GUIDS[$guid] = true;
+	$ENTITY_CACHE_DISABLED_GUIDS[$guid] = true;
 }
 
 /**
@@ -56,10 +56,10 @@ function _elgg_ban_caching_for_entity($guid) {
  *
  * @access private
  */
-function _elgg_unban_caching_for_entity($guid) {
-	global $ENTITY_CACHE_BANNED_GUIDS;
+function _elgg_enable_caching_for_entity($guid) {
+	global $ENTITY_CACHE_DISABLED_GUIDS;
 
-	unset($ENTITY_CACHE_BANNED_GUIDS[$guid]);
+	unset($ENTITY_CACHE_DISABLED_GUIDS[$guid]);
 }
 
 /**
@@ -94,7 +94,7 @@ function _elgg_invalidate_cache_for_entity($guid) {
  * @todo Use an ElggCache object
  */
 function _elgg_cache_entity(ElggEntity $entity) {
-	global $ENTITY_CACHE, $ENTITY_CACHE_BANNED_GUIDS;
+	global $ENTITY_CACHE, $ENTITY_CACHE_DISABLED_GUIDS;
 
 	// 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.
@@ -103,7 +103,7 @@ function _elgg_cache_entity(ElggEntity $entity) {
 	}
 
 	$guid = $entity->getGUID();
-	if (isset($ENTITY_CACHE_BANNED_GUIDS[$guid])) {
+	if (isset($ENTITY_CACHE_DISABLED_GUIDS[$guid])) {
 		return;
 	}
 
-- 
cgit v1.2.3


From 46ace645c75dbbaad4b2cdaeedffcd501487aa93 Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Fri, 7 Jun 2013 09:52:48 -0400
Subject: Fixes #5600: Entities are kept out of entity cache during save

---
 engine/classes/ElggEntity.php | 12 ++++++++++--
 engine/classes/ElggGroup.php  |  7 ++++++-
 engine/classes/ElggObject.php |  8 ++++++--
 engine/classes/ElggUser.php   |  6 +++++-
 4 files changed, 27 insertions(+), 6 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggEntity.php b/engine/classes/ElggEntity.php
index 8b3ceb551..dd1c7c114 100644
--- a/engine/classes/ElggEntity.php
+++ b/engine/classes/ElggEntity.php
@@ -1270,15 +1270,23 @@ abstract class ElggEntity extends ElggData implements
 	public function save() {
 		$guid = $this->getGUID();
 		if ($guid > 0) {
-			_elgg_cache_entity($this);
 
-			return update_entity(
+			// See #5600. This ensures the lower level can_edit_entity() check will use a
+			// fresh entity from the DB so it sees the persisted owner_guid
+			_elgg_disable_caching_for_entity($guid);
+
+			$ret = update_entity(
 				$guid,
 				$this->get('owner_guid'),
 				$this->get('access_id'),
 				$this->get('container_guid'),
 				$this->get('time_created')
 			);
+
+			_elgg_enable_caching_for_entity($guid);
+			_elgg_cache_entity($this);
+
+			return $ret;
 		} else {
 			// Create a new entity (nb: using attribute array directly
 			// 'cos set function does something special!)
diff --git a/engine/classes/ElggGroup.php b/engine/classes/ElggGroup.php
index 61f9163d5..7e69b7a84 100644
--- a/engine/classes/ElggGroup.php
+++ b/engine/classes/ElggGroup.php
@@ -352,7 +352,12 @@ class ElggGroup extends ElggEntity
 		}
 
 		// Now save specific stuff
-		return create_group_entity($this->get('guid'), $this->get('name'), $this->get('description'));
+
+		_elgg_disable_caching_for_entity($this->guid);
+		$ret = create_group_entity($this->get('guid'), $this->get('name'), $this->get('description'));
+		_elgg_enable_caching_for_entity($this->guid);
+
+		return $ret;
 	}
 
 	// EXPORTABLE INTERFACE ////////////////////////////////////////////////////////////
diff --git a/engine/classes/ElggObject.php b/engine/classes/ElggObject.php
index d54752dca..aeaa3ba5c 100644
--- a/engine/classes/ElggObject.php
+++ b/engine/classes/ElggObject.php
@@ -126,8 +126,12 @@ class ElggObject extends ElggEntity {
 		}
 
 		// Save ElggObject-specific attributes
-		return create_object_entity($this->get('guid'), $this->get('title'),
-			$this->get('description'));
+
+		_elgg_disable_caching_for_entity($this->guid);
+		$ret = create_object_entity($this->get('guid'), $this->get('title'), $this->get('description'));
+		_elgg_enable_caching_for_entity($this->guid);
+
+		return $ret;
 	}
 
 	/**
diff --git a/engine/classes/ElggUser.php b/engine/classes/ElggUser.php
index b2cada8ef..6163f9b62 100644
--- a/engine/classes/ElggUser.php
+++ b/engine/classes/ElggUser.php
@@ -132,9 +132,13 @@ class ElggUser extends ElggEntity
 		}
 
 		// Now save specific stuff
-		return create_user_entity($this->get('guid'), $this->get('name'), $this->get('username'),
+		_elgg_disable_caching_for_entity($this->guid);
+		$ret = create_user_entity($this->get('guid'), $this->get('name'), $this->get('username'),
 			$this->get('password'), $this->get('salt'), $this->get('email'), $this->get('language'),
 			$this->get('code'));
+		_elgg_enable_caching_for_entity($this->guid);
+
+		return $ret;
 	}
 
 	/**
-- 
cgit v1.2.3


From 3a3a520958e1eb31ac9d20e7cb818d8c3b5fff4a Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Sat, 8 Jun 2013 21:12:03 -0400
Subject: ElggBatch with incrementOffset off now handles incomplete entities

---
 engine/classes/ElggBatch.php | 36 +++++++++++++++++++--------
 engine/tests/api/helpers.php | 58 +++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 80 insertions(+), 14 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggBatch.php b/engine/classes/ElggBatch.php
index 83963ccee..ac79cf084 100644
--- a/engine/classes/ElggBatch.php
+++ b/engine/classes/ElggBatch.php
@@ -242,9 +242,12 @@ class ElggBatch
 	/**
 	 * Fetches the next chunk of results
 	 *
+	 * @param int $num_incompletes_last_fetch When called recursively, this is the number of
+	 *                                        incomplete entities returned in the last fetch.
+	 *
 	 * @return bool
 	 */
-	private function getNextResultsChunk() {
+	private function getNextResultsChunk($num_incompletes_last_fetch = 0) {
 
 		// always reset results.
 		$this->results = array();
@@ -278,7 +281,7 @@ class ElggBatch
 		if ($this->incrementOffset) {
 			$offset = $this->offset + $this->retrievedResults;
 		} else {
-			$offset = $this->offset;
+			$offset = $this->offset + $num_incompletes_last_fetch;
 		}
 
 		$current_options = array(
@@ -292,17 +295,30 @@ class ElggBatch
 		$this->incompleteEntities = array();
 		$this->results = call_user_func_array($this->getter, array($options));
 
-		// If there were incomplete entities, we pretend they were at the beginning of the results,
-		// fool the local counter to think it's skipped by them already, and update the running
-		// total as if the results contained the incompletes.
-		if ($this->results || $this->incompleteEntities) {
+		$num_results = count($this->results);
+		$num_incomplete = count($this->incompleteEntities);
+
+		if ($this->incompleteEntities) {
+			// pad the front of the results with nulls representing the incompletes
+			array_splice($this->results, 0, 0, array_pad(array(), $num_incomplete, null));
+			// ...and skip past them
+			reset($this->results);
+			for ($i = 0; $i < $num_incomplete; $i++) {
+				next($this->results);
+			}
+		}
+
+		if ($this->results) {
 			$this->chunkIndex++;
-			$this->resultIndex = count($this->incompleteEntities);
-			$this->retrievedResults += (count($this->results) + count($this->incompleteEntities));
-			if (!$this->results) {
+
+			// let the system know we've jumped past the nulls
+			$this->resultIndex = $num_incomplete;
+
+			$this->retrievedResults += ($num_results + $num_incomplete);
+			if ($num_results == 0) {
 				// This fetch was *all* incompletes! We need to fetch until we can either
 				// offer at least one row to iterate over, or give up.
-				return $this->getNextResultsChunk();
+				return $this->getNextResultsChunk($num_incomplete);
 			}
 			return true;
 		} else {
diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php
index 43244636b..06ef55138 100644
--- a/engine/tests/api/helpers.php
+++ b/engine/tests/api/helpers.php
@@ -578,16 +578,14 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
 		$this->assertEqual(11, $j);
 	}
 
-	public function testElggBatchHandlesBrokenEntities() {
+	public function testElggBatchReadHandlesBrokenEntities() {
 		$num_test_entities = 6;
 		$guids = array();
-		$now = time();
 		for ($i = $num_test_entities; $i > 0; $i--) {
 			$entity = new ElggObject();
 			$entity->type = 'object';
 			$entity->subtype = 'test_5357_subtype';
 			$entity->access_id = ACCESS_PUBLIC;
-			$entity->time_created = ($now - $i);
 			$entity->save();
 			$guids[] = $entity->guid;
 			_elgg_invalidate_cache_for_entity($entity->guid);
@@ -604,11 +602,12 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
 		$options = array(
 			'type' => 'object',
 			'subtype' => 'test_5357_subtype',
-			'order_by' => 'e.time_created ASC',
+			'order_by' => 'e.guid',
 		);
 
 		$entities_visited = array();
 		$batch = new ElggBatch('elgg_get_entities', $options, null, 2);
+		/* @var ElggEntity[] $batch */
 		foreach ($batch as $entity) {
 			$entities_visited[] = $entity->guid;
 		}
@@ -629,6 +628,57 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
 		delete_data("DELETE FROM {$db_prefix}objects_entity WHERE guid IN (" . implode(',', $guids) . ")");
 	}
 
+	public function testElggBatchDeleteHandlesBrokenEntities() {
+		$num_test_entities = 6;
+		$guids = array();
+		for ($i = $num_test_entities; $i > 0; $i--) {
+			$entity = new ElggObject();
+			$entity->type = 'object';
+			$entity->subtype = 'test_5357_subtype';
+			$entity->access_id = ACCESS_PUBLIC;
+			$entity->save();
+			$guids[] = $entity->guid;
+			_elgg_invalidate_cache_for_entity($entity->guid);
+		}
+
+		// break entities such that the first fetch has one incomplete
+		// and the second fetch has only incompletes!
+		$db_prefix = elgg_get_config('dbprefix');
+		delete_data("
+			DELETE FROM {$db_prefix}objects_entity
+			WHERE guid IN ({$guids[1]}, {$guids[2]}, {$guids[3]})
+		");
+
+		$options = array(
+			'type' => 'object',
+			'subtype' => 'test_5357_subtype',
+			'order_by' => 'e.guid',
+		);
+
+		$entities_visited = array();
+		$batch = new ElggBatch('elgg_get_entities', $options, null, 2, false);
+		/* @var ElggEntity[] $batch */
+		foreach ($batch as $entity) {
+			$entities_visited[] = $entity->guid;
+			$entity->delete();
+		}
+
+		// The broken entities should not have been visited
+		$this->assertEqual($entities_visited, array($guids[0], $guids[4], $guids[5]));
+
+		// cleanup (including leftovers from previous tests)
+		$entity_rows = elgg_get_entities(array_merge($options, array(
+			'callback' => '',
+			'limit' => false,
+		)));
+		$guids = array();
+		foreach ($entity_rows as $row) {
+			$guids[] = $row->guid;
+		}
+		delete_data("DELETE FROM {$db_prefix}entities WHERE guid IN (" . implode(',', $guids) . ")");
+		delete_data("DELETE FROM {$db_prefix}objects_entity WHERE guid IN (" . implode(',', $guids) . ")");
+	}
+
 	static function elgg_batch_callback_test($options, $reset = false) {
 		static $count = 1;
 
-- 
cgit v1.2.3


From 8a47b2342e53c9cdf3093982486b19d6cc2f3e9b Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Sat, 8 Jun 2013 21:34:11 -0400
Subject: Improved algorithm by tracking total incomplete entities

---
 engine/classes/ElggBatch.php | 18 ++++++++++++------
 engine/tests/api/helpers.php | 16 ++++++++--------
 2 files changed, 20 insertions(+), 14 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggBatch.php b/engine/classes/ElggBatch.php
index ac79cf084..d810ea066 100644
--- a/engine/classes/ElggBatch.php
+++ b/engine/classes/ElggBatch.php
@@ -156,6 +156,13 @@ class ElggBatch
 	 */
 	private $incompleteEntities = array();
 
+	/**
+	 * Total number of incomplete entities fetched
+	 *
+	 * @var int
+	 */
+	private $totalIncompletes = 0;
+
 	/**
 	 * Batches operations on any elgg_get_*() or compatible function that supports
 	 * an options array.
@@ -242,12 +249,9 @@ class ElggBatch
 	/**
 	 * Fetches the next chunk of results
 	 *
-	 * @param int $num_incompletes_last_fetch When called recursively, this is the number of
-	 *                                        incomplete entities returned in the last fetch.
-	 *
 	 * @return bool
 	 */
-	private function getNextResultsChunk($num_incompletes_last_fetch = 0) {
+	private function getNextResultsChunk() {
 
 		// always reset results.
 		$this->results = array();
@@ -281,7 +285,7 @@ class ElggBatch
 		if ($this->incrementOffset) {
 			$offset = $this->offset + $this->retrievedResults;
 		} else {
-			$offset = $this->offset + $num_incompletes_last_fetch;
+			$offset = $this->offset + $this->totalIncompletes;
 		}
 
 		$current_options = array(
@@ -298,6 +302,8 @@ class ElggBatch
 		$num_results = count($this->results);
 		$num_incomplete = count($this->incompleteEntities);
 
+		$this->totalIncompletes += $num_incomplete;
+
 		if ($this->incompleteEntities) {
 			// pad the front of the results with nulls representing the incompletes
 			array_splice($this->results, 0, 0, array_pad(array(), $num_incomplete, null));
@@ -318,7 +324,7 @@ class ElggBatch
 			if ($num_results == 0) {
 				// This fetch was *all* incompletes! We need to fetch until we can either
 				// offer at least one row to iterate over, or give up.
-				return $this->getNextResultsChunk($num_incomplete);
+				return $this->getNextResultsChunk();
 			}
 			return true;
 		} else {
diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php
index 06ef55138..10216140f 100644
--- a/engine/tests/api/helpers.php
+++ b/engine/tests/api/helpers.php
@@ -579,7 +579,7 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
 	}
 
 	public function testElggBatchReadHandlesBrokenEntities() {
-		$num_test_entities = 6;
+		$num_test_entities = 8;
 		$guids = array();
 		for ($i = $num_test_entities; $i > 0; $i--) {
 			$entity = new ElggObject();
@@ -592,11 +592,11 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
 		}
 
 		// break entities such that the first fetch has one incomplete
-		// and the second fetch has only incompletes!
+		// and the second and third fetches have only incompletes!
 		$db_prefix = elgg_get_config('dbprefix');
 		delete_data("
 			DELETE FROM {$db_prefix}objects_entity
-			WHERE guid IN ({$guids[1]}, {$guids[2]}, {$guids[3]})
+			WHERE guid IN ({$guids[1]}, {$guids[2]}, {$guids[3]}, {$guids[4]}, {$guids[5]})
 		");
 
 		$options = array(
@@ -613,7 +613,7 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
 		}
 
 		// The broken entities should not have been visited
-		$this->assertEqual($entities_visited, array($guids[0], $guids[4], $guids[5]));
+		$this->assertEqual($entities_visited, array($guids[0], $guids[6], $guids[7]));
 
 		// cleanup (including leftovers from previous tests)
 		$entity_rows = elgg_get_entities(array_merge($options, array(
@@ -629,7 +629,7 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
 	}
 
 	public function testElggBatchDeleteHandlesBrokenEntities() {
-		$num_test_entities = 6;
+		$num_test_entities = 8;
 		$guids = array();
 		for ($i = $num_test_entities; $i > 0; $i--) {
 			$entity = new ElggObject();
@@ -642,11 +642,11 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
 		}
 
 		// break entities such that the first fetch has one incomplete
-		// and the second fetch has only incompletes!
+		// and the second and third fetches have only incompletes!
 		$db_prefix = elgg_get_config('dbprefix');
 		delete_data("
 			DELETE FROM {$db_prefix}objects_entity
-			WHERE guid IN ({$guids[1]}, {$guids[2]}, {$guids[3]})
+			WHERE guid IN ({$guids[1]}, {$guids[2]}, {$guids[3]}, {$guids[4]}, {$guids[5]})
 		");
 
 		$options = array(
@@ -664,7 +664,7 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
 		}
 
 		// The broken entities should not have been visited
-		$this->assertEqual($entities_visited, array($guids[0], $guids[4], $guids[5]));
+		$this->assertEqual($entities_visited, array($guids[0], $guids[6], $guids[7]));
 
 		// cleanup (including leftovers from previous tests)
 		$entity_rows = elgg_get_entities(array_merge($options, array(
-- 
cgit v1.2.3


From 5a1a793f8634e0f7133644e09e9ace60782864d4 Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Sat, 8 Jun 2013 22:12:12 -0400
Subject: Fixes #5598: Properly update metadata cache in update_metadata()

---
 engine/lib/metadata.php             | 10 +++++-----
 engine/tests/api/metadata_cache.php |  7 +++++++
 2 files changed, 12 insertions(+), 5 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php
index 43f7d5d6e..046b85124 100644
--- a/engine/lib/metadata.php
+++ b/engine/lib/metadata.php
@@ -191,19 +191,19 @@ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_i
 	}
 
 	// 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);
diff --git a/engine/tests/api/metadata_cache.php b/engine/tests/api/metadata_cache.php
index 846116a7b..7fb328169 100644
--- a/engine/tests/api/metadata_cache.php
+++ b/engine/tests/api/metadata_cache.php
@@ -166,4 +166,11 @@ class ElggCoreMetadataCacheTest extends ElggCoreUnitTest {
 		$actual = $this->cache->filterMetadataHeavyEntities($guids, 6000);
 		$this->assertIdentical($actual, $expected);
 	}
+
+	public function testCreateMetadataInvalidates() {
+		$this->obj1->foo = 1;
+		create_metadata($this->guid1, 'foo', 2, '', elgg_get_logged_in_user_guid(), ACCESS_FRIENDS);
+
+		$this->assertEqual($this->obj1->foo, 2);
+	}
 }
-- 
cgit v1.2.3


From d2b525a8c9d4926944ad4a9126dbd266dc823a9b Mon Sep 17 00:00:00 2001
From: Cash Costello 
Date: Fri, 14 Jun 2013 07:29:43 -0400
Subject: Fixes #5626 adds limit for display of titles for river, breadcrumbs,
 and list pages

---
 engine/lib/navigation.php                 | 2 +-
 views/default/object/elements/summary.php | 2 +-
 views/default/river/elements/summary.php  | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php
index 2831d418b..ab9cc05e8 100644
--- a/engine/lib/navigation.php
+++ b/engine/lib/navigation.php
@@ -218,7 +218,7 @@ function elgg_push_breadcrumb($title, $link = NULL) {
 	}
 
 	// avoid key collisions.
-	$CONFIG->breadcrumbs[] = array('title' => $title, 'link' => $link);
+	$CONFIG->breadcrumbs[] = array('title' => elgg_get_excerpt($title, 100), 'link' => $link);
 }
 
 /**
diff --git a/views/default/object/elements/summary.php b/views/default/object/elements/summary.php
index c0f3ad340..63ab8f816 100644
--- a/views/default/object/elements/summary.php
+++ b/views/default/object/elements/summary.php
@@ -27,7 +27,7 @@ if ($title_link === '') {
 		$text = $entity->name;
 	}
 	$params = array(
-		'text' => $text,
+		'text' => elgg_get_excerpt($text, 100),
 		'href' => $entity->getURL(),
 		'is_trusted' => true,
 	);
diff --git a/views/default/river/elements/summary.php b/views/default/river/elements/summary.php
index 416bc708b..d7bde51dd 100644
--- a/views/default/river/elements/summary.php
+++ b/views/default/river/elements/summary.php
@@ -18,9 +18,10 @@ $subject_link = elgg_view('output/url', array(
 	'is_trusted' => true,
 ));
 
+$object_text = $object->title ? $object->title : $object->name;
 $object_link = elgg_view('output/url', array(
 	'href' => $object->getURL(),
-	'text' => $object->title ? $object->title : $object->name,
+	'text' => elgg_get_excerpt($object_text, 100),
 	'class' => 'elgg-river-object',
 	'is_trusted' => true,
 ));
-- 
cgit v1.2.3


From e29554909dc098f163a9dc6de31c42cd749ab4ae Mon Sep 17 00:00:00 2001
From: Jerome Bakker 
Date: Mon, 17 Jun 2013 14:47:49 +0200
Subject: fixed: wrong default behaviour in can_edit_entity_metadata

---
 engine/lib/entities.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index 072b26805..226cf5c6c 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -761,7 +761,7 @@ function get_entity($guid) {
 	// @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 }, 
+	// 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') {
@@ -2126,7 +2126,7 @@ 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)) {
-- 
cgit v1.2.3


From c9d1dd21d3dcf7353570d555c21a2b6ca7ecdd00 Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Sat, 22 Jun 2013 20:19:53 -0400
Subject: Fixes #5673: Properly check simplecache views list if cache file
 missing

---
 engine/handlers/cache_handler.php | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

(limited to 'engine')

diff --git a/engine/handlers/cache_handler.php b/engine/handlers/cache_handler.php
index 9848d3531..36fc665bb 100644
--- a/engine/handlers/cache_handler.php
+++ b/engine/handlers/cache_handler.php
@@ -88,20 +88,18 @@ header("ETag: \"$etag\"");
 $filename = $dataroot . 'views_simplecache/' . md5($viewtype . $view);
 
 if (file_exists($filename)) {
-	$contents = file_get_contents($filename);
+	readfile($filename);
 } else {
 	// someone trying to access a non-cached file or a race condition with cache flushing
 	mysql_close($mysql_dblink);
 	require_once(dirname(dirname(__FILE__)) . "/start.php");
 
 	global $CONFIG;
-	if (!isset($CONFIG->views->simplecache[$view])) {
+	if (!in_array($view, $CONFIG->views->simplecache)) {
 		header("HTTP/1.1 404 Not Found");
 		exit;
 	}
 
 	elgg_set_viewtype($viewtype);
-	$contents = elgg_view($view);
+	echo elgg_view($view);
 }
-
-echo $contents;
-- 
cgit v1.2.3


From 217c51eb6bbf754570cc9347a031b72927bcc985 Mon Sep 17 00:00:00 2001
From: cash 
Date: Fri, 5 Jul 2013 21:03:34 -0400
Subject: Fixes #5671 fixed query for clearing admin settings on plugin

---
 engine/classes/ElggPlugin.php | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

(limited to 'engine')

diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php
index c1c46f272..3cc90f623 100644
--- a/engine/classes/ElggPlugin.php
+++ b/engine/classes/ElggPlugin.php
@@ -350,11 +350,14 @@ class ElggPlugin extends ElggObject {
 	 */
 	public function unsetAllSettings() {
 		$db_prefix = get_config('dbprefix');
-		$ps_prefix = elgg_namespace_plugin_private_setting('setting', '');
+
+		$us_prefix = elgg_namespace_plugin_private_setting('user_setting', '', $this->getID());
+		$is_prefix = elgg_namespace_plugin_private_setting('internal', '', $this->getID());
 
 		$q = "DELETE FROM {$db_prefix}private_settings
 			WHERE entity_guid = $this->guid
-			AND name NOT LIKE '$ps_prefix%'";
+			AND name NOT LIKE '$us_prefix%'
+			AND name NOT LIKE '$is_prefix%'";
 
 		return delete_data($q);
 	}
-- 
cgit v1.2.3


From c301e22224db8b064c1de68799b8e49cc1259e2e Mon Sep 17 00:00:00 2001
From: cash 
Date: Fri, 5 Jul 2013 21:21:00 -0400
Subject: Refs #5662 added error message for what should be impossible
 condition

---
 engine/classes/ElggPlugin.php        | 2 +-
 engine/classes/ElggPluginPackage.php | 1 +
 languages/en.php                     | 1 +
 3 files changed, 3 insertions(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php
index 3cc90f623..7bf6eb1df 100644
--- a/engine/classes/ElggPlugin.php
+++ b/engine/classes/ElggPlugin.php
@@ -549,7 +549,7 @@ class ElggPlugin extends ElggObject {
 	 * Returns if the plugin is complete, meaning has all required files
 	 * and Elgg can read them and they make sense.
 	 *
-	 * @todo bad name? This could be confused with isValid() from ElggPackage.
+	 * @todo bad name? This could be confused with isValid() from ElggPluginPackage.
 	 *
 	 * @return bool
 	 */
diff --git a/engine/classes/ElggPluginPackage.php b/engine/classes/ElggPluginPackage.php
index 209242288..37eb4bf4d 100644
--- a/engine/classes/ElggPluginPackage.php
+++ b/engine/classes/ElggPluginPackage.php
@@ -294,6 +294,7 @@ class ElggPluginPackage {
 			return true;
 		}
 
+		$this->errorMsg = elgg_echo('unknown_error');
 		return false;
 	}
 
diff --git a/languages/en.php b/languages/en.php
index 49e366484..1721865f7 100644
--- a/languages/en.php
+++ b/languages/en.php
@@ -903,6 +903,7 @@ $english = array(
 	'total' => 'Total',
 
 	'learnmore' => "Click here to learn more.",
+	'unknown_error' => 'Unknown error',
 
 	'content' => "content",
 	'content:latest' => 'Latest activity',
-- 
cgit v1.2.3


From 0dfe018f16e93aff5f046c08994a102e3f5d35e6 Mon Sep 17 00:00:00 2001
From: cash 
Date: Fri, 5 Jul 2013 22:31:56 -0400
Subject: Fixes #4293 don't require both offset key and offset for listing
 stuff

---
 engine/lib/entities.php | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index 226cf5c6c..997db79d2 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -1473,8 +1473,10 @@ 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,
-- 
cgit v1.2.3


From 9892692deefdb06d9e7176c72fc5780ab79e3a7d Mon Sep 17 00:00:00 2001
From: Brett Profitt 
Date: Tue, 9 Jul 2013 12:13:17 -0400
Subject: Fixes #5706. Allowing parens in URIs if not last character.

---
 engine/lib/output.php                 | 8 ++++----
 engine/tests/regression/trac_bugs.php | 3 +++
 2 files changed, 7 insertions(+), 4 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/output.php b/engine/lib/output.php
index 5adc01053..6172a5c8d 100644
--- a/engine/lib/output.php
+++ b/engine/lib/output.php
@@ -27,16 +27,16 @@ function parse_urls($text) {
 	// By default htmlawed rewrites tags to this format.
 	// if PHP supported conditional negative lookbehinds we could use this:
 	// $r = preg_replace_callback('/(?"\'\!\(\),]+)/i',
-	$r = preg_replace_callback('/(?"\'\(\)]+)/i',
+	$r = preg_replace_callback('/(?"\']+)/i',
 	create_function(
 		'$matches',
 		'
 			$url = $matches[1];
-			$punc = \'\';
+			$punc = "";
 			$last = substr($url, -1, 1);
-			if (in_array($last, array(".", "!", ","))) {
+			if (in_array($last, array(".", "!", ",", "(", ")"))) {
 				$punc = $last;
-				$url = rtrim($url, ".!,");
+				$url = rtrim($url, ".!,()");
 			}
 			$urltext = str_replace("/", "/", $url);
 			return "$urltext$punc";
diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php
index 5730830bb..f173b5b9f 100644
--- a/engine/tests/regression/trac_bugs.php
+++ b/engine/tests/regression/trac_bugs.php
@@ -291,6 +291,9 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest {
 
 			'unquoted already anchor yahoo' =>
 				'unquoted already anchor yahoo',
+
+			'parens in uri http://thedailywtf.com/Articles/A-(Long-Overdue)-BuildMaster-Introduction.aspx' =>
+				'parens in uri http://thedailywtf.com/Articles/A-(Long-Overdue)-BuildMaster-Introduction.aspx'
 		);
 		foreach ($cases as $input => $output) {
 			$this->assertEqual($output, parse_urls($input));
-- 
cgit v1.2.3


From cf15971dc02b59e2ea36041aaec69bc1b9b21a64 Mon Sep 17 00:00:00 2001
From: Cash Costello 
Date: Sat, 13 Jul 2013 08:06:54 -0400
Subject: Fixes #5800 cast user guid to an int

---
 engine/lib/sessions.php | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'engine')

diff --git a/engine/lib/sessions.php b/engine/lib/sessions.php
index a34c2045b..fb28e1e9a 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
-- 
cgit v1.2.3


From 2cab755b9df35f5e338151cf1e94cbce5f544e98 Mon Sep 17 00:00:00 2001
From: Cash Costello 
Date: Sat, 13 Jul 2013 08:39:58 -0400
Subject: adds warning for those using a string value with the operand "IN" for
 metadata pairs

---
 engine/lib/metadata.php | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php
index 046b85124..d2f8d4cd4 100644
--- a/engine/lib/metadata.php
+++ b/engine/lib/metadata.php
@@ -402,9 +402,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
-- 
cgit v1.2.3


From 283106afa1fb6ff9984341b8911f90c5d4e4c4a2 Mon Sep 17 00:00:00 2001
From: Sem 
Date: Thu, 12 Sep 2013 00:15:52 +0200
Subject: Fixes #6052. Urldecoding usernames to allow non-alphanumeric
 characters.

---
 engine/lib/users.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/lib/users.php b/engine/lib/users.php
index 9a5194896..0b4608034 100644
--- a/engine/lib/users.php
+++ b/engine/lib/users.php
@@ -553,7 +553,7 @@ function get_user($guid) {
 function get_user_by_username($username) {
 	global $CONFIG, $USERNAME_TO_GUID_MAP_CACHE;
 
-	$username = sanitise_string($username);
+	$username = sanitise_string(rawurldecode($username));
 	$access = get_access_sql_suffix('e');
 
 	// Caching
-- 
cgit v1.2.3


From c1ea910e3b3b0bcc27a214383c9f6355a05dd495 Mon Sep 17 00:00:00 2001
From: Paweł Sroka 
Date: Thu, 12 Sep 2013 05:59:18 +0200
Subject: Added function for escaping query strings and fixed several XSRF
 vulnerabilities.

---
 engine/lib/output.php                | 19 +++++++++++++++++++
 mod/groups/lib/groups.php            |  3 ++-
 mod/members/pages/members/search.php |  8 ++++++--
 mod/search/pages/search/index.php    | 10 +---------
 4 files changed, 28 insertions(+), 12 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/output.php b/engine/lib/output.php
index 6172a5c8d..de4f911fb 100644
--- a/engine/lib/output.php
+++ b/engine/lib/output.php
@@ -420,6 +420,25 @@ function _elgg_html_decode($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
  *
diff --git a/mod/groups/lib/groups.php b/mod/groups/lib/groups.php
index 77d7c09cc..aa8766e06 100644
--- a/mod/groups/lib/groups.php
+++ b/mod/groups/lib/groups.php
@@ -73,7 +73,8 @@ function groups_search_page() {
 	elgg_push_breadcrumb(elgg_echo('search'));
 
 	$tag = get_input("tag");
-	$title = elgg_echo('groups:search:title', array($tag));
+	$display_query = _elgg_get_display_query($tag);
+	$title = elgg_echo('groups:search:title', array($display_query));
 
 	// groups plugin saves tags as "interests" - see groups_fields_setup() in start.php
 	$params = array(
diff --git a/mod/members/pages/members/search.php b/mod/members/pages/members/search.php
index 1f0444d67..5466a8246 100644
--- a/mod/members/pages/members/search.php
+++ b/mod/members/pages/members/search.php
@@ -7,7 +7,9 @@
 if ($vars['search_type'] == 'tag') {
 	$tag = get_input('tag');
 
-	$title = elgg_echo('members:title:searchtag', array($tag));
+	$display_query = _elgg_get_display_query($tag);
+
+	$title = elgg_echo('members:title:searchtag', array($display_query));
 
 	$options = array();
 	$options['query'] = $tag;
@@ -28,7 +30,9 @@ if ($vars['search_type'] == 'tag') {
 } else {
 	$name = sanitize_string(get_input('name'));
 
-	$title = elgg_echo('members:title:searchname', array($name));
+	$display_query = _elgg_get_display_query($name);
+
+	$title = elgg_echo('members:title:searchname', array($display_query));
 
 	$db_prefix = elgg_get_config('dbprefix');
 	$params = array(
diff --git a/mod/search/pages/search/index.php b/mod/search/pages/search/index.php
index ede09329b..9542e0751 100644
--- a/mod/search/pages/search/index.php
+++ b/mod/search/pages/search/index.php
@@ -17,15 +17,7 @@ $search_type = get_input('search_type', 'all');
 // XSS protection is more important that searching for HTML.
 $query = stripslashes(get_input('q', get_input('tag', '')));
 
-// @todo - create function for sanitization of strings for display in 1.8
-// encode <,>,&, quotes and characters above 127
-if (function_exists('mb_convert_encoding')) {
-	$display_query = mb_convert_encoding($query, 'HTML-ENTITIES', 'UTF-8');
-} else {
-	// if no mbstring extension, we just strip characters
-	$display_query = preg_replace("/[^\x01-\x7F]/", "", $query);
-}
-$display_query = htmlspecialchars($display_query, ENT_QUOTES, 'UTF-8', false);
+$display_query = _elgg_get_display_query($query);
 
 // check that we have an actual query
 if (!$query) {
-- 
cgit v1.2.3


From 0f448571e3618a2a4ef56e377ff26c6278585b48 Mon Sep 17 00:00:00 2001
From: Matt Beckett 
Date: Thu, 12 Sep 2013 22:10:51 -0700
Subject: collections pages are only for logged in users

---
 engine/lib/users.php | 1 +
 1 file changed, 1 insertion(+)

(limited to 'engine')

diff --git a/engine/lib/users.php b/engine/lib/users.php
index 9a5194896..e26b6cd4b 100644
--- a/engine/lib/users.php
+++ b/engine/lib/users.php
@@ -1091,6 +1091,7 @@ function friends_page_handler($segments, $handler) {
  * @access private
  */
 function collections_page_handler($page_elements) {
+    gatekeeper();
 	elgg_set_context('friends');
 	$base = elgg_get_config('path');
 	if (isset($page_elements[0])) {
-- 
cgit v1.2.3


From 25cdb9287c734dbe7fb29704f39537dd1a1a0cc0 Mon Sep 17 00:00:00 2001
From: Matt Beckett 
Date: Thu, 12 Sep 2013 22:13:45 -0700
Subject: spacing

---
 engine/lib/users.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/lib/users.php b/engine/lib/users.php
index e26b6cd4b..a3813e6a8 100644
--- a/engine/lib/users.php
+++ b/engine/lib/users.php
@@ -1091,7 +1091,7 @@ function friends_page_handler($segments, $handler) {
  * @access private
  */
 function collections_page_handler($page_elements) {
-    gatekeeper();
+	gatekeeper();
 	elgg_set_context('friends');
 	$base = elgg_get_config('path');
 	if (isset($page_elements[0])) {
-- 
cgit v1.2.3


From 32f2a17bec4dc7e19cfdc5f2e5dd55b37732e910 Mon Sep 17 00:00:00 2001
From: Jeroen Dalsem 
Date: Fri, 20 Sep 2013 10:36:27 +0200
Subject: detect pagination needs

---
 engine/lib/river.php | 10 ++++++++--
 engine/lib/views.php | 20 +++++++++++++++-----
 2 files changed, 23 insertions(+), 7 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/river.php b/engine/lib/river.php
index 4926a85c4..e92040eb7 100644
--- a/engine/lib/river.php
+++ b/engine/lib/river.php
@@ -120,7 +120,7 @@ $posted = 0, $annotation_id = 0) {
  *   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
  *
@@ -434,8 +434,13 @@ function elgg_list_river(array $options = array()) {
 		'pagination' => TRUE,
 		'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);
@@ -445,6 +450,7 @@ function elgg_list_river(array $options = array()) {
 
 	$options['count'] = $count;
 	$options['items'] = $items;
+	
 	return elgg_view('page/components/list', $options);
 }
 
diff --git a/engine/lib/views.php b/engine/lib/views.php
index 65ba20204..7f179f572 100644
--- a/engine/lib/views.php
+++ b/engine/lib/views.php
@@ -218,7 +218,7 @@ function elgg_register_ajax_view($view) {
 
 /**
  * Unregister a view for ajax calls
- * 
+ *
  * @param string $view The view name
  * @return void
  * @since 1.8.3
@@ -992,6 +992,11 @@ 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);
 	}
@@ -1064,8 +1069,13 @@ function elgg_view_annotation_list($annotations, array $vars = array()) {
 		'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);
 }
@@ -1334,12 +1344,12 @@ function elgg_view_list_item($item, array $vars = array()) {
 
 /**
  * View one of the elgg sprite icons
- * 
+ *
  * Shorthand for 
- * 
+ *
  * @param string $name  The specific icon to display
  * @param string $class Additional class: float, float-alt, or custom class
- * 
+ *
  * @return string The html for displaying an icon
  */
 function elgg_view_icon($name, $class = '') {
-- 
cgit v1.2.3


From ee2b6351f5a759b6e713d3992c3b0c348850fecf Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Fri, 20 Sep 2013 21:02:30 -0400
Subject: Adds comment to explain URL decoding in get_user_by_username

---
 engine/lib/users.php | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/lib/users.php b/engine/lib/users.php
index 0b4608034..bccfb8b03 100644
--- a/engine/lib/users.php
+++ b/engine/lib/users.php
@@ -553,7 +553,12 @@ function get_user($guid) {
 function get_user_by_username($username) {
 	global $CONFIG, $USERNAME_TO_GUID_MAP_CACHE;
 
-	$username = sanitise_string(rawurldecode($username));
+	// 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
-- 
cgit v1.2.3


From 49ab3a17173aedb8b5e3a2a228cc6cfd0a510e49 Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Fri, 20 Sep 2013 21:19:06 -0400
Subject: Test that get_user_by_username accepts URL encoded input

---
 engine/tests/objects/users.php | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

(limited to 'engine')

diff --git a/engine/tests/objects/users.php b/engine/tests/objects/users.php
index dc9129326..7d2ef6961 100644
--- a/engine/tests/objects/users.php
+++ b/engine/tests/objects/users.php
@@ -159,6 +159,22 @@ class ElggCoreUserTest extends ElggCoreUnitTest {
 		$this->assertFalse($user);
 	}
 
+	public function testGetUserByUsernameAcceptsUrlEncoded() {
+		$username = (string)time();
+		$this->user->username = $username;
+		$guid = $this->user->save();
+
+		// percent encode first letter
+		$first_letter = $username[0];
+		$first_letter = str_pad('%' . dechex(ord($first_letter)), 2, '0', STR_PAD_LEFT);
+		$username =   $first_letter . substr($username, 1);
+
+		$user = get_user_by_username($username);
+		$this->assertTrue((bool) $user);
+		$this->assertEqual($guid, $user->guid);
+
+		$this->user->delete();
+	}
 
 	public function testElggUserMakeAdmin() {
 		global $CONFIG;
-- 
cgit v1.2.3


From ceb9829595b62330ec0d6903287c498e6d6ee37c Mon Sep 17 00:00:00 2001
From: Jerome Bakker 
Date: Mon, 30 Sep 2013 10:34:22 +0200
Subject: fixes #6100 auth_gettoken now works with email address

---
 engine/lib/web_services.php | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

(limited to 'engine')

diff --git a/engine/lib/web_services.php b/engine/lib/web_services.php
index b440e3afb..51cad6f39 100644
--- a/engine/lib/web_services.php
+++ b/engine/lib/web_services.php
@@ -1166,6 +1166,17 @@ function list_all_apis() {
  * @access private
  */
 function auth_gettoken($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) {
@@ -1195,7 +1206,7 @@ $ERRORS = array();
  *
  * @return void
  * @access private
- * 
+ *
  * @throws Exception
  */
 function _php_api_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
-- 
cgit v1.2.3


From 088eb2ce72bfe3852a19f4387e28fee8bdba69c7 Mon Sep 17 00:00:00 2001
From: Steve Clay 
Date: Tue, 8 Oct 2013 08:46:01 -0400
Subject: Fix inline docs for set_input

---
 engine/lib/input.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'engine')

diff --git a/engine/lib/input.php b/engine/lib/input.php
index 2d9bae4dd..80b0b8766 100644
--- a/engine/lib/input.php
+++ b/engine/lib/input.php
@@ -60,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
  */
-- 
cgit v1.2.3


From b3cf5a302d25b06421a055f280ca4f654bd8e6a7 Mon Sep 17 00:00:00 2001
From: beck24 
Date: Sun, 13 Oct 2013 00:03:11 -0700
Subject: Fixes #6177 - refuse to deactive plugins used as dependencies

---
 engine/lib/plugins.php | 35 +++++++++++++++++++++++++++++++++++
 languages/en.php       |  2 ++
 2 files changed, 37 insertions(+)

(limited to 'engine')

diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php
index 74bce45fd..f0d89e92d 100644
--- a/engine/lib/plugins.php
+++ b/engine/lib/plugins.php
@@ -1104,6 +1104,39 @@ function plugins_test($hook, $type, $value, $params) {
 	return $value;
 }
 
+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 = '
    '; + // construct error message and prevent disabling + foreach ($dependents as $dependent) { + $list .= '
  • ' . $dependent->getManifest()->getName() . '
  • '; + } + $list .= '
'; + + register_error(elgg_echo('ElggPlugin:Dependencies:ActiveDependent', array($plugin_name, $list))); + + return false; + } +} + /** * Initialize the plugin system * Listens to system init and registers actions @@ -1115,6 +1148,8 @@ function plugin_init() { run_function_once("plugin_run_once"); elgg_register_plugin_hook_handler('unit_test', 'system', 'plugins_test'); + + elgg_register_event_handler('deactivate', 'plugin', 'plugins_deactivate_dependency_check'); elgg_register_action("plugins/settings/save", '', 'admin'); elgg_register_action("plugins/usersettings/save"); diff --git a/languages/en.php b/languages/en.php index 1721865f7..ad4831db7 100644 --- a/languages/en.php +++ b/languages/en.php @@ -105,6 +105,8 @@ $english = array( 'ElggPlugin:Dependencies:Priority:Before' => 'Before %s', 'ElggPlugin:Dependencies:Priority:Uninstalled' => '%s is not installed', 'ElggPlugin:Dependencies:Suggests:Unsatisfied' => 'Missing', + + 'ElggPlugin:Dependencies:ActiveDependent' => 'There are other plugins that list %s as a dependency. You must disable the following plugins before disabling this one: %s', 'ElggPlugin:InvalidAndDeactivated' => '%s is an invalid plugin and has been deactivated.', -- cgit v1.2.3 From 634216f0978d037fb84ef8e68e4e4272752c22fb Mon Sep 17 00:00:00 2001 From: beck24 Date: Sun, 13 Oct 2013 00:19:46 -0700 Subject: whitespace fix --- engine/lib/plugins.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'engine') diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php index f0d89e92d..e0aa705bb 100644 --- a/engine/lib/plugins.php +++ b/engine/lib/plugins.php @@ -1105,13 +1105,13 @@ function plugins_test($hook, $type, $value, $params) { } 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(); + $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) { + foreach ($active_plugins as $plugin) { $manifest = $plugin->getManifest(); $requires = $manifest->getRequires(); @@ -1121,9 +1121,9 @@ function plugins_deactivate_dependency_check($event, $type, $params) { $dependents[$manifest->getPluginID()] = $plugin; } } - } - - if ($dependents) { + } + + if ($dependents) { $list = '
    '; // construct error message and prevent disabling foreach ($dependents as $dependent) { -- cgit v1.2.3 From 6da43b70ca0de807c0532adb0bba65405d3ffbc1 Mon Sep 17 00:00:00 2001 From: beck24 Date: Sun, 13 Oct 2013 21:51:02 -0700 Subject: move deactivate event registration to the user-triggered action --- actions/admin/plugins/deactivate.php | 3 +++ engine/lib/plugins.php | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'engine') diff --git a/actions/admin/plugins/deactivate.php b/actions/admin/plugins/deactivate.php index 354f4717d..adb86dd7a 100644 --- a/actions/admin/plugins/deactivate.php +++ b/actions/admin/plugins/deactivate.php @@ -10,6 +10,9 @@ * @package Elgg.Core * @subpackage Administration.Plugins */ + + // prevent disabling plugins with active dependents + elgg_register_event_handler('deactivate', 'plugin', 'plugins_deactivate_dependency_check'); $plugin_guids = get_input('plugin_guids'); diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php index e0aa705bb..1b7ad5db9 100644 --- a/engine/lib/plugins.php +++ b/engine/lib/plugins.php @@ -1148,8 +1148,6 @@ function plugin_init() { run_function_once("plugin_run_once"); elgg_register_plugin_hook_handler('unit_test', 'system', 'plugins_test'); - - elgg_register_event_handler('deactivate', 'plugin', 'plugins_deactivate_dependency_check'); elgg_register_action("plugins/settings/save", '', 'admin'); elgg_register_action("plugins/usersettings/save"); -- cgit v1.2.3 From 5a3095d0664dc8c1fa81c7c2e6fac6a8dc8f0eaf Mon Sep 17 00:00:00 2001 From: Jerome Bakker Date: Tue, 22 Oct 2013 14:35:38 +0200 Subject: fixed a unittest I broke in #398 --- engine/tests/api/entity_getter_functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engine') diff --git a/engine/tests/api/entity_getter_functions.php b/engine/tests/api/entity_getter_functions.php index 0492b1fb0..fef9dc0c5 100644 --- a/engine/tests/api/entity_getter_functions.php +++ b/engine/tests/api/entity_getter_functions.php @@ -426,7 +426,7 @@ class ElggCoreEntityGetterFunctionsTest extends ElggCoreUnitTest { $options = array( 'types' => $types, - 'subtype' => $subtype + 'subtypes' => $subtype ); $es = elgg_get_entities($options); -- cgit v1.2.3 From 577201be6cff3dbe2a0ee6e35c9ab33a74a55f77 Mon Sep 17 00:00:00 2001 From: Jeroen Dalsem Date: Wed, 23 Oct 2013 15:11:11 +0200 Subject: fixed issue when reordering plugins to second last position of other column that has more than 2 widgets --- engine/classes/ElggWidget.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'engine') diff --git a/engine/classes/ElggWidget.php b/engine/classes/ElggWidget.php index c123e5032..66191bf47 100644 --- a/engine/classes/ElggWidget.php +++ b/engine/classes/ElggWidget.php @@ -146,10 +146,15 @@ class ElggWidget extends ElggObject { } } + $bottom_rank = count($widgets); + if ($column == $this->column) { + $bottom_rank--; + } + if ($rank == 0) { // top of the column $this->order = reset($widgets)->order - 10; - } elseif ($rank == (count($widgets) - 1)) { + } elseif ($rank == $bottom_rank) { // bottom of the column of active widgets $this->order = end($widgets)->order + 10; } else { -- cgit v1.2.3 From 424eff09557bf5e0cee7f0c1a717b3992d2e82ac Mon Sep 17 00:00:00 2001 From: Jerome Bakker Date: Wed, 23 Oct 2013 15:35:05 +0200 Subject: replaced all references to trac.elgg.org to the correct GitHub issues --- documentation/info/manifest.xml | 2 +- engine/classes/ElggAttributeLoader.php | 12 ++++++------ engine/classes/ElggEntity.php | 12 ++++++------ engine/lib/database.php | 12 ++++++------ engine/lib/entities.php | 2 +- engine/lib/upgrade.php | 2 +- engine/lib/upgrades/2010033101.php | 2 +- ...012041801-1.8.3-multiple_user_tokens-852225f7fd89f6c5.php | 2 +- engine/lib/views.php | 2 +- engine/tests/api/helpers.php | 2 +- engine/tests/api/metadata.php | 2 +- engine/tests/api/plugins.php | 4 ++-- engine/tests/objects/entities.php | 2 +- engine/tests/objects/objects.php | 2 +- engine/tests/regression/trac_bugs.php | 10 +++++----- engine/tests/test_files/plugin_18/manifest.xml | 2 +- mod/search/README.txt | 2 +- upgrade.php | 2 +- views/default/js/elgg.php | 2 +- 19 files changed, 39 insertions(+), 39 deletions(-) (limited to 'engine') diff --git a/documentation/info/manifest.xml b/documentation/info/manifest.xml index 494158481..4fd4be8ce 100644 --- a/documentation/info/manifest.xml +++ b/documentation/info/manifest.xml @@ -7,7 +7,7 @@ This is a longer, more interesting description of my plugin, its features, and other important information. http://www.elgg.org/ https://github.com/Elgg/Elgg - http://trac.elgg.org + https://github.com/Elgg/Elgg/issues http://elgg.org/supporter.php (C) Elgg 2011 GNU General Public License version 2 diff --git a/engine/classes/ElggAttributeLoader.php b/engine/classes/ElggAttributeLoader.php index 0b770da75..ffc80b02d 100644 --- a/engine/classes/ElggAttributeLoader.php +++ b/engine/classes/ElggAttributeLoader.php @@ -4,7 +4,7 @@ * Loads ElggEntity attributes from DB or validates those passed in via constructor * * @access private - * + * * @package Elgg.Core * @subpackage DataModel */ @@ -69,7 +69,7 @@ class ElggAttributeLoader { /** * Constructor - * + * * @param string $class class of object being loaded * @param string $required_type entity type this is being used to populate * @param array $initialized_attrs attributes after initializeAttributes() has been run @@ -94,7 +94,7 @@ class ElggAttributeLoader { /** * Get primary attributes missing that are missing - * + * * @param stdClass $row Database row * @return array */ @@ -104,7 +104,7 @@ class ElggAttributeLoader { /** * Get secondary attributes that are missing - * + * * @param stdClass $row Database row * @return array */ @@ -114,7 +114,7 @@ class ElggAttributeLoader { /** * Check that the type is correct - * + * * @param stdClass $row Database row * @return void * @throws InvalidClassException @@ -216,7 +216,7 @@ class ElggAttributeLoader { // Note: If there are still missing attributes, we're running on a 1.7 or earlier schema. We let // this pass so the upgrades can run. - // guid needs to be an int http://trac.elgg.org/ticket/4111 + // guid needs to be an int https://github.com/elgg/elgg/issues/4111 $row['guid'] = (int) $row['guid']; return $row; diff --git a/engine/classes/ElggEntity.php b/engine/classes/ElggEntity.php index dd1c7c114..a563f6fad 100644 --- a/engine/classes/ElggEntity.php +++ b/engine/classes/ElggEntity.php @@ -24,7 +24,7 @@ * * @package Elgg.Core * @subpackage DataModel.Entities - * + * * @property string $type object, user, group, or site (read-only after save) * @property string $subtype Further clarifies the nature of the entity (read-only after save) * @property int $guid The unique identifier for this entity (read only) @@ -352,8 +352,8 @@ abstract class ElggEntity extends ElggData implements 'limit' => 0 ); // @todo in 1.9 make this return false if can't add metadata - // http://trac.elgg.org/ticket/4520 - // + // https://github.com/elgg/elgg/issues/4520 + // // need to remove access restrictions right now to delete // because this is the expected behavior $ia = elgg_set_ignore_access(true); @@ -379,7 +379,7 @@ abstract class ElggEntity extends ElggData implements // unsaved entity. store in temp array // returning single entries instead of an array of 1 element is decided in // getMetaData(), just like pulling from the db. - // + // // if overwrite, delete first if (!$multiple || !isset($this->temp_metadata[$name])) { $this->temp_metadata[$name] = array(); @@ -964,7 +964,7 @@ abstract class ElggEntity extends ElggData implements * * @tip Can be overridden by registering for the permissions_check:comment, * plugin hook. - * + * * @param int $user_guid User guid (default is logged in user) * * @return bool @@ -1365,7 +1365,7 @@ abstract class ElggEntity extends ElggData implements $this->attributes['tables_loaded']++; } - // guid needs to be an int http://trac.elgg.org/ticket/4111 + // guid needs to be an int https://github.com/elgg/elgg/issues/4111 $this->attributes['guid'] = (int)$this->attributes['guid']; // Cache object handle diff --git a/engine/lib/database.php b/engine/lib/database.php index 37dfb8f8d..a7949788d 100644 --- a/engine/lib/database.php +++ b/engine/lib/database.php @@ -129,7 +129,7 @@ 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)) { // @todo if we keep this cache in 1.9, expose the size as a config parameter - $DB_QUERY_CACHE = new ElggLRUCache(200); + $DB_QUERY_CACHE = new ElggLRUCache(200); } } @@ -399,14 +399,14 @@ function elgg_query_runner($query, $callback = null, $single = false) { // 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. - // http://trac.elgg.org/ticket/4049 + // https://github.com/elgg/elgg/issues/4049 $hash = (string)$callback . (int)$single . $query; // Is cached? if ($DB_QUERY_CACHE) { if (isset($DB_QUERY_CACHE[$hash])) { elgg_log("DB query $query results returned from cache (hash: $hash)", 'NOTICE'); - return $DB_QUERY_CACHE[$hash]; + return $DB_QUERY_CACHE[$hash]; } } @@ -524,7 +524,7 @@ function delete_data($query) { /** * Invalidate the query cache - * + * * @access private */ function _elgg_invalidate_query_cache() { @@ -533,7 +533,7 @@ function _elgg_invalidate_query_cache() { $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 + // In case someone sets the cache to an array and primes it with data $DB_QUERY_CACHE = array(); elgg_log("Query cache invalidated", 'NOTICE'); } @@ -668,7 +668,7 @@ function run_sql_script($scriptlocation) { /** * Format a query string for logging - * + * * @param string $query Query string * @return string * @access private diff --git a/engine/lib/entities.php b/engine/lib/entities.php index 997db79d2..4fcf1c657 100644 --- a/engine/lib/entities.php +++ b/engine/lib/entities.php @@ -791,7 +791,7 @@ function get_entity($guid) { if ($shared_cache) { $cached_entity = $shared_cache->load($guid); - // @todo store ACLs in memcache http://trac.elgg.org/ticket/3018#comment:3 + // @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; diff --git a/engine/lib/upgrade.php b/engine/lib/upgrade.php index 0cc1e64dc..158ec9ec1 100644 --- a/engine/lib/upgrade.php +++ b/engine/lib/upgrade.php @@ -245,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 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 @@ container_guid); diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php index 10216140f..414fb4145 100644 --- a/engine/tests/api/helpers.php +++ b/engine/tests/api/helpers.php @@ -519,7 +519,7 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $this->assertIdentical($elements_sorted_string, $test_elements); } - // see http://trac.elgg.org/ticket/4288 + // see https://github.com/elgg/elgg/issues/4288 public function testElggBatchIncOffset() { // normal increment $options = array( diff --git a/engine/tests/api/metadata.php b/engine/tests/api/metadata.php index 0862341c1..d23510c6a 100644 --- a/engine/tests/api/metadata.php +++ b/engine/tests/api/metadata.php @@ -139,7 +139,7 @@ class ElggCoreMetadataAPITest extends ElggCoreUnitTest { // Make sure metadata with multiple values is correctly deleted when re-written // by another user - // http://trac.elgg.org/ticket/2776 + // https://github.com/elgg/elgg/issues/2776 public function test_elgg_metadata_multiple_values() { $u1 = new ElggUser(); $u1->username = rand(); diff --git a/engine/tests/api/plugins.php b/engine/tests/api/plugins.php index 114f3991b..d0f111c48 100644 --- a/engine/tests/api/plugins.php +++ b/engine/tests/api/plugins.php @@ -69,7 +69,7 @@ class ElggCorePluginsAPITest extends ElggCoreUnitTest { 'description' => 'A longer, more interesting description.', 'website' => 'http://www.elgg.org/', 'repository' => 'https://github.com/Elgg/Elgg', - 'bugtracker' => 'http://trac.elgg.org', + 'bugtracker' => 'https://github.com/elgg/elgg/issues', 'donations' => 'http://elgg.org/supporter.php', 'copyright' => '(C) Elgg Foundation 2011', 'license' => 'GNU General Public License version 2', @@ -174,7 +174,7 @@ class ElggCorePluginsAPITest extends ElggCoreUnitTest { } public function testElggPluginManifestGetBugtracker() { - $this->assertEqual($this->manifest18->getBugTrackerURL(), 'http://trac.elgg.org'); + $this->assertEqual($this->manifest18->getBugTrackerURL(), 'https://github.com/elgg/elgg/issues'); $this->assertEqual($this->manifest17->getBugTrackerURL(), ''); } diff --git a/engine/tests/objects/entities.php b/engine/tests/objects/entities.php index 248b85c9e..bac72079e 100644 --- a/engine/tests/objects/entities.php +++ b/engine/tests/objects/entities.php @@ -271,7 +271,7 @@ class ElggCoreEntityTest extends ElggCoreUnitTest { $this->save_entity(); // test deleting incorrectly - // @link http://trac.elgg.org/ticket/2273 + // @link https://github.com/elgg/elgg/issues/2273 $this->assertNull($this->entity->deleteMetadata('impotent')); $this->assertEqual($this->entity->important, 'indeed!'); diff --git a/engine/tests/objects/objects.php b/engine/tests/objects/objects.php index 915594e0a..263ab2414 100644 --- a/engine/tests/objects/objects.php +++ b/engine/tests/objects/objects.php @@ -194,7 +194,7 @@ class ElggCoreObjectTest extends ElggCoreUnitTest { $old = elgg_set_ignore_access(true); } - // see http://trac.elgg.org/ticket/1196 + // see https://github.com/elgg/elgg/issues/1196 public function testElggEntityRecursiveDisableWhenLoggedOut() { $e1 = new ElggObject(); $e1->access_id = ACCESS_PUBLIC; diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php index f173b5b9f..9372b0855 100644 --- a/engine/tests/regression/trac_bugs.php +++ b/engine/tests/regression/trac_bugs.php @@ -201,8 +201,8 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest { } /** - * http://trac.elgg.org/ticket/3210 - Don't remove -s in friendly titles - * http://trac.elgg.org/ticket/2276 - improve char encoding + * https://github.com/elgg/elgg/issues/3210 - Don't remove -s in friendly titles + * https://github.com/elgg/elgg/issues/2276 - improve char encoding */ public function test_friendly_title() { $cases = array( @@ -216,7 +216,7 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest { => "a-a-a-a-a-a-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // separators trimmed - "-_ hello _-" + "-_ hello _-" => "hello", // accents removed, lower case, other multibyte chars are URL encoded @@ -286,7 +286,7 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest { 'web archive anchor google' => 'web archive anchor google', - 'single quotes already anchor yahoo' => + 'single quotes already anchor yahoo' => 'single quotes already anchor yahoo', 'unquoted already anchor yahoo' => @@ -302,7 +302,7 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest { /** * Ensure additional select columns do not end up in entity attributes. - * + * * https://github.com/Elgg/Elgg/issues/5538 */ public function test_extra_columns_dont_appear_in_attributes() { diff --git a/engine/tests/test_files/plugin_18/manifest.xml b/engine/tests/test_files/plugin_18/manifest.xml index 5d788616a..c8b407511 100644 --- a/engine/tests/test_files/plugin_18/manifest.xml +++ b/engine/tests/test_files/plugin_18/manifest.xml @@ -7,7 +7,7 @@ A longer, more interesting description. http://www.elgg.org/ https://github.com/Elgg/Elgg - http://trac.elgg.org + https://github.com/elgg/elgg/issues http://elgg.org/supporter.php (C) Elgg Foundation 2011 GNU General Public License version 2 diff --git a/mod/search/README.txt b/mod/search/README.txt index 98a002dd5..ac5930e5f 100644 --- a/mod/search/README.txt +++ b/mod/search/README.txt @@ -273,4 +273,4 @@ MySQL's fulltext engine returns *ZERO* rows if more than 50% of the rows searched match. The default search hooks for users and groups ignore subtypes. -See [trac ticket 1499](http://trac.elgg.org/elgg/ticket/1499) +See [GitHub issue 1499](https://github.com/elgg/elgg/issues/1499) diff --git a/upgrade.php b/upgrade.php index c5f158c61..d07b2a1da 100644 --- a/upgrade.php +++ b/upgrade.php @@ -46,7 +46,7 @@ if (get_input('upgrade') == 'upgrade') { } else { // if upgrading from < 1.8.0, check for the core view 'welcome' and bail if it's found. - // see http://trac.elgg.org/ticket/3064 + // see https://github.com/elgg/elgg/issues/3064 // we're not checking the view itself because it's likely themes will override this view. // we're only concerned with core files. $welcome = dirname(__FILE__) . '/views/default/welcome.php'; diff --git a/views/default/js/elgg.php b/views/default/js/elgg.php index 6fe03484d..c3b56e398 100644 --- a/views/default/js/elgg.php +++ b/views/default/js/elgg.php @@ -43,7 +43,7 @@ $libs = array( foreach ($libs as $file) { include("{$CONFIG->path}js/lib/$file.js"); - // putting a new line between the files to address http://trac.elgg.org/ticket/3081 + // putting a new line between the files to address https://github.com/elgg/elgg/issues/3081 echo "\n"; } -- cgit v1.2.3 From 0deb80da1e82af55bf8d7500d09b36225ddd7927 Mon Sep 17 00:00:00 2001 From: Jerome Bakker Date: Wed, 23 Oct 2013 16:03:08 +0200 Subject: found some more references to trac --- engine/lib/elgglib.php | 4 ++-- engine/lib/views.php | 4 ++-- engine/tests/objects/users.php | 2 +- engine/tests/regression/trac_bugs.php | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'engine') diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index b5ef7e572..c95e0c28c 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -1350,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'); @@ -2249,7 +2249,7 @@ function elgg_api_test($hook, $type, $value, $params) { * * @warning ACCESS_DEFAULT is a place holder for the input/access view. Do not * use it when saving an entity. - * + * * @var int */ define('ACCESS_DEFAULT', -1); diff --git a/engine/lib/views.php b/engine/lib/views.php index dc69395c6..fff3581cf 100644 --- a/engine/lib/views.php +++ b/engine/lib/views.php @@ -369,7 +369,7 @@ 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. @@ -795,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 diff --git a/engine/tests/objects/users.php b/engine/tests/objects/users.php index 7d2ef6961..8a1033ac4 100644 --- a/engine/tests/objects/users.php +++ b/engine/tests/objects/users.php @@ -145,7 +145,7 @@ class ElggCoreUserTest extends ElggCoreUnitTest { } public function testElggUserNameCache() { - // Trac #1305 + // issue https://github.com/elgg/elgg/issues/1305 // very unlikely a user would have this username $name = (string)time(); diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php index 9372b0855..f823825ab 100644 --- a/engine/tests/regression/trac_bugs.php +++ b/engine/tests/regression/trac_bugs.php @@ -1,7 +1,7 @@ Date: Wed, 23 Oct 2013 23:42:30 -0700 Subject: Revert "move deactivate event registration to the user-triggered action" This reverts commit 6da43b70ca0de807c0532adb0bba65405d3ffbc1. --- actions/admin/plugins/deactivate.php | 3 --- engine/lib/plugins.php | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'engine') diff --git a/actions/admin/plugins/deactivate.php b/actions/admin/plugins/deactivate.php index adb86dd7a..354f4717d 100644 --- a/actions/admin/plugins/deactivate.php +++ b/actions/admin/plugins/deactivate.php @@ -10,9 +10,6 @@ * @package Elgg.Core * @subpackage Administration.Plugins */ - - // prevent disabling plugins with active dependents - elgg_register_event_handler('deactivate', 'plugin', 'plugins_deactivate_dependency_check'); $plugin_guids = get_input('plugin_guids'); diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php index 1b7ad5db9..e0aa705bb 100644 --- a/engine/lib/plugins.php +++ b/engine/lib/plugins.php @@ -1148,6 +1148,8 @@ function plugin_init() { run_function_once("plugin_run_once"); elgg_register_plugin_hook_handler('unit_test', 'system', 'plugins_test'); + + elgg_register_event_handler('deactivate', 'plugin', 'plugins_deactivate_dependency_check'); elgg_register_action("plugins/settings/save", '', 'admin'); elgg_register_action("plugins/usersettings/save"); -- cgit v1.2.3 From 9762edd4305ab8e6523d2f8171a32688295f1c88 Mon Sep 17 00:00:00 2001 From: Matt Beckett Date: Wed, 23 Oct 2013 23:52:53 -0700 Subject: Added comments regarding deactivation due to error --- engine/lib/plugins.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'engine') diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php index e0aa705bb..c296346fc 100644 --- a/engine/lib/plugins.php +++ b/engine/lib/plugins.php @@ -1149,6 +1149,8 @@ function plugin_init() { 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'); -- cgit v1.2.3 From 1e884c6abe933468ecfa035780bd3e9ff5e1ad61 Mon Sep 17 00:00:00 2001 From: Matt Beckett Date: Thu, 10 Oct 2013 13:29:50 -0700 Subject: #5952 - fix infinite loop when disabling > 50 annotations or metadata --- engine/lib/annotations.php | 6 +++++- engine/lib/metadata.php | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'engine') diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php index 124e67e0f..5e9b530de 100644 --- a/engine/lib/annotations.php +++ b/engine/lib/annotations.php @@ -249,9 +249,13 @@ 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['metastring_type'] = 'annotations'; - return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', false); + return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', $inc_offset); } /** diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php index d2f8d4cd4..fdb1b85f6 100644 --- a/engine/lib/metadata.php +++ b/engine/lib/metadata.php @@ -333,9 +333,13 @@ function elgg_disable_metadata(array $options) { } 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', false); + return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', $inc_offset); } /** -- cgit v1.2.3 From 8a79dc3904a2fda8081216fdf52be6a462db2709 Mon Sep 17 00:00:00 2001 From: Paweł Sroka Date: Sun, 27 Oct 2013 12:17:05 +0100 Subject: Refs #5952 - Added test --- engine/tests/regression/trac_bugs.php | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'engine') diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php index f823825ab..ef1348cf6 100644 --- a/engine/tests/regression/trac_bugs.php +++ b/engine/tests/regression/trac_bugs.php @@ -332,4 +332,45 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest { $group->delete(); } + + /** + * Ensure that ElggBatch doesn't go into infinite loop when disabling annotations recursively when show hidden is enabled. + * + * https://github.com/Elgg/Elgg/issues/5952 + */ + public function test_disabling_annotations_infinite_loop() { + + //let's have some entity + $group = new ElggGroup(); + $group->name = 'test_group'; + $group->access_id = ACCESS_PUBLIC; + $this->assertTrue($group->save() !== false); + + $total = 51; + //add some annotations + for ($cnt = 0; $cnt < $total; $cnt++) { + $group->annotate('test_annotation', 'value_' . $total); + } + + //disable them + $show_hidden = access_get_show_hidden_status(); + access_show_hidden_entities(true); + $options = array( + 'guid' => $group->guid, + 'limit' => $total, //using strict limit to avoid real infinite loop and just see ElggBatch limiting on it before finishing the work + ); + elgg_disable_annotations($options); + access_show_hidden_entities($show_hidden); + + //confirm all being disabled + $annotations = $group->getAnnotations(array( + 'limit' => $total, + )); + foreach ($annotations as $annotation) { + $this->assertTrue($annotation->enabled == 'no'); + } + + //delete group and annotations + $group->delete(); + } } -- cgit v1.2.3 From 61d049487a4f1a72f79f8c49bb65ffa82825e378 Mon Sep 17 00:00:00 2001 From: Paweł Sroka Date: Sun, 27 Oct 2013 13:28:16 +0100 Subject: Refs #6172 - Fixed one more trac mention --- engine/lib/elgglib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engine') diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index c95e0c28c..34111c69d 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -746,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. -- cgit v1.2.3 From 33260fd7a88e5e92fbee6ee0719ab4286e9ce221 Mon Sep 17 00:00:00 2001 From: Paweł Sroka Date: Sun, 27 Oct 2013 19:27:14 +0100 Subject: Refs #6117 - Added docs + changed plugins_deactivate_dependency_check to _plugins_deactivate_dependency_check --- engine/lib/plugins.php | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'engine') diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php index c296346fc..d5d3db466 100644 --- a/engine/lib/plugins.php +++ b/engine/lib/plugins.php @@ -1104,7 +1104,17 @@ function plugins_test($hook, $type, $value, $params) { return $value; } -function plugins_deactivate_dependency_check($event, $type, $params) { +/** + * 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(); @@ -1114,7 +1124,7 @@ function plugins_deactivate_dependency_check($event, $type, $params) { 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 @@ -1130,11 +1140,11 @@ function plugins_deactivate_dependency_check($event, $type, $params) { $list .= '
  • ' . $dependent->getManifest()->getName() . '
  • '; } $list .= '
'; - + register_error(elgg_echo('ElggPlugin:Dependencies:ActiveDependent', array($plugin_name, $list))); - + return false; - } + } } /** @@ -1151,7 +1161,7 @@ function plugin_init() { // 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_event_handler('deactivate', 'plugin', '_plugins_deactivate_dependency_check'); elgg_register_action("plugins/settings/save", '', 'admin'); elgg_register_action("plugins/usersettings/save"); -- cgit v1.2.3 From d53447f7e6b3277f3249d9a70e56ec01a90c3a60 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Thu, 11 Jul 2013 13:24:01 -0400 Subject: Disable loading external entities during XML parsing --- engine/classes/ElggAutoP.php | 14 ++++++++++++++ engine/classes/ElggXMLElement.php | 8 ++++++-- engine/tests/regression/trac_bugs.php | 10 ++++++++++ engine/tests/test_files/xxe/external_entity.txt | 1 + engine/tests/test_files/xxe/request.xml | 8 ++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 engine/tests/test_files/xxe/external_entity.txt create mode 100644 engine/tests/test_files/xxe/request.xml (limited to 'engine') diff --git a/engine/classes/ElggAutoP.php b/engine/classes/ElggAutoP.php index 71536c433..05842d1b2 100644 --- a/engine/classes/ElggAutoP.php +++ b/engine/classes/ElggAutoP.php @@ -110,12 +110,19 @@ class ElggAutoP { // http://www.php.net/manual/en/domdocument.loadhtml.php#95463 libxml_use_internal_errors(true); + // Do not load entities. May be unnecessary, better safe than sorry + $disable_load_entities = libxml_disable_entity_loader(true); + if (!$this->_doc->loadHTML("{$html}" . "")) { + + libxml_disable_entity_loader($disable_load_entities); return false; } + libxml_disable_entity_loader($disable_load_entities); + $this->_xpath = new DOMXPath($this->_doc); // start processing recursively at the BODY element $nodeList = $this->_xpath->query('//body[1]'); @@ -135,9 +142,16 @@ class ElggAutoP { // re-parse so we can handle new AUTOP elements + // Do not load entities. May be unnecessary, better safe than sorry + $disable_load_entities = libxml_disable_entity_loader(true); + if (!$this->_doc->loadHTML($html)) { + libxml_disable_entity_loader($disable_load_entities); return false; } + + libxml_disable_entity_loader($disable_load_entities); + // must re-create XPath object after DOM load $this->_xpath = new DOMXPath($this->_doc); diff --git a/engine/classes/ElggXMLElement.php b/engine/classes/ElggXMLElement.php index 6f2633e25..cbd3fc5ce 100644 --- a/engine/classes/ElggXMLElement.php +++ b/engine/classes/ElggXMLElement.php @@ -20,7 +20,12 @@ class ElggXMLElement { if ($xml instanceof SimpleXMLElement) { $this->_element = $xml; } else { + // do not load entities + $disable_load_entities = libxml_disable_entity_loader(true); + $this->_element = new SimpleXMLElement($xml); + + libxml_disable_entity_loader($disable_load_entities); } } @@ -123,5 +128,4 @@ class ElggXMLElement { } return false; } - -} \ No newline at end of file +} diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php index ef1348cf6..e6773c8af 100644 --- a/engine/tests/regression/trac_bugs.php +++ b/engine/tests/regression/trac_bugs.php @@ -373,4 +373,14 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest { //delete group and annotations $group->delete(); } + + public function test_ElggXMLElement_does_not_load_external_entities() { + $payload = file_get_contents(dirname(dirname(__FILE__)) . '/test_files/xxe/request.xml'); + $payload = sprintf($payload, 'file://' . realpath(dirname(dirname(__FILE__)) . '/test_files/xxe/external_entity.txt')); + + $el = new ElggXMLElement($payload); + $chidren = $el->getChildren(); + $content = $chidren[0]->getContent(); + $this->assertNoPattern('/secret/', $content); + } } diff --git a/engine/tests/test_files/xxe/external_entity.txt b/engine/tests/test_files/xxe/external_entity.txt new file mode 100644 index 000000000..536aca34d --- /dev/null +++ b/engine/tests/test_files/xxe/external_entity.txt @@ -0,0 +1 @@ +secret \ No newline at end of file diff --git a/engine/tests/test_files/xxe/request.xml b/engine/tests/test_files/xxe/request.xml new file mode 100644 index 000000000..4390f9db2 --- /dev/null +++ b/engine/tests/test_files/xxe/request.xml @@ -0,0 +1,8 @@ + + + +]> + + test&xxe;test + -- cgit v1.2.3 From 6eec301f33ff3e618d591d429de7edf30277e972 Mon Sep 17 00:00:00 2001 From: Paweł Sroka Date: Tue, 23 Jul 2013 08:28:30 +0200 Subject: Enhanced test --- engine/tests/regression/trac_bugs.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'engine') diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php index e6773c8af..ea39253df 100644 --- a/engine/tests/regression/trac_bugs.php +++ b/engine/tests/regression/trac_bugs.php @@ -375,12 +375,26 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest { } public function test_ElggXMLElement_does_not_load_external_entities() { + $elLast = libxml_disable_entity_loader(false); + $payload = file_get_contents(dirname(dirname(__FILE__)) . '/test_files/xxe/request.xml'); - $payload = sprintf($payload, 'file://' . realpath(dirname(dirname(__FILE__)) . '/test_files/xxe/external_entity.txt')); + $path = realpath(dirname(dirname(__FILE__)) . '/test_files/xxe/external_entity.txt'); + $path = str_replace('\\', '/', $path); + if ($path[0] != '/') { + $path = '/' . $path; + } + $path = 'file://' . $path; + $payload = sprintf($payload, $path); $el = new ElggXMLElement($payload); $chidren = $el->getChildren(); $content = $chidren[0]->getContent(); $this->assertNoPattern('/secret/', $content); + + //make sure the test is valid + $element = new SimpleXMLElement($payload); + $this->assertPattern('/secret/', (string)$element->methodName); + + libxml_disable_entity_loader($elLast); } } -- cgit v1.2.3 From 7cacdc8bc26c98a58dc8986acfd911d6542608af Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Wed, 31 Jul 2013 13:34:55 -0400 Subject: Emit notice if XXE can't be tested and skip test --- engine/tests/regression/trac_bugs.php | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'engine') diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php index ea39253df..689275661 100644 --- a/engine/tests/regression/trac_bugs.php +++ b/engine/tests/regression/trac_bugs.php @@ -377,6 +377,7 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest { public function test_ElggXMLElement_does_not_load_external_entities() { $elLast = libxml_disable_entity_loader(false); + // build payload that should trigger loading of external entity $payload = file_get_contents(dirname(dirname(__FILE__)) . '/test_files/xxe/request.xml'); $path = realpath(dirname(dirname(__FILE__)) . '/test_files/xxe/external_entity.txt'); $path = str_replace('\\', '/', $path); @@ -384,16 +385,20 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest { $path = '/' . $path; } $path = 'file://' . $path; - $payload = sprintf($payload, $path); + $payload = sprintf($payload, $path); - $el = new ElggXMLElement($payload); - $chidren = $el->getChildren(); - $content = $chidren[0]->getContent(); - $this->assertNoPattern('/secret/', $content); - - //make sure the test is valid + // make sure we can actually this in this environment $element = new SimpleXMLElement($payload); - $this->assertPattern('/secret/', (string)$element->methodName); + $can_load_entity = preg_match('/secret/', (string)$element->methodName); + + $this->skipUnless($can_load_entity, "XXE vulnerability cannot be tested on this system"); + + if ($can_load_entity) { + $el = new ElggXMLElement($payload); + $chidren = $el->getChildren(); + $content = $chidren[0]->getContent(); + $this->assertNoPattern('/secret/', $content); + } libxml_disable_entity_loader($elLast); } -- cgit v1.2.3 From e98f933857548be9cd078416a93011ea9c2f3e3a Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Mon, 10 Jun 2013 23:16:45 -0400 Subject: Allow regenerating site secret --- actions/admin/site/regenerate_secret.php | 11 ++ engine/classes/ElggCrypto.php | 134 +++++++++++++++++++++ engine/lib/actions.php | 27 ++++- engine/lib/admin.php | 2 + ...3060900-1.8.15-site_secret-404fc165cf9e0ac9.php | 13 ++ languages/en.php | 18 ++- .../admin/settings/advanced/site_secret.php | 11 ++ views/default/css/admin.php | 20 +++ .../default/forms/admin/site/regenerate_secret.php | 24 ++++ 9 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 actions/admin/site/regenerate_secret.php create mode 100644 engine/classes/ElggCrypto.php create mode 100644 engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php create mode 100644 views/default/admin/settings/advanced/site_secret.php create mode 100644 views/default/forms/admin/site/regenerate_secret.php (limited to 'engine') diff --git a/actions/admin/site/regenerate_secret.php b/actions/admin/site/regenerate_secret.php new file mode 100644 index 000000000..3112fb5f3 --- /dev/null +++ b/actions/admin/site/regenerate_secret.php @@ -0,0 +1,11 @@ +='); + } + // /dev/urandom is available on many *nix systems and is considered the + // best commonly available pseudo-random source. + if ($fh = @fopen('/dev/urandom', 'rb')) { + // PHP only performs buffered reads, so in reality it will always read + // at least 4096 bytes. Thus, it costs nothing extra to read and store + // that much so as to speed any additional invocations. + $bytes .= fread($fh, max(4096, $count)); + fclose($fh); + } elseif ($php_compatible && function_exists('openssl_random_pseudo_bytes')) { + // openssl_random_pseudo_bytes() will find entropy in a system-dependent + // way. + $bytes .= openssl_random_pseudo_bytes($count - strlen($bytes)); + } + // If /dev/urandom is not available or returns no bytes, this loop will + // generate a good set of pseudo-random bytes on any system. + // Note that it may be important that our $random_state is passed + // through hash() prior to being rolled into $output, that the two hash() + // invocations are different, and that the extra input into the first one - + // the microtime() - is prepended rather than appended. This is to avoid + // directly leaking $random_state via the $output stream, which could + // allow for trivial prediction of further "random" numbers. + while (strlen($bytes) < $count) { + $random_state = hash('sha256', microtime() . mt_rand() . $random_state); + $bytes .= hash('sha256', mt_rand() . $random_state, true); + } + } + $output = substr($bytes, 0, $count); + $bytes = substr($bytes, $count); + return $output; + } + + /** + * Generate a random string of specified length. + * + * Uses supplied character list for generating the new string. + * If no character list provided - uses Base64 URL character set. + * + * @param int $length Desired length of the string + * @param string|null $chars Characters to be chosen from randomly. If not given, the Base64 URL + * charset will be used. + * + * @return string The random string + * + * @throws InvalidArgumentException + * + * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * + * @see https://github.com/zendframework/zf2/blob/master/library/Zend/Math/Rand.php#L179 + */ + public static function getRandomString($length, $chars = null) + { + if ($length < 1) { + throw new InvalidArgumentException('Length should be >= 1'); + } + + if (empty($chars)) { + $numBytes = ceil($length * 0.75); + $bytes = self::getRandomBytes($numBytes); + $string = substr(rtrim(base64_encode($bytes), '='), 0, $length); + + // Base64 URL + return strtr($string, '+/', '-_'); + } + + $listLen = strlen($chars); + + if ($listLen == 1) { + return str_repeat($chars, $length); + } + + $bytes = self::getRandomBytes($length); + $pos = 0; + $result = ''; + for ($i = 0; $i < $length; $i++) { + $pos = ($pos + ord($bytes[$i])) % $listLen; + $result .= $chars[$pos]; + } + + return $result; + } +} diff --git a/engine/lib/actions.php b/engine/lib/actions.php index 56936f582..8047914ac 100644 --- a/engine/lib/actions.php +++ b/engine/lib/actions.php @@ -364,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; } @@ -399,6 +402,26 @@ function get_site_secret() { return $secret; } +/** + * 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. * diff --git a/engine/lib/admin.php b/engine/lib/admin.php index 7f82108c0..f36f29668 100644 --- a/engine/lib/admin.php +++ b/engine/lib/admin.php @@ -236,6 +236,7 @@ function admin_init() { 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'); @@ -291,6 +292,7 @@ function admin_init() { 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 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..b5b614762 --- /dev/null +++ b/engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php @@ -0,0 +1,13 @@ + 'Settings', 'admin:settings:basic' => 'Basic Settings', 'admin:settings:advanced' => 'Advanced Settings', + 'admin:settings:advanced/site_secret' => 'Site Secret', 'admin:site:description' => "This admin panel allows you to control global settings for your site. Choose an option below to get started.", + 'admin:settings:advanced:site_secret' => 'Site Secret', 'admin:site:opt:linktext' => "Configure site...", 'admin:site:access:warning' => "Changing the access setting only affects the permissions on content created in the future.", + 'admin:site:secret:intro' => 'Elgg uses a key to create security tokens for various purposes.', + 'admin:site:secret_regenerated' => "Your site secret has been regenerated.", + 'admin:site:secret:regenerate' => "Regenerate site secret", + 'admin:site:secret:regenerate:help' => "Note: This may inconvenience some users by invalidating tokens used in \"remember me\" cookies, e-mail validation requests, invitation codes, etc.", + 'site_secret:current_strength' => 'Key Strength', + 'site_secret:strength:weak' => "Weak", + 'site_secret:strength_msg:weak' => "We strongly recommend that you regenerate your site secret.", + 'site_secret:strength:moderate' => "Moderate", + 'site_secret:strength_msg:moderate' => "We recommend you regenerate your site secret for the best site security.", + 'site_secret:strength:strong' => "Strong", + 'site_secret:strength_msg:strong' => "✓ Your site secret is sufficiently strong.", + 'admin:dashboard' => 'Dashboard', 'admin:widget:online_users' => 'Online users', 'admin:widget:online_users:help' => 'Lists the users currently on the site', @@ -1064,7 +1078,7 @@ Once you have logged in, we highly recommend that you change your password. 'upgrade:unlock' => 'Unlock upgrade', 'upgrade:unlock:confirm' => "The database is locked for another upgrade. Running concurrent upgrades is dangerous. You should only continue if you know there is not another upgrade running. Unlock?", 'upgrade:locked' => "Cannot upgrade. Another upgrade is running. To clear the upgrade lock, visit the Admin section.", - 'upgrade:unlock:success' => "Upgrade unlocked suscessfully.", + 'upgrade:unlock:success' => "Upgrade unlocked successfully.", 'upgrade:unable_to_upgrade' => 'Unable to upgrade.', 'upgrade:unable_to_upgrade_info' => 'This installation cannot be upgraded because legacy views @@ -1079,6 +1093,8 @@ Once you have logged in, we highly recommend that you change your password. 'update:twitter_api:deactivated' => 'Twitter API (previously Twitter Service) was deactivated during the upgrade. Please activate it manually if required.', 'update:oauth_api:deactivated' => 'OAuth API (previously OAuth Lib) was deactivated during the upgrade. Please activate it manually if required.', + 'upgrade:site_secret_warning:moderate' => "You are encouraged to regenerate your site key to improve system security. See Configure > Site Secret", + 'upgrade:site_secret_warning:weak' => "You are strongly encouraged to regenerate your site key to improve system security. See Configure > Site Secret", 'deprecated:function' => '%s() was deprecated by %s()', diff --git a/views/default/admin/settings/advanced/site_secret.php b/views/default/admin/settings/advanced/site_secret.php new file mode 100644 index 000000000..e70ac7ab6 --- /dev/null +++ b/views/default/admin/settings/advanced/site_secret.php @@ -0,0 +1,11 @@ + _elgg_get_site_secret_strength(), +)); diff --git a/views/default/css/admin.php b/views/default/css/admin.php index 3896ded5d..c435621b2 100644 --- a/views/default/css/admin.php +++ b/views/default/css/admin.php @@ -1543,6 +1543,26 @@ table.mceLayout { margin: 0 0 1em 2em; } +/* *************************************** + SITE SECRET +*************************************** */ +.elgg-form-admin-site-regenerate-secret table { + width: 60%; + margin: 1em auto; +} +td.elgg-strength-strong, +td.elgg-strength-strong h4 { + background: #DFF0D8; color: #468847; +} +td.elgg-strength-moderate, +td.elgg-strength-moderate h4 { + background: #FCF8E3; color: #C09853; +} +td.elgg-strength-weak, +td.elgg-strength-weak h4 { + background: #F2DEDE; color: #B94A48; +} + /* *************************************** HELPERS *************************************** */ diff --git a/views/default/forms/admin/site/regenerate_secret.php b/views/default/forms/admin/site/regenerate_secret.php new file mode 100644 index 000000000..af269b801 --- /dev/null +++ b/views/default/forms/admin/site/regenerate_secret.php @@ -0,0 +1,24 @@ + +

+ + + + + + +
+

+
+
+ +
+ elgg_echo('admin:site:secret:regenerate'), + 'class' => 'elgg-requires-confirmation elgg-button elgg-button-submit', + )); ?> +

+
-- cgit v1.2.3 From 4bcca223409915e075dd08f0aaca9f23ea63f610 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Thu, 13 Jun 2013 14:05:33 -0400 Subject: PRNG replace Drupal's with George Argyros' --- engine/classes/ElggCrypto.php | 181 +++++++++++++++++++++++++++++------------- 1 file changed, 128 insertions(+), 53 deletions(-) (limited to 'engine') diff --git a/engine/classes/ElggCrypto.php b/engine/classes/ElggCrypto.php index 364af4542..358b721ea 100644 --- a/engine/classes/ElggCrypto.php +++ b/engine/classes/ElggCrypto.php @@ -15,70 +15,145 @@ class ElggCrypto { const CHARS_PASSWORD = 'bcdfghjklmnpqrstvwxyz2346789'; /** - * Returns a string of highly randomized bytes (over the full 8-bit range). + * Generate a string of highly randomized bytes (over the full 8-bit range). * - * This function is better than simply calling mt_rand() or any other built-in - * PHP function because it can return a long string of bytes (compared to < 4 - * bytes normally from mt_rand()) and uses the best available pseudo-random - * source. + * @param int $length Number of bytes needed + * @return string Random bytes * - * @param int $count The number of characters (bytes) to return in the string. - * @return string + * @author George Argyros + * @copyright 2012, George Argyros. All rights reserved. + * @license Modified BSD + * @link https://github.com/GeorgeArgyros/Secure-random-bytes-in-PHP/blob/master/srand.php Original * - * @copyright Copyright 2001 - 2012 by the original authors - * https://github.com/drupal/drupal/blob/7.x/COPYRIGHT.txt - * @license https://github.com/drupal/drupal/blob/7.x/LICENSE.txt GPL 2 + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. * - * @see https://github.com/drupal/drupal/blob/7.x/includes/bootstrap.inc#L1942 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL GEORGE ARGYROS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - public static function getRandomBytes($count) { - // $random_state does not use drupal_static as it stores random bytes. - static $random_state, $bytes, $php_compatible; - // Initialize on the first call. The contents of $_SERVER includes a mix of - // user-specific and system information that varies a little with each page. - if (!isset($random_state)) { - $random_state = print_r($_SERVER, true); - if (function_exists('getmypid')) { - // Further initialize with the somewhat random PHP process ID. - $random_state .= getmypid(); + public function getRandomBytes($length) { + /** + * Our primary choice for a cryptographic strong randomness function is + * openssl_random_pseudo_bytes. + */ + $SSLstr = '4'; // http://xkcd.com/221/ + if (function_exists('openssl_random_pseudo_bytes') + && (version_compare(PHP_VERSION, '5.3.4') >= 0 || substr(PHP_OS, 0, 3) !== 'WIN')) { + $SSLstr = openssl_random_pseudo_bytes($length, $strong); + if ($strong) { + return $SSLstr; } - $bytes = ''; } - if (strlen($bytes) < $count) { - // PHP versions prior 5.3.4 experienced openssl_random_pseudo_bytes() - // locking on Windows and rendered it unusable. - if (!isset($php_compatible)) { - $php_compatible = version_compare(PHP_VERSION, '5.3.4', '>='); + + /** + * If mcrypt extension is available then we use it to gather entropy from + * the operating system's PRNG. This is better than reading /dev/urandom + * directly since it avoids reading larger blocks of data than needed. + * Older versions of mcrypt_create_iv may be broken or take too much time + * to finish so we only use this function with PHP 5.3.7 and above. + * @see https://bugs.php.net/bug.php?id=55169 + */ + if (function_exists('mcrypt_create_iv') + && (version_compare(PHP_VERSION, '5.3.7') >= 0 || substr(PHP_OS, 0, 3) !== 'WIN')) { + $str = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); + if ($str !== false) { + return $str; + } + } + + /** + * No build-in crypto randomness function found. We collect any entropy + * available in the PHP core PRNGs along with some filesystem info and memory + * stats. To make this data cryptographically strong we add data either from + * /dev/urandom or if its unavailable, we gather entropy by measuring the + * time needed to compute a number of SHA-1 hashes. + */ + $str = ''; + $bits_per_round = 2; // bits of entropy collected in each clock drift round + $msec_per_round = 400; // expected running time of each round in microseconds + $hash_len = 20; // SHA-1 Hash length + $total = $length; // total bytes of entropy to collect + + $handle = @fopen('/dev/urandom', 'rb'); + if ($handle && function_exists('stream_set_read_buffer')) { + @stream_set_read_buffer($handle, 0); + } + + do { + $bytes = ($total > $hash_len)? $hash_len : $total; + $total -= $bytes; + + //collect any entropy available from the PHP system and filesystem + $entropy = rand() . uniqid(mt_rand(), true) . $SSLstr; + $entropy .= implode('', @fstat(@fopen( __FILE__, 'r'))); + $entropy .= memory_get_usage() . getmypid(); + $entropy .= serialize($_ENV) . serialize($_SERVER); + if (function_exists('posix_times')) { + $entropy .= serialize(posix_times()); } - // /dev/urandom is available on many *nix systems and is considered the - // best commonly available pseudo-random source. - if ($fh = @fopen('/dev/urandom', 'rb')) { - // PHP only performs buffered reads, so in reality it will always read - // at least 4096 bytes. Thus, it costs nothing extra to read and store - // that much so as to speed any additional invocations. - $bytes .= fread($fh, max(4096, $count)); - fclose($fh); - } elseif ($php_compatible && function_exists('openssl_random_pseudo_bytes')) { - // openssl_random_pseudo_bytes() will find entropy in a system-dependent - // way. - $bytes .= openssl_random_pseudo_bytes($count - strlen($bytes)); + if (function_exists('zend_thread_id')) { + $entropy .= zend_thread_id(); } - // If /dev/urandom is not available or returns no bytes, this loop will - // generate a good set of pseudo-random bytes on any system. - // Note that it may be important that our $random_state is passed - // through hash() prior to being rolled into $output, that the two hash() - // invocations are different, and that the extra input into the first one - - // the microtime() - is prepended rather than appended. This is to avoid - // directly leaking $random_state via the $output stream, which could - // allow for trivial prediction of further "random" numbers. - while (strlen($bytes) < $count) { - $random_state = hash('sha256', microtime() . mt_rand() . $random_state); - $bytes .= hash('sha256', mt_rand() . $random_state, true); + + if ($handle) { + $entropy .= @fread($handle, $bytes); + } else { + // Measure the time that the operations will take on average + for ($i = 0; $i < 3; $i++) { + $c1 = microtime(true); + $var = sha1(mt_rand()); + for ($j = 0; $j < 50; $j++) { + $var = sha1($var); + } + $c2 = microtime(true); + $entropy .= $c1 . $c2; + } + + // Based on the above measurement determine the total rounds + // in order to bound the total running time. + $rounds = (int) ($msec_per_round * 50 / (int) (($c2 - $c1) * 1000000)); + + // Take the additional measurements. On average we can expect + // at least $bits_per_round bits of entropy from each measurement. + $iter = $bytes * (int) (ceil(8 / $bits_per_round)); + + for ($i = 0; $i < $iter; $i++) { + $c1 = microtime(); + $var = sha1(mt_rand()); + for ($j = 0; $j < $rounds; $j++) { + $var = sha1($var); + } + $c2 = microtime(); + $entropy .= $c1 . $c2; + } } + + // We assume sha1 is a deterministic extractor for the $entropy variable. + $str .= sha1($entropy, true); + + } while ($length > strlen($str)); + + if ($handle) { + @fclose($handle); } - $output = substr($bytes, 0, $count); - $bytes = substr($bytes, $count); - return $output; + + return substr($str, 0, $length); } /** -- cgit v1.2.3 From 003946eff06fcafe60db5894e1ade0abee7314b4 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Thu, 13 Jun 2013 14:10:35 -0400 Subject: code style --- engine/classes/ElggCrypto.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'engine') diff --git a/engine/classes/ElggCrypto.php b/engine/classes/ElggCrypto.php index 358b721ea..b6a8b2024 100644 --- a/engine/classes/ElggCrypto.php +++ b/engine/classes/ElggCrypto.php @@ -175,8 +175,7 @@ class ElggCrypto { * * @see https://github.com/zendframework/zf2/blob/master/library/Zend/Math/Rand.php#L179 */ - public static function getRandomString($length, $chars = null) - { + public static function getRandomString($length, $chars = null) { if ($length < 1) { throw new InvalidArgumentException('Length should be >= 1'); } -- cgit v1.2.3 From 76b7a8f78975098a5cd09f794feb34d4f7a4ee76 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Sun, 1 Dec 2013 21:50:20 -0500 Subject: Make sure new lang key available during upgrade --- engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'engine') 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 index b5b614762..538d74dd6 100644 --- a/engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php +++ b/engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php @@ -9,5 +9,8 @@ $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")); } -- cgit v1.2.3 From 47f209929b1913a73b8051d35d5545d28a37dba7 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Sun, 1 Dec 2013 21:56:48 -0500 Subject: Code style fixes in ElggCrypto --- engine/classes/ElggCrypto.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'engine') diff --git a/engine/classes/ElggCrypto.php b/engine/classes/ElggCrypto.php index b6a8b2024..317d371e4 100644 --- a/engine/classes/ElggCrypto.php +++ b/engine/classes/ElggCrypto.php @@ -96,12 +96,12 @@ class ElggCrypto { } do { - $bytes = ($total > $hash_len)? $hash_len : $total; + $bytes = ($total > $hash_len) ? $hash_len : $total; $total -= $bytes; //collect any entropy available from the PHP system and filesystem $entropy = rand() . uniqid(mt_rand(), true) . $SSLstr; - $entropy .= implode('', @fstat(@fopen( __FILE__, 'r'))); + $entropy .= implode('', @fstat(@fopen(__FILE__, 'r'))); $entropy .= memory_get_usage() . getmypid(); $entropy .= serialize($_ENV) . serialize($_SERVER); if (function_exists('posix_times')) { @@ -113,7 +113,7 @@ class ElggCrypto { if ($handle) { $entropy .= @fread($handle, $bytes); - } else { + } else { // Measure the time that the operations will take on average for ($i = 0; $i < 3; $i++) { $c1 = microtime(true); @@ -162,9 +162,9 @@ class ElggCrypto { * Uses supplied character list for generating the new string. * If no character list provided - uses Base64 URL character set. * - * @param int $length Desired length of the string - * @param string|null $chars Characters to be chosen from randomly. If not given, the Base64 URL - * charset will be used. + * @param int $length Desired length of the string + * @param string|null $chars Characters to be chosen from randomly. If not given, the Base64 URL + * charset will be used. * * @return string The random string * -- cgit v1.2.3 From beab3edd8f0b821b7e90e288add261342505321f Mon Sep 17 00:00:00 2001 From: Ed Lyons Date: Mon, 2 Dec 2013 06:34:08 -0500 Subject: Fix #6238 Return blank arrays I committed this simple change to return the empty array rather than false for empty settings result for ElggPlugin::getAllSettings and getAllUsersSettings. Put this into 1.8 branch. --- engine/classes/ElggPlugin.php | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'engine') diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php index 7bf6eb1df..81831d8cd 100644 --- a/engine/classes/ElggPlugin.php +++ b/engine/classes/ElggPlugin.php @@ -299,17 +299,16 @@ class ElggPlugin extends ElggObject { $private_settings = get_data($q); + $return = array(); + if ($private_settings) { - $return = array(); - + foreach ($private_settings as $setting) { $return[$setting->name] = $setting->value; } + } - return $return; - } - - return false; + return $return; } /** @@ -423,9 +422,10 @@ class ElggPlugin extends ElggObject { $private_settings = get_data($q); - if ($private_settings) { - $return = array(); - + $return = array(); + + if ($private_settings) { + foreach ($private_settings as $setting) { $name = substr($setting->name, $ps_prefix_len); $value = $setting->value; @@ -433,10 +433,9 @@ class ElggPlugin extends ElggObject { $return[$name] = $value; } - return $return; } - return false; + return $return; } /** -- cgit v1.2.3 From 908628e622d798c5036f7e25bc5b7d6d36d64754 Mon Sep 17 00:00:00 2001 From: Jerome Bakker Date: Mon, 2 Dec 2013 14:56:20 +0100 Subject: fixes #3143 login part --- engine/lib/memcache.php | 20 ++++++++++++++++++++ engine/lib/sessions.php | 6 ++++++ 2 files changed, 26 insertions(+) (limited to 'engine') 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/sessions.php b/engine/lib/sessions.php index fb28e1e9a..e3d5ce9cd 100644 --- a/engine/lib/sessions.php +++ b/engine/lib/sessions.php @@ -326,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; } -- cgit v1.2.3 From 63db31c0237d24247b3b75b8365d610be936c283 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Sat, 7 Dec 2013 19:27:18 -0500 Subject: Handle case if get_user_notification_settings() returns false --- engine/lib/notification.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'engine') diff --git a/engine/lib/notification.php b/engine/lib/notification.php index b6399b3c6..2506867d5 100644 --- a/engine/lib/notification.php +++ b/engine/lib/notification.php @@ -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_array($tmp)) { + foreach ($tmp as $k => $v) { + // Add method if method is turned on for user! + if ($v) { + $methods[] = $k; + } } } } -- cgit v1.2.3 From f4420e017f6dc2039e8e3910e5b98c0eb17a7be2 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Sat, 7 Dec 2013 20:27:32 -0500 Subject: Fixes #6012: Gets correct client IP behind proxy (1.8) --- engine/lib/system_log.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'engine') diff --git a/engine/lib/system_log.php b/engine/lib/system_log.php index 5a153afb2..bed863755 100644 --- a/engine/lib/system_log.php +++ b/engine/lib/system_log.php @@ -187,7 +187,11 @@ function system_log($object, $event) { $object_subtype = $object->getSubtype(); $event = sanitise_string($event); $time = time(); - $ip_address = sanitise_string($_SERVER['REMOTE_ADDR']); + if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $ip_address = array_pop(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])); + } else { + $ip_address = sanitise_string($_SERVER['REMOTE_ADDR']); + } $performed_by = elgg_get_logged_in_user_guid(); if (isset($object->access_id)) { -- cgit v1.2.3 From 5866c12f7b5cc7c9fa922324a26c419a66fc5ea3 Mon Sep 17 00:00:00 2001 From: Paweł Sroka Date: Sun, 8 Dec 2013 04:13:02 +0100 Subject: Checks X-Real-Ip header as well when determining client IP --- engine/lib/system_log.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'engine') diff --git a/engine/lib/system_log.php b/engine/lib/system_log.php index bed863755..84302632e 100644 --- a/engine/lib/system_log.php +++ b/engine/lib/system_log.php @@ -187,11 +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 = sanitise_string($_SERVER['REMOTE_ADDR']); + $ip_address = $_SERVER['REMOTE_ADDR']; } + $ip_address = sanitise_string($ip_address); + $performed_by = elgg_get_logged_in_user_guid(); if (isset($object->access_id)) { -- cgit v1.2.3 From 54d559f8ce84877f4dc2ccf84d00fd5047669d88 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Mon, 9 Dec 2013 09:26:28 -0500 Subject: Code style fixes for recent PR --- engine/classes/ElggPlugin.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'engine') diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php index 81831d8cd..545b9a53c 100644 --- a/engine/classes/ElggPlugin.php +++ b/engine/classes/ElggPlugin.php @@ -300,13 +300,12 @@ class ElggPlugin extends ElggObject { $private_settings = get_data($q); $return = array(); - + if ($private_settings) { - foreach ($private_settings as $setting) { $return[$setting->name] = $setting->value; } - } + } return $return; } @@ -423,16 +422,14 @@ class ElggPlugin extends ElggObject { $private_settings = get_data($q); $return = array(); - - if ($private_settings) { - + + if ($private_settings) { foreach ($private_settings as $setting) { $name = substr($setting->name, $ps_prefix_len); $value = $setting->value; $return[$name] = $value; } - } return $return; -- cgit v1.2.3 From c6ec6a0e01f50f72e742bbf20431f3f3aa04a2fa Mon Sep 17 00:00:00 2001 From: Paweł Sroka Date: Sat, 28 Dec 2013 18:55:36 +0100 Subject: Added missing @deprecated tags --- engine/lib/deprecated-1.7.php | 2 ++ engine/lib/deprecated-1.8.php | 2 ++ 2 files changed, 4 insertions(+) (limited to 'engine') 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 6aa42a81d..91068d047 100644 --- a/engine/lib/deprecated-1.8.php +++ b/engine/lib/deprecated-1.8.php @@ -3414,6 +3414,7 @@ function list_annotations($entity_guid, $name = "", $limit = 25, $asc = true) { * @param unknown_type $timeupper * @param unknown_type $calculation * @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, @@ -4667,6 +4668,7 @@ function display_widget(ElggObject $widget) { * * @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); -- cgit v1.2.3 From 2634e94664045e08b3960dc83487d6357ec081a7 Mon Sep 17 00:00:00 2001 From: Steve Clay Date: Mon, 6 Jan 2014 23:39:29 -0500 Subject: Fixes #6309: Fixes notify_user() broken by 63db31c --- engine/lib/notification.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engine') diff --git a/engine/lib/notification.php b/engine/lib/notification.php index 2506867d5..be0c359d4 100644 --- a/engine/lib/notification.php +++ b/engine/lib/notification.php @@ -113,7 +113,7 @@ function notify_user($to, $from, $subject, $message, array $params = NULL, $meth $tmp = get_user_notification_settings($guid); $methods = array(); // $tmp may be false. don't cast - if (is_array($tmp)) { + if (is_object($tmp)) { foreach ($tmp as $k => $v) { // Add method if method is turned on for user! if ($v) { @@ -168,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; -- cgit v1.2.3