diff options
Diffstat (limited to 'engine/lib/input.php')
| -rw-r--r-- | engine/lib/input.php | 738 |
1 files changed, 517 insertions, 221 deletions
diff --git a/engine/lib/input.php b/engine/lib/input.php index 1380860b8..80b0b8766 100644 --- a/engine/lib/input.php +++ b/engine/lib/input.php @@ -1,224 +1,520 @@ -<?php
- /**
- * Parameter input functions.
- * This file contains functions for getting input from get/post variables.
- *
- * @package Elgg
- * @subpackage Core
- * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
- * @author Curverider Ltd <info@elgg.com>
- * @copyright Curverider Ltd 2008-2009
- * @link http://elgg.org/
- */
-
- /**
- * Get some input from variables passed on the GET or POST line.
- *
- * @param $variable string The variable we want to return.
- * @param $default mixed A default value for the variable if it is not found. - * @param $filter_result If true then the result is filtered for bad tags.
- */
- function get_input($variable, $default = "", $filter_result = true)
- {
-
- global $CONFIG;
-
- if (isset($CONFIG->input[$variable]))
- return $CONFIG->input[$variable];
-
- if (isset($_REQUEST[$variable])) { -
- if (is_array($_REQUEST[$variable])) { - $var = $_REQUEST[$variable]; - } else { - $var = trim($_REQUEST[$variable]);
- }
- - if ($filter_result) - $var = filter_tags($var);
-
- return $var;
-
- }
-
- return $default;
-
- }
-
- /**
- * Sets an input value that may later be retrieved by get_input
- *
- * @param string $variable The name of the variable
- * @param string $value The value of the variable
- */
- function set_input($variable, $value) {
-
- global $CONFIG;
- if (!isset($CONFIG->input))
- $CONFIG->input = array(); - - if (is_array($value)) - { - foreach ($value as $key => $val) - $value[$key] = trim($val); - - $CONFIG->input[trim($variable)] = $value; +<?php +/** + * Parameter input functions. + * This file contains functions for getting input from get/post variables. + * + * @package Elgg.Core + * @subpackage Input + */ + +/** + * Get some input from variables passed submitted through GET or POST. + * + * If using any data obtained from get_input() in a web page, please be aware that + * it is a possible vector for a reflected XSS attack. If you are expecting an + * integer, cast it to an int. If it is a string, escape quotes. + * + * Note: this function does not handle nested arrays (ex: form input of param[m][n]) + * because of the filtering done in htmlawed from the filter_tags call. + * @todo Is this ^ still true? + * + * @param string $variable The variable name we want. + * @param mixed $default A default value for the variable if it is not found. + * @param bool $filter_result If true, then the result is filtered for bad tags. + * + * @return mixed + */ +function get_input($variable, $default = NULL, $filter_result = TRUE) { + + global $CONFIG; + + $result = $default; + + elgg_push_context('input'); + + if (isset($CONFIG->input[$variable])) { + $result = $CONFIG->input[$variable]; + + if ($filter_result) { + $result = filter_tags($result); + } + } elseif (isset($_REQUEST[$variable])) { + if (is_array($_REQUEST[$variable])) { + $result = $_REQUEST[$variable]; + } else { + $result = trim($_REQUEST[$variable]); } - else
- $CONFIG->input[trim($variable)] = trim($value);
-
- }
-
- /**
- * Filter tags from a given string based on registered hooks.
- * @param $var
- * @return mixed The filtered result
- */
- function filter_tags($var)
- {
- return trigger_plugin_hook('validate', 'input', null, $var);
+ + if ($filter_result) { + $result = filter_tags($result); + } + } + + elgg_pop_context(); + + return $result; +} + +/** + * Sets an input value that may later be retrieved by get_input + * + * Note: this function does not handle nested arrays (ex: form input of param[m][n]) + * + * @param string $variable The name of the variable + * @param string|string[] $value The value of the variable + * + * @return void + */ +function set_input($variable, $value) { + global $CONFIG; + if (!isset($CONFIG->input)) { + $CONFIG->input = array(); } - - /** - * Sanitise file paths for input, ensuring that they begin and end with slashes etc. - * - * @param string $path The path - * @return string - */ - function sanitise_filepath($path) - { - // Convert to correct UNIX paths - $path = str_replace('\\', '/', $path); - - // Sort trailing slash - $path = trim($path); - $path = rtrim($path, " /"); - $path = $path . "/"; - - return $path; - }
- -
- /**
- * Takes a string and turns any URLs into formatted links
- *
- * @param string $text The input string
- * @return string The output stirng with formatted links
- **/
- function parse_urls($text) { - - return preg_replace_callback('/(?<!=["\'])((ht|f)tps?:\/\/[^\s\r\n\t<>"\'\!\(\)]+)/i', - create_function( - '$matches', - ' - $url = $matches[1]; - $urltext = str_replace("/", "/<wbr />", $url); - return "<a href=\"$url\" style=\"text-decoration:underline;\">$urltext</a>"; - ' - ), $text);
- }
-
- function autop($pee, $br = 1) {
- $pee = $pee . "\n"; // just to make things a little easier, pad the end
- $pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee);
- // Space things out a little
- $allblocks = '(?:table|thead|tfoot|caption|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|map|area|blockquote|address|math|style|input|p|h[1-6]|hr)';
- $pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "\n$1", $pee);
- $pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
- $pee = str_replace(array("\r\n", "\r"), "\n", $pee); // cross-platform newlines
- if ( strpos($pee, '<object') !== false ) {
- $pee = preg_replace('|\s*<param([^>]*)>\s*|', "<param$1>", $pee); // no pee inside object/embed
- $pee = preg_replace('|\s*</embed>\s*|', '</embed>', $pee);
- }
- $pee = preg_replace("/\n\n+/", "\n\n", $pee); // take care of duplicates
- $pee = preg_replace('/\n?(.+?)(?:\n\s*\n|\z)/s', "<p>$1</p>\n", $pee); // make paragraphs, including one at the end
- $pee = preg_replace('|<p>\s*?</p>|', '', $pee); // under certain strange conditions it could create a P of entirely whitespace
- $pee = preg_replace('!<p>([^<]+)\s*?(</(?:div|address|form)[^>]*>)!', "<p>$1</p>$2", $pee);
- $pee = preg_replace( '|<p>|', "$1<p>", $pee );
- $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee); // don't pee all over a tag
- $pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // problem with nested lists
- $pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
- $pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
- $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
- $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
- if ($br) {
- $pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', create_function('$matches', 'return str_replace("\n", "<WPPreserveNewline />", $matches[0]);'), $pee);
- $pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); // optionally make line breaks
- $pee = str_replace('<WPPreserveNewline />', "\n", $pee);
- }
- $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
- $pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
- if (strpos($pee, '<pre') !== false)
- $pee = preg_replace_callback('!(<pre.*?>)(.*?)</pre>!is', 'clean_pre', $pee );
- $pee = preg_replace( "|\n</p>$|", '</p>', $pee );
-
- return $pee;
- }
-
- function input_init() {
-
- if (ini_get_bool('magic_quotes_gpc') ) {
-
- //do keys as well, cos array_map ignores them
- function stripslashes_arraykeys($array) {
- if (is_array($array)) {
- $array2 = array();
- foreach ($array as $key => $data) {
- if ($key != stripslashes($key)) {
- $array2[stripslashes($key)] = $data;
- } else {
- $array2[$key] = $data;
- }
- }
- return $array2;
- } else {
- return $array;
- }
- }
-
- function stripslashes_deep($value) {
- if (is_array($value)) {
- $value = stripslashes_arraykeys($value);
- $value = array_map('stripslashes_deep', $value);
- } else {
- $value = stripslashes($value);
- }
- return $value;
- }
-
- $_POST = stripslashes_arraykeys($_POST);
- $_GET = stripslashes_arraykeys($_GET);
- $_COOKIE = stripslashes_arraykeys($_COOKIE);
- $_REQUEST = stripslashes_arraykeys($_REQUEST);
-
- $_POST = array_map('stripslashes_deep', $_POST);
- $_GET = array_map('stripslashes_deep', $_GET);
- $_COOKIE = array_map('stripslashes_deep', $_COOKIE);
- $_REQUEST = array_map('stripslashes_deep', $_REQUEST);
- if (!empty($_SERVER['REQUEST_URI'])) {
- $_SERVER['REQUEST_URI'] = stripslashes($_SERVER['REQUEST_URI']);
- }
- if (!empty($_SERVER['QUERY_STRING'])) {
- $_SERVER['QUERY_STRING'] = stripslashes($_SERVER['QUERY_STRING']);
- }
- if (!empty($_SERVER['HTTP_REFERER'])) {
- $_SERVER['HTTP_REFERER'] = stripslashes($_SERVER['HTTP_REFERER']);
- }
- if (!empty($_SERVER['PATH_INFO'])) {
- $_SERVER['PATH_INFO'] = stripslashes($_SERVER['PATH_INFO']);
- }
- if (!empty($_SERVER['PHP_SELF'])) {
- $_SERVER['PHP_SELF'] = stripslashes($_SERVER['PHP_SELF']);
- }
- if (!empty($_SERVER['PATH_TRANSLATED'])) {
- $_SERVER['PATH_TRANSLATED'] = stripslashes($_SERVER['PATH_TRANSLATED']);
- }
-
+ + if (is_array($value)) { + array_walk_recursive($value, create_function('&$v, $k', '$v = trim($v);')); + $CONFIG->input[trim($variable)] = $value; + } else { + $CONFIG->input[trim($variable)] = trim($value); + } +} + +/** + * Filter tags from a given string based on registered hooks. + * + * @param mixed $var Anything that does not include an object (strings, ints, arrays) + * This includes multi-dimensional arrays. + * + * @return mixed The filtered result - everything will be strings + */ +function filter_tags($var) { + return elgg_trigger_plugin_hook('validate', 'input', null, $var); +} + +/** + * Validates an email address. + * + * @param string $address Email address. + * + * @return bool + */ +function is_email_address($address) { + return filter_var($address, FILTER_VALIDATE_EMAIL) === $address; +} + +/** + * Load all the REQUEST variables into the sticky form cache + * + * Call this from an action when you want all your submitted variables + * available if the submission fails validation and is sent back to the form + * + * @param string $form_name Name of the sticky form + * + * @return void + * @link http://docs.elgg.org/Tutorials/UI/StickyForms + * @since 1.8.0 + */ +function elgg_make_sticky_form($form_name) { + + elgg_clear_sticky_form($form_name); + + if (!isset($_SESSION['sticky_forms'])) { + $_SESSION['sticky_forms'] = array(); + } + $_SESSION['sticky_forms'][$form_name] = array(); + + foreach ($_REQUEST as $key => $var) { + // will go through XSS filtering on the get function + $_SESSION['sticky_forms'][$form_name][$key] = $var; + } +} + +/** + * Clear the sticky form cache + * + * Call this if validation is successful in the action handler or + * when they sticky values have been used to repopulate the form + * after a validation error. + * + * @param string $form_name Form namespace + * + * @return void + * @link http://docs.elgg.org/Tutorials/UI/StickyForms + * @since 1.8.0 + */ +function elgg_clear_sticky_form($form_name) { + unset($_SESSION['sticky_forms'][$form_name]); +} + +/** + * Has this form been made sticky? + * + * @param string $form_name Form namespace + * + * @return boolean + * @link http://docs.elgg.org/Tutorials/UI/StickyForms + * @since 1.8.0 + */ +function elgg_is_sticky_form($form_name) { + return isset($_SESSION['sticky_forms'][$form_name]); +} + +/** + * Get a specific sticky variable + * + * @param string $form_name The name of the form + * @param string $variable The name of the variable + * @param mixed $default Default value if the variable does not exist in sticky cache + * @param boolean $filter_result Filter for bad input if true + * + * @return mixed + * + * @todo should this filter the default value? + * @link http://docs.elgg.org/Tutorials/UI/StickyForms + * @since 1.8.0 + */ +function elgg_get_sticky_value($form_name, $variable = '', $default = NULL, $filter_result = true) { + if (isset($_SESSION['sticky_forms'][$form_name][$variable])) { + $value = $_SESSION['sticky_forms'][$form_name][$variable]; + if ($filter_result) { + // XSS filter result + $value = filter_tags($value); } -
- }
-
- register_elgg_event_handler('init','system','input_init');
-
-
-?>
\ No newline at end of file + return $value; + } + return $default; +} + +/** + * Get all the values in a sticky form in an array + * + * @param string $form_name The name of the form + * @param bool $filter_result Filter for bad input if true + * + * @return array + * @since 1.8.0 + */ +function elgg_get_sticky_values($form_name, $filter_result = true) { + if (!isset($_SESSION['sticky_forms'][$form_name])) { + return array(); + } + + $values = $_SESSION['sticky_forms'][$form_name]; + if ($filter_result) { + foreach ($values as $key => $value) { + // XSS filter result + $values[$key] = filter_tags($value); + } + } + return $values; +} + +/** + * Clear a specific sticky variable + * + * @param string $form_name The name of the form + * @param string $variable The name of the variable to clear + * + * @return void + * @link http://docs.elgg.org/Tutorials/UI/StickyForms + * @since 1.8.0 + */ +function elgg_clear_sticky_value($form_name, $variable) { + unset($_SESSION['sticky_forms'][$form_name][$variable]); +} + +/** + * Page handler for autocomplete endpoint. + * + * @todo split this into functions/objects, this is way too big + * + * /livesearch?q=<query> + * + * Other options include: + * match_on string all or array(groups|users|friends) + * match_owner int 0/1 + * limit int default is 10 + * + * @param array $page + * @return string JSON string is returned and then exit + * @access private + */ +function input_livesearch_page_handler($page) { + global $CONFIG; + + // only return results to logged in users. + if (!$user = elgg_get_logged_in_user_entity()) { + exit; + } + + if (!$q = get_input('term', get_input('q'))) { + exit; + } + + $q = sanitise_string($q); + + // replace mysql vars with escaped strings + $q = str_replace(array('_', '%'), array('\_', '\%'), $q); + + $match_on = get_input('match_on', 'all'); + + if (!is_array($match_on)) { + $match_on = array($match_on); + } + + // all = users and groups + if (in_array('all', $match_on)) { + $match_on = array('users', 'groups'); + } + + if (get_input('match_owner', false)) { + $owner_where = 'AND e.owner_guid = ' . $user->getGUID(); + } else { + $owner_where = ''; + } + + $limit = sanitise_int(get_input('limit', 10)); + + // grab a list of entities and send them in json. + $results = array(); + foreach ($match_on as $match_type) { + switch ($match_type) { + case 'users': + $query = "SELECT * FROM {$CONFIG->dbprefix}users_entity as ue, {$CONFIG->dbprefix}entities as e + WHERE e.guid = ue.guid + AND e.enabled = 'yes' + AND ue.banned = 'no' + AND (ue.name LIKE '$q%' OR ue.name LIKE '% $q%' OR ue.username LIKE '$q%') + LIMIT $limit + "; + + if ($entities = get_data($query)) { + foreach ($entities as $entity) { + // @todo use elgg_get_entities (don't query in a loop!) + $entity = get_entity($entity->guid); + /* @var ElggUser $entity */ + if (!$entity) { + continue; + } + + if (in_array('groups', $match_on)) { + $value = $entity->guid; + } else { + $value = $entity->username; + } + + $output = elgg_view_list_item($entity, array( + 'use_hover' => false, + 'class' => 'elgg-autocomplete-item', + )); + + $icon = elgg_view_entity_icon($entity, 'tiny', array( + 'use_hover' => false, + )); + + $result = array( + 'type' => 'user', + 'name' => $entity->name, + 'desc' => $entity->username, + 'guid' => $entity->guid, + 'label' => $output, + 'value' => $value, + 'icon' => $icon, + 'url' => $entity->getURL(), + ); + $results[$entity->name . rand(1, 100)] = $result; + } + } + break; + + case 'groups': + // don't return results if groups aren't enabled. + if (!elgg_is_active_plugin('groups')) { + continue; + } + $query = "SELECT * FROM {$CONFIG->dbprefix}groups_entity as ge, {$CONFIG->dbprefix}entities as e + WHERE e.guid = ge.guid + AND e.enabled = 'yes' + $owner_where + AND (ge.name LIKE '$q%' OR ge.name LIKE '% $q%' OR ge.description LIKE '% $q%') + LIMIT $limit + "; + if ($entities = get_data($query)) { + foreach ($entities as $entity) { + // @todo use elgg_get_entities (don't query in a loop!) + $entity = get_entity($entity->guid); + /* @var ElggGroup $entity */ + if (!$entity) { + continue; + } + + $output = elgg_view_list_item($entity, array( + 'use_hover' => false, + 'class' => 'elgg-autocomplete-item', + )); + + $icon = elgg_view_entity_icon($entity, 'tiny', array( + 'use_hover' => false, + )); + + $result = array( + 'type' => 'group', + 'name' => $entity->name, + 'desc' => strip_tags($entity->description), + 'guid' => $entity->guid, + 'label' => $output, + 'value' => $entity->guid, + 'icon' => $icon, + 'url' => $entity->getURL(), + ); + + $results[$entity->name . rand(1, 100)] = $result; + } + } + break; + + case 'friends': + $query = "SELECT * FROM + {$CONFIG->dbprefix}users_entity as ue, + {$CONFIG->dbprefix}entity_relationships as er, + {$CONFIG->dbprefix}entities as e + WHERE er.relationship = 'friend' + AND er.guid_one = {$user->getGUID()} + AND er.guid_two = ue.guid + AND e.guid = ue.guid + AND e.enabled = 'yes' + AND ue.banned = 'no' + AND (ue.name LIKE '$q%' OR ue.name LIKE '% $q%' OR ue.username LIKE '$q%') + LIMIT $limit + "; + + if ($entities = get_data($query)) { + foreach ($entities as $entity) { + // @todo use elgg_get_entities (don't query in a loop!) + $entity = get_entity($entity->guid); + /* @var ElggUser $entity */ + if (!$entity) { + continue; + } + + $output = elgg_view_list_item($entity, array( + 'use_hover' => false, + 'class' => 'elgg-autocomplete-item', + )); + + $icon = elgg_view_entity_icon($entity, 'tiny', array( + 'use_hover' => false, + )); + + $result = array( + 'type' => 'user', + 'name' => $entity->name, + 'desc' => $entity->username, + 'guid' => $entity->guid, + 'label' => $output, + 'value' => $entity->username, + 'icon' => $icon, + 'url' => $entity->getURL(), + ); + $results[$entity->name . rand(1, 100)] = $result; + } + } + break; + + default: + header("HTTP/1.0 400 Bad Request", true); + echo "livesearch: unknown match_on of $match_type"; + exit; + break; + } + } + + ksort($results); + header("Content-Type: application/json"); + echo json_encode(array_values($results)); + exit; +} + +/** + * Register input functions and sanitize input + * + * @return void + * @access private + */ +function input_init() { + // register an endpoint for live search / autocomplete. + elgg_register_page_handler('livesearch', 'input_livesearch_page_handler'); + + if (ini_get_bool('magic_quotes_gpc')) { + + /** + * do keys as well, cos array_map ignores them + * + * @param array $array Array of values + * + * @return array Sanitized array + */ + function stripslashes_arraykeys($array) { + if (is_array($array)) { + $array2 = array(); + foreach ($array as $key => $data) { + if ($key != stripslashes($key)) { + $array2[stripslashes($key)] = $data; + } else { + $array2[$key] = $data; + } + } + return $array2; + } else { + return $array; + } + } + + /** + * Strip slashes on everything + * + * @param mixed $value The value to remove slashes from + * + * @return mixed + */ + function stripslashes_deep($value) { + if (is_array($value)) { + $value = stripslashes_arraykeys($value); + $value = array_map('stripslashes_deep', $value); + } else { + $value = stripslashes($value); + } + return $value; + } + + $_POST = stripslashes_arraykeys($_POST); + $_GET = stripslashes_arraykeys($_GET); + $_COOKIE = stripslashes_arraykeys($_COOKIE); + $_REQUEST = stripslashes_arraykeys($_REQUEST); + + $_POST = array_map('stripslashes_deep', $_POST); + $_GET = array_map('stripslashes_deep', $_GET); + $_COOKIE = array_map('stripslashes_deep', $_COOKIE); + $_REQUEST = array_map('stripslashes_deep', $_REQUEST); + if (!empty($_SERVER['REQUEST_URI'])) { + $_SERVER['REQUEST_URI'] = stripslashes($_SERVER['REQUEST_URI']); + } + if (!empty($_SERVER['QUERY_STRING'])) { + $_SERVER['QUERY_STRING'] = stripslashes($_SERVER['QUERY_STRING']); + } + if (!empty($_SERVER['HTTP_REFERER'])) { + $_SERVER['HTTP_REFERER'] = stripslashes($_SERVER['HTTP_REFERER']); + } + if (!empty($_SERVER['PATH_INFO'])) { + $_SERVER['PATH_INFO'] = stripslashes($_SERVER['PATH_INFO']); + } + if (!empty($_SERVER['PHP_SELF'])) { + $_SERVER['PHP_SELF'] = stripslashes($_SERVER['PHP_SELF']); + } + if (!empty($_SERVER['PATH_TRANSLATED'])) { + $_SERVER['PATH_TRANSLATED'] = stripslashes($_SERVER['PATH_TRANSLATED']); + } + } +} + +elgg_register_event_handler('init', 'system', 'input_init'); |
