/** * Returns a where clause for a search query. * * @param str $table Prefix for table to search on * @param array $fields Fields to match against * @param array $params Original search params * @return str */ function search_get_where_sql($table, $fields, $params, $use_fulltext = TRUE) { global $CONFIG; $query = $params['query']; // add the table prefix to the fields foreach ($fields as $i => $field) { if ($table) { $fields[$i] = "{$table}.{$field}"; } } // if we're not using full text, rewrite the query for bool mode. // exploiting a feature(ish) of bool mode where +-word is the same as -word if (!$use_fulltext) { $query = '+' . str_replace(' ', ' +', $query); } // if query is shorter than the min for fts words // it's likely a single acronym or similar // switch to literal mode if (elgg_strlen($query) < $CONFIG->search_info['min_chars']) { $likes = array(); $query = sanitise_string($query); foreach ($fields as $field) { $likes[] = "{$field} LIKE '%{$query}%'"; } $likes_str = implode(' OR ', $likes); $where = "({$likes_str})"; } else { // if using advanced or paired "s, switch into boolean mode if (!$use_fulltext || isset($params['advanced_search']) && $params['advanced_search'] || elgg_substr_count($query, '"') >= 2) { $options = 'IN BOOLEAN MODE'; } else { // natural language mode is default and this keyword isn't supported in < 5.1 //$options = 'IN NATURAL LANGUAGE MODE'; $options = ''; } // if short query, use query expansion. // @todo doesn't seem to be working well. if (elgg_strlen($query) < 5) { //$options .= ' WITH QUERY EXPANSION'; } $query = sanitise_string($query); $fields_str = implode(',', $fields); $where = "(MATCH ({$fields_str}) AGAINST ('{$query}' {$options}))"; } return $where; }
} $users = array(); $activeletters = array(); // Are we displaying form tags and submit buttons? // (If we've been given a target, then yes! Otherwise, no.) if (isset($vars['formtarget'])) { $formtarget = $vars['formtarget']; } else { $formtarget = false; } // Sort users by letter if (is_array($friends) && sizeof($friends)) { foreach ($friends as $friend) { $letter = elgg_substr($friend->name, 0, 1); $letter = elgg_strtoupper($letter); if (!elgg_substr_count($chararray, $letter)) { $letter = "*"; } if (!isset($users[$letter])) { $users[$letter] = array(); } $users[$letter][$friend->guid] = $friend; } } if (!$callback) { ?> <div class="friends-picker-main-wrapper"> <?php if (isset($vars['content'])) {
/** * Returns a where clause for a search query. * * @param string $table Prefix for table to search on * @param array $fields Fields to match against * @return string */ function sqlGetWhereFulltextClause($table, $fields, $query, $use_fulltext = TRUE) { $query = str_replace(array('_', '%'), array('\\_', '\\%'), sanitize_string($query)); // add the table prefix to the fields foreach ($fields as $i => $field) { if ($table) { $fields[$i] = "{$table}.{$field}"; } } $where = ''; // if query is shorter than the min for fts words // it's likely a single acronym or similar // switch to literal mode if (elgg_strlen($this->query) < $this->ft_min_chars) { $likes = array(); foreach ($fields as $field) { $likes[] = "{$field} LIKE '%{$query}%'"; } $likes_str = implode(' OR ', $likes); $where = "({$likes_str})"; } else { // if we're not using full text, rewrite the query for bool mode. // exploiting a feature(ish) of bool mode where +-word is the same as -word if (!$use_fulltext) { $query = '+' . str_replace(' ', ' +', $query); } // if using advanced, boolean operators, or paired "s, switch into boolean mode $booleans_used = preg_match("/([\\-\\+~])([\\w]+)/i", $query); $quotes_used = elgg_substr_count($query, '"') >= 2; if (!$use_fulltext || $booleans_used || $quotes_used) { $options = 'IN BOOLEAN MODE'; } else { $options = ''; } $query = sanitise_string($query); $fields_str = implode(',', $fields); $where = "(MATCH ({$fields_str}) AGAINST ('{$query}' {$options}))"; } return $where; }
/** * Returns a where clause for a search query. * * @see search_get_where_sql * * @param str $table Prefix for table to search on * @param array $fields Fields to match against * @param array $params Original search params * @param bool $use_fulltext Use fulltext search * @return str */ public static function getFieldSearchWhereClause($table, $fields, $params, $use_fulltext = TRUE) { if (is_callable('search_get_where_sql')) { return search_get_where_sql($table, $fields, $params, $use_fulltext); } $query = $params['query']; // add the table prefix to the fields foreach ($fields as $i => $field) { if ($table) { $fields[$i] = "{$table}.{$field}"; } } $where = ''; $search_info = elgg_get_config('search_info'); // if query is shorter than the min for fts words // it's likely a single acronym or similar // switch to literal mode if (elgg_strlen($query) < $search_info['min_chars']) { $likes = array(); $query = sanitise_string($query); foreach ($fields as $field) { $likes[] = "{$field} LIKE '%{$query}%'"; } $likes_str = implode(' OR ', $likes); $where = "({$likes_str})"; } else { // if we're not using full text, rewrite the query for bool mode. // exploiting a feature(ish) of bool mode where +-word is the same as -word if (!$use_fulltext) { $query = '+' . str_replace(' ', ' +', $query); } // if using advanced, boolean operators, or paired "s, switch into boolean mode $booleans_used = preg_match("/([\\-\\+~])([\\w]+)/i", $query); $advanced_search = isset($params['advanced_search']) && $params['advanced_search']; $quotes_used = elgg_substr_count($query, '"') >= 2; $options = ''; if (!$use_fulltext || $booleans_used || $advanced_search || $quotes_used) { $options = 'IN BOOLEAN MODE'; } $query = sanitise_string($query); $fields_str = implode(',', $fields); $where = "(MATCH ({$fields_str}) AGAINST ('{$query}' {$options}))"; } return $where; }
/** * Return a string with highlighted matched queries and relevant context * Determines context based upon occurance and distance of words with each other. * * @param string $haystack * @param string $query * @param int $min_match_context = 30 * @param int $max_length = 300 * @param bool $tag_match Search is for tags. Don't ignore words. * @return string */ function search_get_highlighted_relevant_substrings($haystack, $query, $min_match_context = 30, $max_length = 300, $tag_match = false) { $haystack = strip_tags($haystack); $haystack_length = elgg_strlen($haystack); $haystack_lc = elgg_strtolower($haystack); if (!$tag_match) { $words = search_remove_ignored_words($query, 'array'); } else { $words = array(); } // if haystack < $max_length return the entire haystack w/formatting immediately if ($haystack_length <= $max_length) { $return = search_highlight_words($words, $haystack); return $return; } // get the starting positions and lengths for all matching words $starts = array(); $lengths = array(); foreach ($words as $word) { $word = elgg_strtolower($word); $count = elgg_substr_count($haystack_lc, $word); $word_len = elgg_strlen($word); $haystack_len = elgg_strlen($haystack_lc); // find the start positions for the words if ($count > 1) { $offset = 0; while (FALSE !== ($pos = elgg_strpos($haystack_lc, $word, $offset))) { $start = $pos - $min_match_context > 0 ? $pos - $min_match_context : 0; $starts[] = $start; $stop = $pos + $word_len + $min_match_context; $lengths[] = $stop - $start; $offset += $pos + $word_len; if ($offset >= $haystack_len) { break; } } } else { $pos = elgg_strpos($haystack_lc, $word); $start = $pos - $min_match_context > 0 ? $pos - $min_match_context : 0; $starts[] = $start; $stop = $pos + $word_len + $min_match_context; $lengths[] = $stop - $start; } } $offsets = search_consolidate_substrings($starts, $lengths); // figure out if we can adjust the offsets and lengths // in order to return more context $total_length = array_sum($offsets); $add_length = 0; if ($total_length < $max_length && $offsets) { $add_length = floor(($max_length - $total_length) / count($offsets) / 2); $starts = array(); $lengths = array(); foreach ($offsets as $offset => $length) { $start = $offset - $add_length > 0 ? $offset - $add_length : 0; $length = $length + $add_length; $starts[] = $start; $lengths[] = $length; } $offsets = search_consolidate_substrings($starts, $lengths); } // sort by order of string size descending (which is roughly // the proximity of matched terms) so we can keep the // substrings with terms closest together and discard // the others as needed to fit within $max_length. arsort($offsets); $return_strs = array(); $total_length = 0; foreach ($offsets as $start => $length) { $string = trim(elgg_substr($haystack, $start, $length)); // continue past if adding this substring exceeds max length if ($total_length + $length > $max_length) { continue; } $total_length += $length; $return_strs[$start] = $string; } // put the strings in order of occurence ksort($return_strs); // add ...s where needed $return = implode('...', $return_strs); if (!array_key_exists(0, $return_strs)) { $return = "...{$return}"; } // add to end of string if last substring doesn't hit the end. $starts = array_keys($return_strs); $last_pos = $starts[count($starts) - 1]; if ($last_pos + elgg_strlen($return_strs[$last_pos]) < $haystack_length) { $return .= '...'; } $return = search_highlight_words($words, $return); return $return; }