diff options
35 files changed, 306 insertions, 125 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 7a3422d7d..5eb9aca0d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,45 @@ +Version 1.8.9 +(November 11, 2012 from https://github.com/Elgg/Elgg/tree/1.8) + + Contributing Developers: + * Brett Profitt + * Cash Costello + * Evan Winslow + * Jeroen Dalsem + * Jerome Bakker + * Matt Beckett + * Paweł Sroka + * Sem + * Steve Clay + + Security Enhancements: + * Sample CLI installer cannot break site + * Removed XSS vulnerabilities in titles and user profiles + + Enhancements: + * UX: A group's owner can transfer ownership to another member + * UX: Search queries persist in the search box + * Several (X)HTML validation improvements + * Improved performance via more aggressive entity and metadata caching + * BC: 1.7 group profile URLs forward correctly + + Bugfixes: + * UX: Titles containing HTML tokens are never mangled + * UX: Empty user profile values saved properly + * UX: Blog creator always mentioned in activity stream (not user who published it) + * UI: Fixed ordering of registered menu items in some cases + * UI: Embed dialog does not break file inputs + * UI: Datepicker now respects language + * UI: More reliable display of access input in widgets + * UI: Group edit form is sticky + * UI: Site categories are sticky in forms + * API: Language fallback works in Javascript + * API: Fallback to default viewtype if invalid one given + * API: Notices reported for missing language keys + * Memcache now safe to use; never bypasses access control + * BC: upgrade shows comments consistently in activity stream + + Version 1.8.8 (July 11, 2012 from https://github.com/Elgg/Elgg/tree/1.8) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 0163757e7..a8e74d3a4 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -1,6 +1,7 @@ The following have made notable contributions to the Elgg Project. (List in alphabetical order.) +Steve Clay - http://www.mrclay.org/, https://twitter.com/mrclay_org Cash Costello - cash@elgg.org, http://cashcostello.com/ @@ -20,10 +21,10 @@ Tom Read - MITRE http://mitre.org/ Justin Richer - MITRE http://mitre.org/ -Dave Tosh - davidgtosh@gmail.com, http://twitter.com/davetosh +Dave Tosh - davidgtosh@gmail.com, http://twitter.com/davetosh Ben Werdmuller - http://benwerd.com/ -Nicholas Whitt - nick.whitt@gmail.com, http://twitter.com/nogoodnick +Nicholas Whitt - nick.whitt@gmail.com, http://twitter.com/nogoodnick Evan Winslow - evan@elgg.org, http://evanwinslow.com/ diff --git a/actions/profile/edit.php b/actions/profile/edit.php index 8ca60f246..89bf2bc0b 100644 --- a/actions/profile/edit.php +++ b/actions/profile/edit.php @@ -25,7 +25,7 @@ if (!is_array($accesslevel)) { * wrapper for recursive array walk decoding */ function profile_array_decoder(&$v) { - $v = html_entity_decode($v, ENT_COMPAT, 'UTF-8'); + $v = _elgg_html_decode($v); } $profile_fields = elgg_get_config('profile_fields'); @@ -37,7 +37,7 @@ foreach ($profile_fields as $shortname => $valuetype) { if (is_array($value)) { array_walk_recursive($value, 'profile_array_decoder'); } else { - $value = html_entity_decode($value, ENT_COMPAT, 'UTF-8'); + $value = _elgg_html_decode($value); } // limit to reasonable sizes @@ -51,7 +51,7 @@ foreach ($profile_fields as $shortname => $valuetype) { if ($valuetype == 'tags') { $value = string_to_tag_array($value); } - + $input[$shortname] = $value; } @@ -71,24 +71,30 @@ if (sizeof($input) > 0) { foreach ($input as $shortname => $value) { $options = array( 'guid' => $owner->guid, - 'metadata_name' => $shortname + 'metadata_name' => $shortname, + 'limit' => false ); elgg_delete_metadata($options); - if (isset($accesslevel[$shortname])) { - $access_id = (int) $accesslevel[$shortname]; - } else { - // this should never be executed since the access level should always be set - $access_id = ACCESS_DEFAULT; - } - if (is_array($value)) { - $i = 0; - foreach ($value as $interval) { - $i++; - $multiple = ($i > 1) ? TRUE : FALSE; - create_metadata($owner->guid, $shortname, $interval, 'text', $owner->guid, $access_id, $multiple); + + if(!is_null($value) && ($value !== '')){ + // only create metadata for non empty values (0 is allowed) to prevent metadata records with empty string values #4858 + + if (isset($accesslevel[$shortname])) { + $access_id = (int) $accesslevel[$shortname]; + } else { + // this should never be executed since the access level should always be set + $access_id = ACCESS_DEFAULT; + } + if (is_array($value)) { + $i = 0; + foreach ($value as $interval) { + $i++; + $multiple = ($i > 1) ? TRUE : FALSE; + create_metadata($owner->guid, $shortname, $interval, 'text', $owner->guid, $access_id, $multiple); + } + } else { + create_metadata($owner->getGUID(), $shortname, $value, 'text', $owner->getGUID(), $access_id); } - } else { - create_metadata($owner->getGUID(), $shortname, $value, 'text', $owner->getGUID(), $access_id); } } diff --git a/actions/register.php b/actions/register.php index f23d5b381..810ceaf27 100644 --- a/actions/register.php +++ b/actions/register.php @@ -30,8 +30,6 @@ if (elgg_get_config('allow_registration')) { $guid = register_user($username, $password, $name, $email, false, $friend_guid, $invitecode); if ($guid) { - elgg_clear_sticky_form('register'); - $new_user = get_entity($guid); // allow plugins to respond to self registration @@ -54,6 +52,7 @@ if (elgg_get_config('allow_registration')) { throw new RegistrationException(elgg_echo('registerbad')); } + elgg_clear_sticky_form('register'); system_message(elgg_echo("registerok", array(elgg_get_site_entity()->name))); // if exception thrown, this probably means there is a validation @@ -76,4 +75,4 @@ if (elgg_get_config('allow_registration')) { register_error(elgg_echo('registerdisabled')); } -forward(REFERER);
\ No newline at end of file +forward(REFERER); diff --git a/engine/classes/ElggMenuBuilder.php b/engine/classes/ElggMenuBuilder.php index de0017599..df0f9147f 100644 --- a/engine/classes/ElggMenuBuilder.php +++ b/engine/classes/ElggMenuBuilder.php @@ -204,6 +204,9 @@ class ElggMenuBuilder { // sort each section foreach ($this->menu as $index => $section) { + foreach ($section as $key => $node) { + $section[$key]->original_order = $key; + } usort($section, $sort_callback); $this->menu[$index] = $section; @@ -232,10 +235,14 @@ class ElggMenuBuilder { * @return bool */ public static function compareByText($a, $b) { - $a = $a->getText(); - $b = $b->getText(); + $at = $a->getText(); + $bt = $b->getText(); - return strnatcmp($a, $b); + $result = strnatcmp($at, $bt); + if ($result === 0) { + return $a->original_order - $b->original_order; + } + return $result; } /** @@ -246,10 +253,14 @@ class ElggMenuBuilder { * @return bool */ public static function compareByName($a, $b) { - $a = $a->getName(); - $b = $b->getName(); + $an = $a->getName(); + $bn = $b->getName(); - return strcmp($a, $b); + $result = strcmp($an, $bn); + if ($result === 0) { + return $a->original_order - $b->original_order; + } + return $result; } /** @@ -260,9 +271,12 @@ class ElggMenuBuilder { * @return bool */ public static function compareByWeight($a, $b) { - $a = $a->getWeight(); - $b = $b->getWeight(); + $aw = $a->getWeight(); + $bw = $b->getWeight(); - return $a > $b; + if ($aw == $bw) { + return $a->original_order - $b->original_order; + } + return $aw - $bw; } } diff --git a/engine/classes/ElggMenuItem.php b/engine/classes/ElggMenuItem.php index 4bc9144d4..fe25f3ddd 100644 --- a/engine/classes/ElggMenuItem.php +++ b/engine/classes/ElggMenuItem.php @@ -542,6 +542,9 @@ class ElggMenuItem { * @return void */ public function sortChildren($sortFunction) { + foreach ($this->data['children'] as $key => $node) { + $this->data['children'][$key]->original_order = $key; + } usort($this->data['children'], $sortFunction); } diff --git a/engine/classes/ElggPAM.php b/engine/classes/ElggPAM.php index 0681a909b..f07095fc1 100644 --- a/engine/classes/ElggPAM.php +++ b/engine/classes/ElggPAM.php @@ -53,11 +53,17 @@ class ElggPAM { foreach ($_PAM_HANDLERS[$this->policy] as $k => $v) { $handler = $v->handler; + if (!is_callable($handler)) { + continue; + } + /* @var callable $handler */ + $importance = $v->importance; try { // Execute the handler - $result = $handler($credentials); + // @todo don't assume $handler is a global function + $result = call_user_func($handler, $credentials); if ($result) { $authenticated = true; } elseif ($result === false) { diff --git a/engine/lib/access.php b/engine/lib/access.php index e8b3b0d52..3b2b7aeaa 100644 --- a/engine/lib/access.php +++ b/engine/lib/access.php @@ -88,11 +88,7 @@ function get_access_array($user_id = 0, $site_id = 0, $flush = false) { // @todo everything from the db is cached. // this cache might be redundant. But db cache is flushed on every db write. - static $access_array; - - if (!isset($access_array)) { - $access_array = array(); - } + static $access_array = array(); if ($user_id == 0) { $user_id = elgg_get_logged_in_user_guid(); @@ -476,7 +472,7 @@ function can_edit_access_collection($collection_id, $user_guid = null) { return false; } - $write_access = get_write_access_array($user->getGUID(), null, true); + $write_access = get_write_access_array($user->getGUID(), 0, true); // don't ignore access when checking users. if ($user_guid) { @@ -560,8 +556,6 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) { * @see remove_user_from_access_collection() */ function update_access_collection($collection_id, $members) { - global $CONFIG; - $acl = get_access_collection($collection_id); if (!$acl) { @@ -1018,6 +1012,7 @@ function elgg_override_permissions($hook, $type, $value, $params) { */ function access_test($hook, $type, $value, $params) { global $CONFIG; + $value[] = $CONFIG->path . 'engine/tests/api/access_collections.php'; return $value; } diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index 26c1cccfd..974f38aad 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -671,7 +671,7 @@ function elgg_register_event_handler($event, $object_type, $callback, $priority global $CONFIG; if (empty($event) || empty($object_type)) { - return FALSE; + return false; } if (!isset($CONFIG->events)) { @@ -684,8 +684,8 @@ function elgg_register_event_handler($event, $object_type, $callback, $priority $CONFIG->events[$event][$object_type] = array(); } - if (!is_callable($callback)) { - return FALSE; + if (!is_callable($callback, true)) { + return false; } $priority = max((int) $priority, 0); @@ -695,7 +695,7 @@ function elgg_register_event_handler($event, $object_type, $callback, $priority } $CONFIG->events[$event][$object_type][$priority] = $callback; ksort($CONFIG->events[$event][$object_type]); - return TRUE; + return true; } /** @@ -770,14 +770,14 @@ function elgg_trigger_event($event, $object_type, $object = null) { foreach ($events as $callback_list) { if (is_array($callback_list)) { foreach ($callback_list as $callback) { - if (call_user_func_array($callback, $args) === FALSE) { - return FALSE; + if (is_callable($callback) && (call_user_func_array($callback, $args) === false)) { + return false; } } } } - return TRUE; + return true; } /** @@ -850,7 +850,7 @@ function elgg_register_plugin_hook_handler($hook, $type, $callback, $priority = global $CONFIG; if (empty($hook) || empty($type)) { - return FALSE; + return false; } if (!isset($CONFIG->hooks)) { @@ -863,8 +863,8 @@ function elgg_register_plugin_hook_handler($hook, $type, $callback, $priority = $CONFIG->hooks[$hook][$type] = array(); } - if (!is_callable($callback)) { - return FALSE; + if (!is_callable($callback, true)) { + return false; } $priority = max((int) $priority, 0); @@ -874,7 +874,7 @@ function elgg_register_plugin_hook_handler($hook, $type, $callback, $priority = } $CONFIG->hooks[$hook][$type][$priority] = $callback; ksort($CONFIG->hooks[$hook][$type]); - return TRUE; + return true; } /** @@ -970,10 +970,12 @@ function elgg_trigger_plugin_hook($hook, $type, $params = null, $returnvalue = n foreach ($hooks as $callback_list) { if (is_array($callback_list)) { foreach ($callback_list as $hookcallback) { - $args = array($hook, $type, $returnvalue, $params); - $temp_return_value = call_user_func_array($hookcallback, $args); - if (!is_null($temp_return_value)) { - $returnvalue = $temp_return_value; + if (is_callable($hookcallback)) { + $args = array($hook, $type, $returnvalue, $params); + $temp_return_value = call_user_func_array($hookcallback, $args); + if (!is_null($temp_return_value)) { + $returnvalue = $temp_return_value; + } } } } diff --git a/engine/lib/entities.php b/engine/lib/entities.php index a50567d9f..a14160e14 100644 --- a/engine/lib/entities.php +++ b/engine/lib/entities.php @@ -1838,7 +1838,7 @@ function oddentity_to_elggentity(ODDEntity $element) { function import_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) { $element = $params['element']; - $tmp = NULL; + $tmp = null; if ($element instanceof ODDEntity) { $tmp = oddentity_to_elggentity($element); @@ -2011,7 +2011,7 @@ function get_entity_url($entity_guid) { function elgg_register_entity_url_handler($entity_type, $entity_subtype, $function_name) { global $CONFIG; - if (!is_callable($function_name)) { + if (!is_callable($function_name, true)) { return false; } diff --git a/engine/lib/extender.php b/engine/lib/extender.php index 43421342c..538f601e1 100644 --- a/engine/lib/extender.php +++ b/engine/lib/extender.php @@ -136,14 +136,15 @@ function can_edit_extender($extender_id, $type, $user_guid = 0) { $functionname = "elgg_get_{$type}_from_id"; if (is_callable($functionname)) { - $extender = $functionname($extender_id); + $extender = call_user_func($functionname, $extender_id); } else { return false; } - if (!is_a($extender, "ElggExtender")) { + if (!($extender instanceof ElggExtender)) { return false; } + /* @var ElggExtender $extender */ // If the owner is the specified user, great! They can edit. if ($extender->getOwnerGUID() == $user->getGUID()) { @@ -175,7 +176,7 @@ function elgg_register_extender_url_handler($extender_type, $extender_name, $fun global $CONFIG; - if (!is_callable($function_name)) { + if (!is_callable($function_name, true)) { return false; } @@ -228,7 +229,7 @@ function get_extender_url(ElggExtender $extender) { if ($url == "") { $nameid = $extender->id; if ($type == 'volatile') { - $nameid == $extender->name; + $nameid = $extender->name; } $url = "export/$view/$guid/$type/$nameid/"; } diff --git a/engine/lib/notification.php b/engine/lib/notification.php index 18faff27f..9e3c075a8 100644 --- a/engine/lib/notification.php +++ b/engine/lib/notification.php @@ -38,7 +38,7 @@ $NOTIFICATION_HANDLERS = array(); function register_notification_handler($method, $handler, $params = NULL) { global $NOTIFICATION_HANDLERS; - if (is_callable($handler)) { + if (is_callable($handler, true)) { $NOTIFICATION_HANDLERS[$method] = new stdClass; $NOTIFICATION_HANDLERS[$method]->handler = $handler; @@ -131,8 +131,9 @@ function notify_user($to, $from, $subject, $message, array $params = NULL, $meth // Extract method details from list $details = $NOTIFICATION_HANDLERS[$method]; $handler = $details->handler; + /* @var callable $handler */ - if ((!$NOTIFICATION_HANDLERS[$method]) || (!$handler)) { + if ((!$NOTIFICATION_HANDLERS[$method]) || (!$handler) || (!is_callable($handler))) { error_log(elgg_echo('NotificationException:NoHandlerFound', array($method))); } @@ -140,7 +141,7 @@ function notify_user($to, $from, $subject, $message, array $params = NULL, $meth // Trigger handler and retrieve result. try { - $result[$guid][$method] = $handler( + $result[$guid][$method] = call_user_func($handler, $from ? get_entity($from) : NULL, // From entity get_entity($guid), // To entity $subject, // The subject diff --git a/engine/lib/output.php b/engine/lib/output.php index 7bfc4be6e..352de863b 100644 --- a/engine/lib/output.php +++ b/engine/lib/output.php @@ -271,8 +271,8 @@ function elgg_normalize_url($url) { // '?query=test', #target return $url; - } elseif (stripos($url, 'javascript:') === 0) { - // 'javascript:' + } elseif (stripos($url, 'javascript:') === 0 || stripos($url, 'mailto:') === 0) { + // 'javascript:' and 'mailto:' // Not covered in FILTER_VALIDATE_URL return $url; @@ -398,3 +398,45 @@ function elgg_strip_tags($string) { return $string; } + +/** + * Apply html_entity_decode() to a string while re-entitising HTML + * special char entities to prevent them from being decoded back to their + * unsafe original forms. + * + * This relies on html_entity_decode() not translating entities when + * doing so leaves behind another entity, e.g. &gt; if decoded would + * create > which is another entity itself. This seems to escape the + * usual behaviour where any two paired entities creating a HTML tag are + * usually decoded, i.e. a lone > is not decoded, but <foo> would + * be decoded to <foo> since it creates a full tag. + * + * Note: This function is poorly explained in the manual - which is really + * bad given its potential for misuse on user input already escaped elsewhere. + * Stackoverflow is littered with advice to use this function in the precise + * way that would lead to user input being capable of injecting arbitrary HTML. + * + * @param string $string + * + * @return string + * + * @author Pádraic Brady + * @copyright Copyright (c) 2010 Pádraic Brady (http://blog.astrumfutura.com) + * @license Released under dual-license GPL2/MIT by explicit permission of Pádraic Brady + * + * @access private + */ +function _elgg_html_decode($string) { + $string = str_replace( + array('>', '<', '&', '"', '''), + array('&gt;', '&lt;', '&amp;', '&quot;', '&#039;'), + $string + ); + $string = html_entity_decode($string, ENT_NOQUOTES, 'UTF-8'); + $string = str_replace( + array('&gt;', '&lt;', '&amp;', '&quot;', '&#039;'), + array('>', '<', '&', '"', '''), + $string + ); + return $string; +} diff --git a/engine/lib/pagehandler.php b/engine/lib/pagehandler.php index ba7518a77..0cf99b6fe 100644 --- a/engine/lib/pagehandler.php +++ b/engine/lib/pagehandler.php @@ -45,7 +45,10 @@ function page_handler($handler, $page) { $page = $request['segments']; $result = false; - if (isset($CONFIG->pagehandler) && !empty($handler) && isset($CONFIG->pagehandler[$handler])) { + if (isset($CONFIG->pagehandler) + && !empty($handler) + && isset($CONFIG->pagehandler[$handler]) + && is_callable($CONFIG->pagehandler[$handler])) { $function = $CONFIG->pagehandler[$handler]; $result = call_user_func($function, $page, $handler); } @@ -76,14 +79,15 @@ function page_handler($handler, $page) { * @param string $handler The page type to handle * @param string $function Your function name * - * @return true|false Depending on success + * @return bool Depending on success */ function elgg_register_page_handler($handler, $function) { global $CONFIG; + if (!isset($CONFIG->pagehandler)) { $CONFIG->pagehandler = array(); } - if (is_callable($function)) { + if (is_callable($function, true)) { $CONFIG->pagehandler[$handler] = $function; return true; } diff --git a/engine/lib/pam.php b/engine/lib/pam.php index 4f9f44278..1c9c3bfe1 100644 --- a/engine/lib/pam.php +++ b/engine/lib/pam.php @@ -30,7 +30,9 @@ $_PAM_HANDLERS = array(); * failure, return false or throw an exception. Returning nothing indicates that * the handler wants to be skipped. * - * @param string $handler The handler function in the format + * Note, $handler must be string callback (not an array/Closure). + * + * @param string $handler Callable global handler function in the format () * pam_handler($credentials = NULL); * @param string $importance The importance - "sufficient" (default) or "required" * @param string $policy The policy type, default is "user" @@ -45,7 +47,8 @@ function register_pam_handler($handler, $importance = "sufficient", $policy = "u $_PAM_HANDLERS[$policy] = array(); } - if (is_callable($handler)) { + // @todo remove requirement that $handle be a global function + if (is_string($handler) && is_callable($handler, true)) { $_PAM_HANDLERS[$policy][$handler] = new stdClass; $_PAM_HANDLERS[$policy][$handler]->handler = $handler; diff --git a/engine/lib/relationships.php b/engine/lib/relationships.php index 09d541e22..01654b1ce 100644 --- a/engine/lib/relationships.php +++ b/engine/lib/relationships.php @@ -416,7 +416,7 @@ function elgg_list_entities_from_relationship_count($options) { function elgg_register_relationship_url_handler($relationship_type, $function_name) { global $CONFIG; - if (!is_callable($function_name)) { + if (!is_callable($function_name, true)) { return false; } diff --git a/engine/lib/upgrades/2010052601.php b/engine/lib/upgrades/2010052601.php index 5b477910f..a9cca6dc5 100644 --- a/engine/lib/upgrades/2010052601.php +++ b/engine/lib/upgrades/2010052601.php @@ -9,14 +9,14 @@ $params = array('type' => 'group', $groups = elgg_get_entities($params); if ($groups) { foreach ($groups as $group) { - $group->name = html_entity_decode($group->name, ENT_COMPAT, 'UTF-8'); - $group->description = html_entity_decode($group->description, ENT_COMPAT, 'UTF-8'); - $group->briefdescription = html_entity_decode($group->briefdescription, ENT_COMPAT, 'UTF-8'); - $group->website = html_entity_decode($group->website, ENT_COMPAT, 'UTF-8'); + $group->name = _elgg_html_decode($group->name); + $group->description = _elgg_html_decode($group->description); + $group->briefdescription = _elgg_html_decode($group->briefdescription); + $group->website = _elgg_html_decode($group->website); if ($group->interests) { $tags = $group->interests; - foreach ($tags as $index=>$tag) { - $tags[$index] = html_entity_decode($tag, ENT_COMPAT, 'UTF-8'); + foreach ($tags as $index => $tag) { + $tags[$index] = _elgg_html_decode($tag); } $group->interests = $tags; } diff --git a/engine/lib/views.php b/engine/lib/views.php index 6135026a7..8a0642c2b 100644 --- a/engine/lib/views.php +++ b/engine/lib/views.php @@ -1403,7 +1403,8 @@ function elgg_view_access_collections($owner_guid) { */ function set_template_handler($function_name) { global $CONFIG; - if (!empty($function_name) && is_callable($function_name)) { + + if (is_callable($function_name)) { $CONFIG->template_handler = $function_name; return true; } diff --git a/engine/lib/web_services.php b/engine/lib/web_services.php index da3ed76a9..c8e4a13cc 100644 --- a/engine/lib/web_services.php +++ b/engine/lib/web_services.php @@ -232,6 +232,7 @@ function execute_method($method) { $function = $API_METHODS[$method]["function"]; $serialised_parameters = trim($serialised_parameters, ", "); + // @todo document why we cannot use call_user_func_array here $result = eval("return $function($serialised_parameters);"); // Sanity check result @@ -1194,6 +1195,8 @@ $ERRORS = array(); * * @return void * @access private + * + * @throws Exception */ function _php_api_error_handler($errno, $errmsg, $filename, $linenum, $vars) { global $ERRORS; @@ -1278,11 +1281,9 @@ function service_handler($handler, $request) { // no handlers set or bad url header("HTTP/1.0 404 Not Found"); exit; - } else if (isset($CONFIG->servicehandler[$handler]) - && is_callable($CONFIG->servicehandler[$handler])) { - + } else if (isset($CONFIG->servicehandler[$handler]) && is_callable($CONFIG->servicehandler[$handler])) { $function = $CONFIG->servicehandler[$handler]; - $function($request, $handler); + call_user_func($function, $request, $handler); } else { // no handler for this web service header("HTTP/1.0 404 Not Found"); @@ -1301,10 +1302,11 @@ function service_handler($handler, $request) { */ function register_service_handler($handler, $function) { global $CONFIG; + if (!isset($CONFIG->servicehandler)) { $CONFIG->servicehandler = array(); } - if (is_callable($function)) { + if (is_callable($function, true)) { $CONFIG->servicehandler[$handler] = $function; return true; } @@ -1319,11 +1321,13 @@ function register_service_handler($handler, $function) { * * @param string $handler web services type * - * @return 1.7.0 + * @return void + * @since 1.7.0 */ function unregister_service_handler($handler) { global $CONFIG; - if (isset($CONFIG->servicehandler) && isset($CONFIG->servicehandler[$handler])) { + + if (isset($CONFIG->servicehandler, $CONFIG->servicehandler[$handler])) { unset($CONFIG->servicehandler[$handler]); } } @@ -1333,6 +1337,8 @@ function unregister_service_handler($handler) { * * @return void * @access private + * + * @throws SecurityException|APIException */ function rest_handler() { global $CONFIG; @@ -1387,7 +1393,7 @@ function rest_handler() { /** * Unit tests for API * - * @param sting $hook unit_test + * @param string $hook unit_test * @param string $type system * @param mixed $value Array of tests * @param mixed $params Params @@ -1397,6 +1403,7 @@ function rest_handler() { */ function api_unit_test($hook, $type, $value, $params) { global $CONFIG; + $value[] = $CONFIG->path . 'engine/tests/services/api.php'; return $value; } @@ -1418,15 +1425,18 @@ function api_init() { elgg_echo("system.api.list"), "GET", false, false); // The authentication token api - expose_function("auth.gettoken", - "auth_gettoken", array( - 'username' => array ('type' => 'string'), - 'password' => array ('type' => 'string'), - ), - elgg_echo('auth.gettoken'), - 'POST', - false, - false); + expose_function( + "auth.gettoken", + "auth_gettoken", + array( + 'username' => array ('type' => 'string'), + 'password' => array ('type' => 'string'), + ), + elgg_echo('auth.gettoken'), + 'POST', + false, + false + ); } diff --git a/engine/tests/api/metadata.php b/engine/tests/api/metadata.php index 9933263d1..825290d80 100644 --- a/engine/tests/api/metadata.php +++ b/engine/tests/api/metadata.php @@ -102,14 +102,14 @@ class ElggCoreMetadataAPITest extends ElggCoreUnitTest { $e = new ElggObject(); $e->save(); - for ($i=0; $i<30; $i++) { - $name = "test_metadata" . rand(0, 10000); + for ($i = 0; $i < 30; $i++) { + $name = "test_metadata$i"; $e->$name = rand(0, 10000); } $options = array( 'guid' => $e->getGUID(), - 'limit' => 0 + 'limit' => 0, ); $md = elgg_get_metadata($options); diff --git a/install/ElggInstaller.php b/install/ElggInstaller.php index 03c84a43e..934b38d28 100644 --- a/install/ElggInstaller.php +++ b/install/ElggInstaller.php @@ -157,7 +157,7 @@ class ElggInstaller { 'password', ); foreach ($requiredParams as $key) { - if (!array_key_exists($key, $params)) { + if (empty($params[$key])) { $msg = elgg_echo('install:error:requiredfield', array($key)); throw new InstallationException($msg); } diff --git a/install/cli/sample_installer.php b/install/cli/sample_installer.php index 954169a6a..0bae0cd23 100644 --- a/install/cli/sample_installer.php +++ b/install/cli/sample_installer.php @@ -3,10 +3,27 @@ * Sample cli installer script */ +$enabled = false; + +// Do not edit below this line. ////////////////////////////// + + +if (!$enabled) { + echo "To enable this script, change \$enabled to true.\n"; + echo "You *must* disable this script after a successful installation.\n"; + exit; +} + +if (PHP_SAPI !== 'cli') { + echo "You must use the command line to run this script."; + exit; +} + require_once(dirname(dirname(__FILE__)) . "/ElggInstaller.php"); $installer = new ElggInstaller(); +// none of the following may be empty $params = array( // database parameters 'dbuser' => '', @@ -28,3 +45,21 @@ $params = array( // install and create the .htaccess file $installer->batchInstall($params, TRUE); + +// at this point installation has completed (otherwise an exception halted execution). + +// try to rewrite the script to disable it. +if (is_writable(__FILE__)) { + $code = file_get_contents(__FILE__); + if (preg_match('~\\$enabled\\s*=\\s*(true|1)\\s*;~i', $code)) { + // looks safe to rewrite + $code = preg_replace('~\\$enabled\\s*=\\s*(true|1)\\s*;~i', '$enabled = false;', $code); + file_put_contents(__FILE__, $code); + + echo "\nNote: This script has been disabled for your safety.\n"; + exit; + } +} + +echo "\nWarning: You *must* disable this script by setting \$enabled = false;.\n"; +echo "Leaving this script enabled could endanger your installation.\n"; diff --git a/js/lib/elgglib.js b/js/lib/elgglib.js index 81209ebd0..dc7c07165 100644 --- a/js/lib/elgglib.js +++ b/js/lib/elgglib.js @@ -283,7 +283,7 @@ elgg.normalize_url = function(url) { } // 'javascript:' - else if (url.indexOf('javascript:') === 0) { + else if (url.indexOf('javascript:') === 0 || url.indexOf('mailto:') === 0 ) { return url; } diff --git a/languages/en.php b/languages/en.php index bb5376a44..62b35dd81 100644 --- a/languages/en.php +++ b/languages/en.php @@ -229,6 +229,7 @@ $english = array( 'LoginException:PasswordFailure' => 'We could not log you in. Please check your username/email and password.', 'LoginException:AccountLocked' => 'Your account has been locked for too many log in failures.', 'LoginException:ChangePasswordFailure' => 'Failed current password check.', + 'LoginException:Unknown' => 'We could not log you in due to an unknown error.', 'deprecatedfunction' => 'Warning: This code uses the deprecated function \'%s\' and is not compatible with this version of Elgg', diff --git a/mod/blog/views/default/forms/blog/save.php b/mod/blog/views/default/forms/blog/save.php index a805541bd..36fa2e0e8 100644 --- a/mod/blog/views/default/forms/blog/save.php +++ b/mod/blog/views/default/forms/blog/save.php @@ -23,7 +23,7 @@ if ($vars['guid']) { $delete_link = elgg_view('output/confirmlink', array( 'href' => $delete_url, 'text' => elgg_echo('delete'), - 'class' => 'elgg-button elgg-button-delete elgg-state-disabled float-alt' + 'class' => 'elgg-button elgg-button-delete float-alt' )); } @@ -53,7 +53,7 @@ $excerpt_label = elgg_echo('blog:excerpt'); $excerpt_input = elgg_view('input/text', array( 'name' => 'excerpt', 'id' => 'blog_excerpt', - 'value' => html_entity_decode($vars['excerpt'], ENT_COMPAT, 'UTF-8') + 'value' => _elgg_html_decode($vars['excerpt']) )); $body_label = elgg_echo('blog:body'); @@ -125,9 +125,10 @@ $draft_warning $excerpt_input </div> -<label for="blog_description">$body_label</label> -$body_input -<br /> +<div> + <label for="blog_description">$body_label</label> + $body_input +</div> <div> <label for="blog_tags">$tags_label</label> diff --git a/mod/groups/actions/groups/edit.php b/mod/groups/actions/groups/edit.php index a4169461a..2d7e1f023 100644 --- a/mod/groups/actions/groups/edit.php +++ b/mod/groups/actions/groups/edit.php @@ -8,15 +8,15 @@ // Load configuration global $CONFIG; +elgg_make_sticky_form('groups'); + /** * wrapper for recursive array walk decoding */ function profile_array_decoder(&$v) { - $v = html_entity_decode($v, ENT_COMPAT, 'UTF-8'); + $v = _elgg_html_decode($v); } -elgg_make_sticky_form('groups'); - // Get group fields $input = array(); foreach ($CONFIG->group as $shortname => $valuetype) { @@ -25,7 +25,7 @@ foreach ($CONFIG->group as $shortname => $valuetype) { if (is_array($input[$shortname])) { array_walk_recursive($input[$shortname], 'profile_array_decoder'); } else { - $input[$shortname] = html_entity_decode($input[$shortname], ENT_COMPAT, 'UTF-8'); + $input[$shortname] = _elgg_html_decode($input[$shortname]); } if ($valuetype == 'tags') { diff --git a/mod/messages/pages/messages/read.php b/mod/messages/pages/messages/read.php index eb36eaa4b..4223c6bac 100644 --- a/mod/messages/pages/messages/read.php +++ b/mod/messages/pages/messages/read.php @@ -38,9 +38,9 @@ if ($inbox) { ); $body_params = array('message' => $message); $content .= elgg_view_form('messages/reply', $form_params, $body_params); - $from_user = get_user($message->fromID); + $from_user = get_user($message->fromId); - if (elgg_get_logged_in_user_guid() == elgg_get_page_owner_guid() && $from_user) { + if ((elgg_get_logged_in_user_guid() == elgg_get_page_owner_guid()) && $from_user) { elgg_register_menu_item('title', array( 'name' => 'reply', 'href' => '#messages-reply-form', diff --git a/mod/twitter/views/default/widgets/twitter/content.php b/mod/twitter/views/default/widgets/twitter/content.php index e429d0103..c616d944c 100644 --- a/mod/twitter/views/default/widgets/twitter/content.php +++ b/mod/twitter/views/default/widgets/twitter/content.php @@ -20,7 +20,7 @@ if ($username) { <ul id="twitter_update_list"></ul> <p class="visit_twitter"><a href="http://twitter.com/<?php echo $username; ?>"><?php echo elgg_echo("twitter:visit"); ?></a></p> <script type="text/javascript" src="http://twitter.com/javascripts/blogger.js"></script> - <script type="text/javascript" src="http://twitter.com/statuses/user_timeline/<?php echo $username; ?>.json?callback=twitterCallback2&count=<?php echo $num; ?>"></script> + <script type="text/javascript" src="https://api.twitter.com/1/statuses/user_timeline/<?php echo $username; ?>.json?callback=twitterCallback2&count=<?php echo $num; ?>"></script> </div> <?php diff --git a/mod/twitter_api/vendors/twitteroauth/OAuth.php b/mod/twitter_api/vendors/twitteroauth/OAuth.php index b0e3cfd5e..e132a5bc8 100644 --- a/mod/twitter_api/vendors/twitteroauth/OAuth.php +++ b/mod/twitter_api/vendors/twitteroauth/OAuth.php @@ -78,6 +78,7 @@ class twitterOAuthRequest extends OAuthRequest { private $http_url; // for debug purposes public $base_string; + public static $version = '1.0'; public static $POST_INPUT = 'php://input'; function __construct($http_method, $http_url, $parameters=NULL) { @@ -145,7 +146,7 @@ class twitterOAuthRequest extends OAuthRequest { */ public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) { @$parameters or $parameters = array(); - $defaults = array("oauth_version" => '1.0', + $defaults = array("oauth_version" => twitterOAuthRequest::$version, "oauth_nonce" => twitterOAuthRequest::generate_nonce(), "oauth_timestamp" => twitterOAuthRequest::generate_timestamp(), "oauth_consumer_key" => $consumer->key); diff --git a/mod/twitter_api/vendors/twitteroauth/twitterOAuth.php b/mod/twitter_api/vendors/twitteroauth/twitterOAuth.php index a1021ce6f..f36e6158d 100644 --- a/mod/twitter_api/vendors/twitteroauth/twitterOAuth.php +++ b/mod/twitter_api/vendors/twitteroauth/twitterOAuth.php @@ -43,8 +43,8 @@ class TwitterOAuth { * Set API URLS */ function accessTokenURL() { return 'https://api.twitter.com/oauth/access_token'; } - function authenticateURL() { return 'https://twitter.com/oauth/authenticate'; } - function authorizeURL() { return 'https://twitter.com/oauth/authorize'; } + function authenticateURL() { return 'https://api.twitter.com/oauth/authenticate'; } + function authorizeURL() { return 'https://api.twitter.com/oauth/authorize'; } function requestTokenURL() { return 'https://api.twitter.com/oauth/request_token'; } /** diff --git a/mod/uservalidationbyemail/start.php b/mod/uservalidationbyemail/start.php index f98f57faf..f44d2ab50 100644 --- a/mod/uservalidationbyemail/start.php +++ b/mod/uservalidationbyemail/start.php @@ -233,15 +233,23 @@ function uservalidationbyemail_public_pages($hook, $type, $return_value, $params * @param string $type * @param ElggUser $user * @return bool + * + * @throws LoginException */ function uservalidationbyemail_check_manual_login($event, $type, $user) { $access_status = access_get_show_hidden_status(); access_show_hidden_entities(TRUE); - // @todo register_error()? - $return = ($user instanceof ElggUser && !$user->isEnabled() && !$user->validated) ? FALSE : NULL; + if (($user instanceof ElggUser) && !$user->isEnabled() && !$user->validated) { + // send new validation email + uservalidationbyemail_request_validation($user->getGUID()); + + // restore hidden entities settings + access_show_hidden_entities($access_status); + + // throw error so we get a nice error message + throw new LoginException(elgg_echo('uservalidationbyemail:login:fail')); + } access_show_hidden_entities($access_status); - - return $return; } diff --git a/version.php b/version.php index dda087c52..a2417d848 100644 --- a/version.php +++ b/version.php @@ -11,7 +11,7 @@ // YYYYMMDD = Elgg Date // XX = Interim incrementer -$version = 2012071100; +$version = 2012111100; // Human-friendly version name -$release = '1.8.8'; +$release = '1.8.9'; diff --git a/views/default/forms/profile/edit.php b/views/default/forms/profile/edit.php index 222935344..9538b779e 100644 --- a/views/default/forms/profile/edit.php +++ b/views/default/forms/profile/edit.php @@ -18,7 +18,8 @@ if (is_array($profile_fields) && count($profile_fields) > 0) { foreach ($profile_fields as $shortname => $valtype) { $metadata = elgg_get_metadata(array( 'guid' => $vars['entity']->guid, - 'metadata_name' => $shortname + 'metadata_name' => $shortname, + 'limit' => false )); if ($metadata) { if (is_array($metadata)) { diff --git a/views/default/object/plugin/elements/dependencies.php b/views/default/object/plugin/elements/dependencies.php index 8abd61692..d8daedd33 100644 --- a/views/default/object/plugin/elements/dependencies.php +++ b/views/default/object/plugin/elements/dependencies.php @@ -29,6 +29,8 @@ foreach ($deps as $dep) { if ($dep['status']) { $class = "elgg-state-success elgg-dependency elgg-dependency-$type"; + } elseif ($dep['type'] == 'suggests') { + $class = "elgg-state-warning elgg-dependency elgg-dependency-$type"; } else { $class = "elgg-state-error elgg-dependency elgg-dependency-$type"; } diff --git a/views/default/output/email.php b/views/default/output/email.php index 00eefad1f..f5a8bc4b8 100644 --- a/views/default/output/email.php +++ b/views/default/output/email.php @@ -10,6 +10,8 @@ * */ +$encoded_value = htmlspecialchars($vars['value'], ENT_QUOTES, 'UTF-8'); + if (!empty($vars['value'])) { - echo "<a href=\"mailto:" . $vars['value'] . "\">". htmlspecialchars($vars['value'], ENT_QUOTES, 'UTF-8', false) ."</a>"; + echo "<a href=\"mailto:$encoded_value\">$encoded_value</a>"; }
\ No newline at end of file |