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/classes') 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/classes') 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/classes') 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/classes') 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/classes') 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/classes') 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 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/classes') 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/classes') 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 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/classes') 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 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/classes') 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/classes') 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/classes') 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/classes') 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/classes') 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 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/classes') 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/classes') 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 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/classes') 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 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/classes') 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/classes') 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 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/classes') 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 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/classes') 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 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/classes') 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/classes') 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 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/classes') 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/classes') 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 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/classes') 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/classes') 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/classes') 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 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/classes') 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/classes') 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 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/classes') 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/classes') 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 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/classes') 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 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/classes') 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/classes') 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/classes') 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 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/classes') 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/classes') 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 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/classes') 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