diff options
Diffstat (limited to 'phpBB/phpbb/search')
-rw-r--r-- | phpBB/phpbb/search/base.php | 12 | ||||
-rw-r--r-- | phpBB/phpbb/search/fulltext_mysql.php | 138 | ||||
-rw-r--r-- | phpBB/phpbb/search/fulltext_native.php | 208 | ||||
-rw-r--r-- | phpBB/phpbb/search/fulltext_postgres.php | 104 | ||||
-rw-r--r-- | phpBB/phpbb/search/fulltext_sphinx.php | 76 | ||||
-rw-r--r-- | phpBB/phpbb/search/sphinx/config.php | 4 | ||||
-rw-r--r-- | phpBB/phpbb/search/sphinx/config_section.php | 6 |
7 files changed, 400 insertions, 148 deletions
diff --git a/phpBB/phpbb/search/base.php b/phpBB/phpbb/search/base.php index d9313dddab..e7d0774b6c 100644 --- a/phpBB/phpbb/search/base.php +++ b/phpBB/phpbb/search/base.php @@ -133,7 +133,7 @@ class base { global $cache, $config, $db, $user; - $length = min(sizeof($id_ary), $config['search_block_size']); + $length = min(count($id_ary), $config['search_block_size']); // nothing to cache so exit if (!$length) @@ -148,7 +148,7 @@ class base if (!($store = $cache->get('_search_results_' . $search_key))) { // add the current keywords to the recent searches in the cache which are listed on the search page - if (!empty($keywords) || sizeof($author_ary)) + if (!empty($keywords) || count($author_ary)) { $sql = 'SELECT search_time FROM ' . SEARCH_RESULTS_TABLE . ' @@ -201,7 +201,7 @@ class base $store += $store_ids; // if the cache is too big - if (sizeof($store) - 2 > 20 * $config['search_block_size']) + if (count($store) - 2 > 20 * $config['search_block_size']) { // remove everything in front of two blocks in front of the current start index for ($i = 0, $n = $id_range[0] - 2 * $config['search_block_size']; $i < $n; $i++) @@ -243,7 +243,7 @@ class base global $db, $cache, $config; // clear all searches that searched for the specified words - if (sizeof($words)) + if (count($words)) { $sql_where = ''; foreach ($words as $word) @@ -264,7 +264,7 @@ class base } // clear all searches that searched for the specified authors - if (is_array($authors) && sizeof($authors)) + if (is_array($authors) && count($authors)) { $sql_where = ''; foreach ($authors as $author) @@ -286,7 +286,7 @@ class base $sql = 'DELETE FROM ' . SEARCH_RESULTS_TABLE . ' - WHERE search_time < ' . (time() - $config['search_store_results']); + WHERE search_time < ' . (time() - (int) $config['search_store_results']); $db->sql_query($sql); } } diff --git a/phpBB/phpbb/search/fulltext_mysql.php b/phpBB/phpbb/search/fulltext_mysql.php index 64a63e83e0..1105d0892f 100644 --- a/phpBB/phpbb/search/fulltext_mysql.php +++ b/phpBB/phpbb/search/fulltext_mysql.php @@ -188,7 +188,7 @@ class fulltext_mysql extends \phpbb\search\base } $sql = 'SHOW VARIABLES - LIKE \'ft\_%\''; + LIKE \'%ft\_%\''; $result = $this->db->sql_query($sql); $mysql_info = array(); @@ -198,8 +198,16 @@ class fulltext_mysql extends \phpbb\search\base } $this->db->sql_freeresult($result); - set_config('fulltext_mysql_max_word_len', $mysql_info['ft_max_word_len']); - set_config('fulltext_mysql_min_word_len', $mysql_info['ft_min_word_len']); + if ($engine === 'MyISAM') + { + $this->config->set('fulltext_mysql_max_word_len', $mysql_info['ft_max_word_len']); + $this->config->set('fulltext_mysql_min_word_len', $mysql_info['ft_min_word_len']); + } + else if ($engine === 'InnoDB') + { + $this->config->set('fulltext_mysql_max_word_len', $mysql_info['innodb_ft_max_token_size']); + $this->config->set('fulltext_mysql_min_word_len', $mysql_info['innodb_ft_min_token_size']); + } return false; } @@ -232,9 +240,9 @@ class fulltext_mysql extends \phpbb\search\base $this->split_words = $matches[1]; // We limit the number of allowed keywords to minimize load on the database - if ($this->config['max_num_search_keywords'] && sizeof($this->split_words) > $this->config['max_num_search_keywords']) + if ($this->config['max_num_search_keywords'] && count($this->split_words) > $this->config['max_num_search_keywords']) { - trigger_error($this->user->lang('MAX_NUM_SEARCH_KEYWORDS_REFINE', (int) $this->config['max_num_search_keywords'], sizeof($this->split_words))); + trigger_error($this->user->lang('MAX_NUM_SEARCH_KEYWORDS_REFINE', (int) $this->config['max_num_search_keywords'], count($this->split_words))); } // to allow phrase search, we need to concatenate quoted words @@ -361,7 +369,7 @@ class fulltext_mysql extends \phpbb\search\base // remove too short or too long words $text = array_values($text); - for ($i = 0, $n = sizeof($text); $i < $n; $i++) + for ($i = 0, $n = count($text); $i < $n; $i++) { $text[$i] = trim($text[$i]); if (utf8_strlen($text[$i]) < $this->config['fulltext_mysql_min_word_len'] || utf8_strlen($text[$i]) > $this->config['fulltext_mysql_max_word_len']) @@ -563,12 +571,12 @@ class fulltext_mysql extends \phpbb\search\base $sql_select = ($type == 'posts') ? $sql_select . 'p.post_id' : 'DISTINCT ' . $sql_select . 't.topic_id'; $sql_from = ($join_topic) ? TOPICS_TABLE . ' t, ' : ''; $field = ($type == 'posts') ? 'post_id' : 'topic_id'; - if (sizeof($author_ary) && $author_name) + if (count($author_ary) && $author_name) { // first one matches post of registered users, second one guests and deleted users $sql_author = ' AND (' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; } - else if (sizeof($author_ary)) + else if (count($author_ary)) { $sql_author = ' AND ' . $this->db->sql_in_set('p.poster_id', $author_ary); } @@ -580,7 +588,7 @@ class fulltext_mysql extends \phpbb\search\base $sql_where_options = $sql_sort_join; $sql_where_options .= ($topic_id) ? ' AND p.topic_id = ' . $topic_id : ''; $sql_where_options .= ($join_topic) ? ' AND t.topic_id = p.topic_id' : ''; - $sql_where_options .= (sizeof($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; + $sql_where_options .= (count($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; $sql_where_options .= ' AND ' . $post_visibility; $sql_where_options .= $sql_author; $sql_where_options .= ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; @@ -591,6 +599,7 @@ class fulltext_mysql extends \phpbb\search\base WHERE MATCH ($sql_match) AGAINST ('" . $this->db->sql_escape(htmlspecialchars_decode($this->search_query)) . "' IN BOOLEAN MODE) $sql_where_options ORDER BY $sql_sort"; + $this->db->sql_return_on_error(true); $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start); while ($row = $this->db->sql_fetchrow($result)) @@ -602,7 +611,7 @@ class fulltext_mysql extends \phpbb\search\base $id_ary = array_unique($id_ary); // if the total result count is not cached yet, retrieve it from the db - if (!$result_count) + if (!$result_count && count($id_ary)) { $sql_found_rows = 'SELECT FOUND_ROWS() as result_count'; $result = $this->db->sql_query($sql_found_rows); @@ -659,7 +668,7 @@ class fulltext_mysql extends \phpbb\search\base public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) { // No author? No posts - if (!sizeof($author_ary)) + if (!count($author_ary)) { return 0; } @@ -736,7 +745,7 @@ class fulltext_mysql extends \phpbb\search\base { $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary); } - $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; + $sql_fora = (count($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; $sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : ''; $sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; $sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : ''; @@ -889,7 +898,7 @@ class fulltext_mysql extends \phpbb\search\base $id_ary = array_unique($id_ary); } - if (sizeof($id_ary)) + if (count($id_ary)) { $this->save_ids($search_key, '', $author_ary, $result_count, $id_ary, $start, $sort_dir); $id_ary = array_slice($id_ary, 0, $per_page); @@ -917,6 +926,34 @@ class fulltext_mysql extends \phpbb\search\base $words = array_unique(array_merge($split_text, $split_title)); + /** + * Event to modify method arguments and words before the MySQL search index is updated + * + * @event core.search_mysql_index_before + * @var string mode Contains the post mode: edit, post, reply, quote + * @var int post_id The id of the post which is modified/created + * @var string message New or updated post content + * @var string subject New or updated post subject + * @var int poster_id Post author's user id + * @var int forum_id The id of the forum in which the post is located + * @var array words List of words added to the index + * @var array split_text Array of words from the message + * @var array split_title Array of words from the title + * @since 3.2.3-RC1 + */ + $vars = array( + 'mode', + 'post_id', + 'message', + 'subject', + 'poster_id', + 'forum_id', + 'words', + 'split_text', + 'split_title', + ); + extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_index_before', compact($vars))); + unset($split_text); unset($split_title); @@ -942,7 +979,7 @@ class fulltext_mysql extends \phpbb\search\base // destroy too old cached search results $this->destroy_cache(array()); - set_config('search_last_gc', time(), true); + $this->config->set('search_last_gc', time(), false); } /** @@ -996,12 +1033,37 @@ class fulltext_mysql extends \phpbb\search\base $alter_list[] = $alter_entry; } - if (sizeof($alter_list)) + $sql_queries = []; + + foreach ($alter_list as $alter) { - foreach ($alter_list as $alter) - { - $this->db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter)); - } + $sql_queries[] = 'ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter); + } + + if (!isset($this->stats['post_text'])) + { + $sql_queries[] = 'ALTER TABLE ' . POSTS_TABLE . ' ADD FULLTEXT post_text (post_text)'; + } + + $stats = $this->stats; + + /** + * Event to modify SQL queries before the MySQL search index is created + * + * @event core.search_mysql_create_index_before + * @var array sql_queries Array with queries for creating the search index + * @var array stats Array with statistics of the current index (read only) + * @since 3.2.3-RC1 + */ + $vars = array( + 'sql_queries', + 'stats', + ); + extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_create_index_before', compact($vars))); + + foreach ($sql_queries as $sql_query) + { + $this->db->sql_query($sql_query); } $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); @@ -1039,9 +1101,37 @@ class fulltext_mysql extends \phpbb\search\base $alter[] = 'DROP INDEX post_content'; } - if (sizeof($alter)) + if (isset($this->stats['post_text'])) { - $this->db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter)); + $alter[] = 'DROP INDEX post_text'; + } + + $sql_queries = []; + + if (count($alter)) + { + $sql_queries[] = 'ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter); + } + + $stats = $this->stats; + + /** + * Event to modify SQL queries before the MySQL search index is deleted + * + * @event core.search_mysql_delete_index_before + * @var array sql_queries Array with queries for deleting the search index + * @var array stats Array with statistics of the current index (read only) + * @since 3.2.3-RC1 + */ + $vars = array( + 'sql_queries', + 'stats', + ); + extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_delete_index_before', compact($vars))); + + foreach ($sql_queries as $sql_query) + { + $this->db->sql_query($sql_query); } $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); @@ -1059,7 +1149,7 @@ class fulltext_mysql extends \phpbb\search\base $this->get_stats(); } - return isset($this->stats['post_subject']) && isset($this->stats['post_content']); + return isset($this->stats['post_subject']) && isset($this->stats['post_content']) && isset($this->stats['post_text']); } /** @@ -1103,6 +1193,10 @@ class fulltext_mysql extends \phpbb\search\base { $this->stats['post_subject'] = $row; } + else if ($row['Key_name'] == 'post_text') + { + $this->stats['post_text'] = $row; + } else if ($row['Key_name'] == 'post_content') { $this->stats['post_content'] = $row; diff --git a/phpBB/phpbb/search/fulltext_native.php b/phpBB/phpbb/search/fulltext_native.php index 63b0b24edf..c83de75eed 100644 --- a/phpBB/phpbb/search/fulltext_native.php +++ b/phpBB/phpbb/search/fulltext_native.php @@ -18,6 +18,13 @@ namespace phpbb\search; */ class fulltext_native extends \phpbb\search\base { + const UTF8_HANGUL_FIRST = "\xEA\xB0\x80"; + const UTF8_HANGUL_LAST = "\xED\x9E\xA3"; + const UTF8_CJK_FIRST = "\xE4\xB8\x80"; + const UTF8_CJK_LAST = "\xE9\xBE\xBB"; + const UTF8_CJK_B_FIRST = "\xF0\xA0\x80\x80"; + const UTF8_CJK_B_LAST = "\xF0\xAA\x9B\x96"; + /** * Associative array holding index stats * @var array @@ -99,7 +106,7 @@ class fulltext_native extends \phpbb\search\base protected $user; /** - * Initialises the fulltext_native search backend with min/max word length and makes sure the UTF-8 normalizer is loaded + * Initialises the fulltext_native search backend with min/max word length * * @param boolean|string &$error is passed by reference and should either be set to false on success or an error message on failure * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object @@ -113,15 +120,11 @@ class fulltext_native extends \phpbb\search\base $this->phpbb_dispatcher = $phpbb_dispatcher; $this->user = $user; - $this->word_length = array('min' => $this->config['fulltext_native_min_chars'], 'max' => $this->config['fulltext_native_max_chars']); + $this->word_length = array('min' => (int) $this->config['fulltext_native_min_chars'], 'max' => (int) $this->config['fulltext_native_max_chars']); /** * Load the UTF tools */ - if (!class_exists('utf_normalizer')) - { - include($this->phpbb_root_path . 'includes/utf/utf_normalizer.' . $this->php_ext); - } if (!function_exists('utf8_decode_ncr')) { include($this->phpbb_root_path . 'includes/utf/utf_tools.' . $this->php_ext); @@ -187,7 +190,7 @@ class fulltext_native extends \phpbb\search\base */ public function split_keywords($keywords, $terms) { - $tokens = '+-|()*'; + $tokens = '+-|()* '; $keywords = trim($this->cleanup($keywords, $tokens)); @@ -221,12 +224,10 @@ class fulltext_native extends \phpbb\search\base $keywords[$i] = '|'; break; case '*': - if ($i === 0 || ($keywords[$i - 1] !== '*' && strcspn($keywords[$i - 1], $tokens) === 0)) + // $i can never be 0 here since $open_bracket is initialised to false + if (strpos($tokens, $keywords[$i - 1]) !== false && ($i + 1 === $n || strpos($tokens, $keywords[$i + 1]) !== false)) { - if ($i === $n - 1 || ($keywords[$i + 1] !== '*' && strcspn($keywords[$i + 1], $tokens) === 0)) - { - $keywords = substr($keywords, 0, $i) . substr($keywords, $i + 1); - } + $keywords[$i] = '|'; } break; } @@ -261,7 +262,7 @@ class fulltext_native extends \phpbb\search\base } } - if ($open_bracket) + if ($open_bracket !== false) { $keywords .= ')'; } @@ -282,7 +283,7 @@ class fulltext_native extends \phpbb\search\base ); $keywords = preg_replace($match, $replace, $keywords); - $num_keywords = sizeof(explode(' ', $keywords)); + $num_keywords = count(explode(' ', $keywords)); // We limit the number of allowed keywords to minimize load on the database if ($this->config['max_num_search_keywords'] && $num_keywords > $this->config['max_num_search_keywords']) @@ -298,12 +299,26 @@ class fulltext_native extends \phpbb\search\base $words = array(); preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#u', $keywords, $words); - if (sizeof($words[1])) + if (count($words[1])) { $keywords = '(' . implode('|', $words[1]) . ')'; } } + // Remove non trailing wildcards from each word to prevent a full table scan (it's now using the database index) + $match = '#\*(?!$|\s)#'; + $replace = '$1'; + $keywords = preg_replace($match, $replace, $keywords); + + // Only allow one wildcard in the search query to limit the database load + $match = '#\*#'; + $replace = '$1'; + $count_wildcards = substr_count($keywords, '*'); + + // Reverse the string to remove all wildcards except the first one + $keywords = strrev(preg_replace($match, $replace, strrev($keywords), $count_wildcards - 1)); + unset($count_wildcards); + // set the search_query which is shown to the user $this->search_query = $keywords; @@ -313,7 +328,7 @@ class fulltext_native extends \phpbb\search\base $common_ids = $words = array(); - if (sizeof($exact_words)) + if (count($exact_words)) { $sql = 'SELECT word_id, word_text, word_common FROM ' . SEARCH_WORDLIST_TABLE . ' @@ -349,9 +364,6 @@ class fulltext_native extends \phpbb\search\base $this->must_not_contain_ids = array(); $this->must_exclude_one_ids = array(); - $mode = ''; - $ignore_no_id = true; - foreach ($query as $word) { if (empty($word)) @@ -409,8 +421,16 @@ class fulltext_native extends \phpbb\search\base { if (strpos($word_part, '*') !== false) { - $id_words[] = '\'' . $this->db->sql_escape(str_replace('*', '%', $word_part)) . '\''; - $non_common_words[] = $word_part; + $len = utf8_strlen(str_replace('*', '', $word_part)); + if ($len >= $this->word_length['min'] && $len <= $this->word_length['max']) + { + $id_words[] = '\'' . $this->db->sql_escape(str_replace('*', '%', $word_part)) . '\''; + $non_common_words[] = $word_part; + } + else + { + $this->common_words[] = $word_part; + } } else if (isset($words[$word_part])) { @@ -426,10 +446,10 @@ class fulltext_native extends \phpbb\search\base } } } - if (sizeof($id_words)) + if (count($id_words)) { sort($id_words); - if (sizeof($id_words) > 1) + if (count($id_words) > 1) { $this->{$mode . '_ids'}[] = $id_words; } @@ -440,7 +460,7 @@ class fulltext_native extends \phpbb\search\base } } // throw an error if we shall not ignore unexistant words - else if (!$ignore_no_id && sizeof($non_common_words)) + else if (!$ignore_no_id && count($non_common_words)) { trigger_error(sprintf($this->user->lang['WORDS_IN_NO_POST'], implode($this->user->lang['COMMA_SEPARATOR'], $non_common_words))); } @@ -480,7 +500,7 @@ class fulltext_native extends \phpbb\search\base } // Return true if all words are not common words - if (sizeof($exact_words) - sizeof($this->common_words) > 0) + if (count($exact_words) - count($this->common_words) > 0) { return true; } @@ -594,7 +614,6 @@ class fulltext_native extends \phpbb\search\base $id_ary = array(); $sql_where = array(); - $group_by = false; $m_num = 0; $w_num = 0; @@ -717,7 +736,7 @@ class fulltext_native extends \phpbb\search\base } } - if (sizeof($this->must_not_contain_ids)) + if (count($this->must_not_contain_ids)) { $sql_array['LEFT_JOIN'][] = array( 'FROM' => array(SEARCH_WORDMATCH_TABLE => 'm' . $m_num), @@ -827,7 +846,7 @@ class fulltext_native extends \phpbb\search\base $sql_where[] = 'p.topic_id = ' . $topic_id; } - if (sizeof($author_ary)) + if (count($author_ary)) { if ($author_name) { @@ -841,7 +860,7 @@ class fulltext_native extends \phpbb\search\base $sql_where[] = $sql_author; } - if (sizeof($ex_fid_ary)) + if (count($ex_fid_ary)) { $sql_where[] = $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true); } @@ -879,7 +898,6 @@ class fulltext_native extends \phpbb\search\base break; - case 'sqlite': case 'sqlite3': $sql_array_count['SELECT'] = ($type == 'posts') ? 'DISTINCT p.post_id' : 'DISTINCT p.topic_id'; $sql = 'SELECT COUNT(' . (($type == 'posts') ? 'post_id' : 'topic_id') . ') as total_results @@ -1012,7 +1030,7 @@ class fulltext_native extends \phpbb\search\base public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) { // No author? No posts - if (!sizeof($author_ary)) + if (!count($author_ary)) { return 0; } @@ -1084,7 +1102,7 @@ class fulltext_native extends \phpbb\search\base { $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary); } - $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; + $sql_fora = (count($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; $sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; $sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : ''; $sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : ''; @@ -1186,7 +1204,7 @@ class fulltext_native extends \phpbb\search\base } else { - if ($this->db->get_sql_layer() == 'sqlite' || $this->db->get_sql_layer() == 'sqlite3') + if ($this->db->get_sql_layer() == 'sqlite3') { $sql = 'SELECT COUNT(topic_id) as total_results FROM (SELECT DISTINCT t.topic_id'; @@ -1203,7 +1221,7 @@ class fulltext_native extends \phpbb\search\base $post_visibility $sql_fora AND t.topic_id = p.topic_id - $sql_time" . (($this->db->get_sql_layer() == 'sqlite' || $this->db->get_sql_layer() == 'sqlite3') ? ')' : ''); + $sql_time" . ($this->db->get_sql_layer() == 'sqlite3' ? ')' : ''); } $result = $this->db->sql_query($sql); @@ -1291,7 +1309,7 @@ class fulltext_native extends \phpbb\search\base $this->db->sql_freeresult($result); } - if (sizeof($id_ary)) + if (count($id_ary)) { $this->save_ids($search_key, '', $author_ary, $total_results, $id_ary, $start, $sort_dir); $id_ary = array_slice($id_ary, 0, $per_page); @@ -1325,7 +1343,6 @@ class fulltext_native extends \phpbb\search\base $match[] = '#\[\/?[a-z0-9\*\+\-]+(?:=.*?)?(?::[a-z])?(\:?[0-9a-z]{5,})\]#'; $min = $this->word_length['min']; - $max = $this->word_length['max']; $isset_min = $min - 1; @@ -1361,9 +1378,9 @@ class fulltext_native extends \phpbb\search\base * Note: this could be optimized. If the codepoint is lower than Hangul's range * we know that it will also be lower than CJK ranges */ - if ((strncmp($word, UTF8_HANGUL_FIRST, 3) < 0 || strncmp($word, UTF8_HANGUL_LAST, 3) > 0) - && (strncmp($word, UTF8_CJK_FIRST, 3) < 0 || strncmp($word, UTF8_CJK_LAST, 3) > 0) - && (strncmp($word, UTF8_CJK_B_FIRST, 4) < 0 || strncmp($word, UTF8_CJK_B_LAST, 4) > 0)) + if ((strncmp($word, self::UTF8_HANGUL_FIRST, 3) < 0 || strncmp($word, self::UTF8_HANGUL_LAST, 3) > 0) + && (strncmp($word, self::UTF8_CJK_FIRST, 3) < 0 || strncmp($word, self::UTF8_CJK_LAST, 3) > 0) + && (strncmp($word, self::UTF8_CJK_B_FIRST, 4) < 0 || strncmp($word, self::UTF8_CJK_B_LAST, 4) > 0)) { $word = strtok(' '); continue; @@ -1436,6 +1453,38 @@ class fulltext_native extends \phpbb\search\base $words['del']['post'] = array(); $words['del']['title'] = array(); } + + /** + * Event to modify method arguments and words before the native search index is updated + * + * @event core.search_native_index_before + * @var string mode Contains the post mode: edit, post, reply, quote + * @var int post_id The id of the post which is modified/created + * @var string message New or updated post content + * @var string subject New or updated post subject + * @var int poster_id Post author's user id + * @var int forum_id The id of the forum in which the post is located + * @var array words Grouped lists of words added to or remove from the index + * @var array split_text Array of words from the message + * @var array split_title Array of words from the title + * @var array cur_words Array of words currently in the index for comparing to new words + * when mode is edit. Empty for other modes. + * @since 3.2.3-RC1 + */ + $vars = array( + 'mode', + 'post_id', + 'message', + 'subject', + 'poster_id', + 'forum_id', + 'words', + 'split_text', + 'split_title', + 'cur_words', + ); + extract($this->phpbb_dispatcher->trigger_event('core.search_native_index_before', compact($vars))); + unset($split_text); unset($split_title); @@ -1446,7 +1495,7 @@ class fulltext_native extends \phpbb\search\base // individual arrays of added and removed words for text and title. What // we need to do now is add the new words (if they don't already exist) // and then add (or remove) matches between the words and this post - if (sizeof($unique_add_words)) + if (count($unique_add_words)) { $sql = 'SELECT word_id, word_text FROM ' . SEARCH_WORDLIST_TABLE . ' @@ -1462,7 +1511,7 @@ class fulltext_native extends \phpbb\search\base $new_words = array_diff($unique_add_words, array_keys($word_ids)); $this->db->sql_transaction('begin'); - if (sizeof($new_words)) + if (count($new_words)) { $sql_ary = array(); @@ -1486,7 +1535,7 @@ class fulltext_native extends \phpbb\search\base { $title_match = ($word_in == 'title') ? 1 : 0; - if (sizeof($word_ary)) + if (count($word_ary)) { $sql_in = array(); foreach ($word_ary as $word) @@ -1515,7 +1564,7 @@ class fulltext_native extends \phpbb\search\base { $title_match = ($word_in == 'title') ? 1 : 0; - if (sizeof($word_ary)) + if (count($word_ary)) { $sql = 'INSERT INTO ' . SEARCH_WORDMATCH_TABLE . ' (post_id, word_id, title_match) SELECT ' . (int) $post_id . ', word_id, ' . (int) $title_match . ' @@ -1546,7 +1595,7 @@ class fulltext_native extends \phpbb\search\base */ public function index_remove($post_ids, $author_ids, $forum_ids) { - if (sizeof($post_ids)) + if (count($post_ids)) { $sql = 'SELECT w.word_id, w.word_text, m.title_match FROM ' . SEARCH_WORDMATCH_TABLE . ' m, ' . SEARCH_WORDLIST_TABLE . ' w @@ -1569,7 +1618,7 @@ class fulltext_native extends \phpbb\search\base } $this->db->sql_freeresult($result); - if (sizeof($title_word_ids)) + if (count($title_word_ids)) { $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' SET word_count = word_count - 1 @@ -1578,7 +1627,7 @@ class fulltext_native extends \phpbb\search\base $this->db->sql_query($sql); } - if (sizeof($message_word_ids)) + if (count($message_word_ids)) { $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' SET word_count = word_count - 1 @@ -1608,7 +1657,7 @@ class fulltext_native extends \phpbb\search\base // carry on ... it's okay ... I know when I'm not wanted boo hoo if (!$this->config['fulltext_native_load_upd']) { - set_config('search_last_gc', time(), true); + $this->config->set('search_last_gc', time(), false); return; } @@ -1633,7 +1682,7 @@ class fulltext_native extends \phpbb\search\base } $this->db->sql_freeresult($result); - if (sizeof($sql_in)) + if (count($sql_in)) { // Flag the words $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . ' @@ -1643,7 +1692,7 @@ class fulltext_native extends \phpbb\search\base // by setting search_last_gc to the new time here we make sure that if a user reloads because the // following query takes too long, he won't run into it again - set_config('search_last_gc', time(), true); + $this->config->set('search_last_gc', time(), false); // Delete the matches $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . ' @@ -1653,13 +1702,13 @@ class fulltext_native extends \phpbb\search\base unset($sql_in); } - if (sizeof($destroy_cache_words)) + if (count($destroy_cache_words)) { // destroy cached search results containing any of the words that are now common or were removed $this->destroy_cache(array_unique($destroy_cache_words)); } - set_config('search_last_gc', time(), true); + $this->config->set('search_last_gc', time(), false); } /** @@ -1667,21 +1716,43 @@ class fulltext_native extends \phpbb\search\base */ public function delete_index($acp_module, $u_action) { + $sql_queries = []; + switch ($this->db->get_sql_layer()) { - case 'sqlite': case 'sqlite3': - $this->db->sql_query('DELETE FROM ' . SEARCH_WORDLIST_TABLE); - $this->db->sql_query('DELETE FROM ' . SEARCH_WORDMATCH_TABLE); - $this->db->sql_query('DELETE FROM ' . SEARCH_RESULTS_TABLE); + $sql_queries[] = 'DELETE FROM ' . SEARCH_WORDLIST_TABLE; + $sql_queries[] = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE; + $sql_queries[] = 'DELETE FROM ' . SEARCH_RESULTS_TABLE; break; default: - $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_WORDLIST_TABLE); - $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_WORDMATCH_TABLE); - $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); + $sql_queries[] = 'TRUNCATE TABLE ' . SEARCH_WORDLIST_TABLE; + $sql_queries[] = 'TRUNCATE TABLE ' . SEARCH_WORDMATCH_TABLE; + $sql_queries[] = 'TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE; break; } + + $stats = $this->stats; + + /** + * Event to modify SQL queries before the native search index is deleted + * + * @event core.search_native_delete_index_before + * @var array sql_queries Array with queries for deleting the search index + * @var array stats Array with statistics of the current index (read only) + * @since 3.2.3-RC1 + */ + $vars = array( + 'sql_queries', + 'stats', + ); + extract($this->phpbb_dispatcher->trigger_event('core.search_native_delete_index_before', compact($vars))); + + foreach ($sql_queries as $sql_query) + { + $this->db->sql_query($sql_query); + } } /** @@ -1689,7 +1760,7 @@ class fulltext_native extends \phpbb\search\base */ public function index_created() { - if (!sizeof($this->stats)) + if (!count($this->stats)) { $this->get_stats(); } @@ -1702,7 +1773,7 @@ class fulltext_native extends \phpbb\search\base */ public function index_stats() { - if (!sizeof($this->stats)) + if (!count($this->stats)) { $this->get_stats(); } @@ -1730,13 +1801,11 @@ class fulltext_native extends \phpbb\search\base * @param string $allowed_chars String of special chars to allow * @param string $encoding Text encoding * @return string Cleaned up text, only alphanumeric chars are left - * - * @todo \normalizer::cleanup being able to be used? */ protected function cleanup($text, $allowed_chars = null, $encoding = 'utf-8') { static $conv = array(), $conv_loaded = array(); - $words = $allow = array(); + $allow = array(); // Convert the text to UTF-8 $encoding = strtolower($encoding); @@ -1758,12 +1827,9 @@ class fulltext_native extends \phpbb\search\base $text = htmlspecialchars_decode(utf8_decode_ncr($text), ENT_QUOTES); /** - * Load the UTF-8 normalizer - * - * If we use it more widely, an instance of that class should be held in a - * a global variable instead + * Normalize to NFC */ - \utf_normalizer::nfc($text); + $text = \Normalizer::normalize($text); /** * The first thing we do is: @@ -1856,9 +1922,9 @@ class fulltext_native extends \phpbb\search\base $utf_char = substr($text, $pos, $utf_len); $pos += $utf_len; - if (($utf_char >= UTF8_HANGUL_FIRST && $utf_char <= UTF8_HANGUL_LAST) - || ($utf_char >= UTF8_CJK_FIRST && $utf_char <= UTF8_CJK_LAST) - || ($utf_char >= UTF8_CJK_B_FIRST && $utf_char <= UTF8_CJK_B_LAST)) + if (($utf_char >= self::UTF8_HANGUL_FIRST && $utf_char <= self::UTF8_HANGUL_LAST) + || ($utf_char >= self::UTF8_CJK_FIRST && $utf_char <= self::UTF8_CJK_LAST) + || ($utf_char >= self::UTF8_CJK_B_FIRST && $utf_char <= self::UTF8_CJK_B_LAST)) { /** * All characters within these ranges are valid diff --git a/phpBB/phpbb/search/fulltext_postgres.php b/phpBB/phpbb/search/fulltext_postgres.php index 04441e6226..2f387e791e 100644 --- a/phpBB/phpbb/search/fulltext_postgres.php +++ b/phpBB/phpbb/search/fulltext_postgres.php @@ -294,7 +294,7 @@ class fulltext_postgres extends \phpbb\search\base // remove too short or too long words $text = array_values($text); - for ($i = 0, $n = sizeof($text); $i < $n; $i++) + for ($i = 0, $n = count($text); $i < $n; $i++) { $text[$i] = trim($text[$i]); if (utf8_strlen($text[$i]) < $this->config['fulltext_postgres_min_word_len'] || utf8_strlen($text[$i]) > $this->config['fulltext_postgres_max_word_len']) @@ -498,17 +498,16 @@ class fulltext_postgres extends \phpbb\search\base ); extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_keywords_main_query_before', compact($vars))); - $sql_select = ($type == 'posts') ? 'p.post_id' : 'DISTINCT t.topic_id'; + $sql_select = ($type == 'posts') ? 'p.post_id' : 'DISTINCT t.topic_id, ' . $sort_by_sql[$sort_key]; $sql_from = ($join_topic) ? TOPICS_TABLE . ' t, ' : ''; $field = ($type == 'posts') ? 'post_id' : 'topic_id'; - $sql_author = (sizeof($author_ary) == 1) ? ' = ' . $author_ary[0] : 'IN (' . implode(', ', $author_ary) . ')'; - if (sizeof($author_ary) && $author_name) + if (count($author_ary) && $author_name) { // first one matches post of registered users, second one guests and deleted users $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; } - else if (sizeof($author_ary)) + else if (count($author_ary)) { $sql_author = ' AND ' . $this->db->sql_in_set('p.poster_id', $author_ary); } @@ -520,13 +519,12 @@ class fulltext_postgres extends \phpbb\search\base $sql_where_options = $sql_sort_join; $sql_where_options .= ($topic_id) ? ' AND p.topic_id = ' . $topic_id : ''; $sql_where_options .= ($join_topic) ? ' AND t.topic_id = p.topic_id' : ''; - $sql_where_options .= (sizeof($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; + $sql_where_options .= (count($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; $sql_where_options .= ' AND ' . $post_visibility; $sql_where_options .= $sql_author; $sql_where_options .= ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; $sql_where_options .= $sql_match_where; - $tmp_sql_match = array(); $sql_match = str_replace(',', " || ' ' ||", $sql_match); $tmp_sql_match = "to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', " . $sql_match . ") @@ to_tsquery ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', '" . $this->db->sql_escape($this->tsearch_query) . "')"; @@ -611,7 +609,7 @@ class fulltext_postgres extends \phpbb\search\base public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) { // No author? No posts - if (!sizeof($author_ary)) + if (!count($author_ary)) { return 0; } @@ -688,7 +686,7 @@ class fulltext_postgres extends \phpbb\search\base { $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary); } - $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; + $sql_fora = (count($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; $sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : ''; $sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; $sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : ''; @@ -838,7 +836,7 @@ class fulltext_postgres extends \phpbb\search\base GROUP BY t.topic_id, $sort_by_sql[$sort_key]"; } - $result = $this->db->sql_query($sql_count); + $this->db->sql_query($sql_count); $result_count = (int) $this->db->sql_fetchfield('result_count'); if (!$result_count) @@ -863,7 +861,7 @@ class fulltext_postgres extends \phpbb\search\base $id_ary = array_unique($id_ary); } - if (sizeof($id_ary)) + if (count($id_ary)) { $this->save_ids($search_key, '', $author_ary, $result_count, $id_ary, $start, $sort_dir); $id_ary = array_slice($id_ary, 0, $per_page); @@ -891,6 +889,34 @@ class fulltext_postgres extends \phpbb\search\base $words = array_unique(array_merge($split_text, $split_title)); + /** + * Event to modify method arguments and words before the PostgreSQL search index is updated + * + * @event core.search_postgres_index_before + * @var string mode Contains the post mode: edit, post, reply, quote + * @var int post_id The id of the post which is modified/created + * @var string message New or updated post content + * @var string subject New or updated post subject + * @var int poster_id Post author's user id + * @var int forum_id The id of the forum in which the post is located + * @var array words Array of words added to the index + * @var array split_text Array of words from the message + * @var array split_title Array of words from the title + * @since 3.2.3-RC1 + */ + $vars = array( + 'mode', + 'post_id', + 'message', + 'subject', + 'poster_id', + 'forum_id', + 'words', + 'split_text', + 'split_title', + ); + extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_index_before', compact($vars))); + unset($split_text); unset($split_title); @@ -916,7 +942,7 @@ class fulltext_postgres extends \phpbb\search\base // destroy too old cached search results $this->destroy_cache(array()); - set_config('search_last_gc', time(), true); + $this->config->set('search_last_gc', time(), false); } /** @@ -937,14 +963,37 @@ class fulltext_postgres extends \phpbb\search\base $this->get_stats(); } + $sql_queries = []; + if (!isset($this->stats['post_subject'])) { - $this->db->sql_query("CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_subject ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_subject))"); + $sql_queries[] = "CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_subject ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_subject))"; } if (!isset($this->stats['post_content'])) { - $this->db->sql_query("CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_content ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_text || ' ' || post_subject))"); + $sql_queries[] = "CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_content ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_text || ' ' || post_subject))"; + } + + $stats = $this->stats; + + /** + * Event to modify SQL queries before the Postgres search index is created + * + * @event core.search_postgres_create_index_before + * @var array sql_queries Array with queries for creating the search index + * @var array stats Array with statistics of the current index (read only) + * @since 3.2.3-RC1 + */ + $vars = array( + 'sql_queries', + 'stats', + ); + extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_create_index_before', compact($vars))); + + foreach ($sql_queries as $sql_query) + { + $this->db->sql_query($sql_query); } $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); @@ -970,14 +1019,37 @@ class fulltext_postgres extends \phpbb\search\base $this->get_stats(); } + $sql_queries = []; + if (isset($this->stats['post_subject'])) { - $this->db->sql_query('DROP INDEX ' . $this->stats['post_subject']['relname']); + $sql_queries[] = 'DROP INDEX ' . $this->stats['post_subject']['relname']; } if (isset($this->stats['post_content'])) { - $this->db->sql_query('DROP INDEX ' . $this->stats['post_content']['relname']); + $sql_queries[] = 'DROP INDEX ' . $this->stats['post_content']['relname']; + } + + $stats = $this->stats; + + /** + * Event to modify SQL queries before the Postgres search index is created + * + * @event core.search_postgres_delete_index_before + * @var array sql_queries Array with queries for deleting the search index + * @var array stats Array with statistics of the current index (read only) + * @since 3.2.3-RC1 + */ + $vars = array( + 'sql_queries', + 'stats', + ); + extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_delete_index_before', compact($vars))); + + foreach ($sql_queries as $sql_query) + { + $this->db->sql_query($sql_query); } $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE); diff --git a/phpBB/phpbb/search/fulltext_sphinx.php b/phpBB/phpbb/search/fulltext_sphinx.php index 0dbc6e33df..227fbd3fd6 100644 --- a/phpBB/phpbb/search/fulltext_sphinx.php +++ b/phpBB/phpbb/search/fulltext_sphinx.php @@ -85,7 +85,7 @@ class fulltext_sphinx /** * Database Tools object - * @var \phpbb\db\tools + * @var \phpbb\db\tools\tools_interface */ protected $db_tools; @@ -143,12 +143,13 @@ class fulltext_sphinx $this->db = $db; $this->auth = $auth; - // Initialize \phpbb\db\tools object - $this->db_tools = new \phpbb\db\tools($this->db); + // Initialize \phpbb\db\tools\tools object + global $phpbb_container; // TODO inject into object + $this->db_tools = $phpbb_container->get('dbal.tools'); if (!$this->config['fulltext_sphinx_id']) { - set_config('fulltext_sphinx_id', unique_id()); + $this->config->set('fulltext_sphinx_id', unique_id()); } $this->id = $this->config['fulltext_sphinx_id']; $this->indexes = 'index_phpbb_' . $this->id . '_delta;index_phpbb_' . $this->id . '_main'; @@ -219,7 +220,7 @@ class fulltext_sphinx } // Move delta to main index each hour - set_config('search_gc', 3600); + $this->config->set('search_gc', 3600); return false; } @@ -291,7 +292,6 @@ class fulltext_sphinx AND p.post_id >= $start AND p.post_id <= $end'), array('sql_query_post', ''), array('sql_query_post_index', 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = $maxid WHERE counter_id = 1'), - array('sql_query_info', 'SELECT * FROM ' . POSTS_TABLE . ' WHERE post_id = $id'), array('sql_attr_uint', 'forum_id'), array('sql_attr_uint', 'topic_id'), array('sql_attr_uint', 'poster_id'), @@ -303,7 +303,7 @@ class fulltext_sphinx array('sql_attr_string', 'post_subject'), ), 'source source_phpbb_' . $this->id . '_delta : source_phpbb_' . $this->id . '_main' => array( - array('sql_query_pre', ''), + array('sql_query_pre', 'SET NAMES \'utf8\''), array('sql_query_range', ''), array('sql_range_step', ''), array('sql_query', 'SELECT @@ -323,6 +323,7 @@ class fulltext_sphinx WHERE p.topic_id = t.topic_id AND p.post_id >= ( SELECT max_doc_id FROM ' . SPHINX_TABLE . ' WHERE counter_id=1 )'), + array('sql_query_post_index', ''), ), 'index index_phpbb_' . $this->id . '_main' => array( array('path', $this->config['fulltext_sphinx_data_path'] . 'index_phpbb_' . $this->id . '_main'), @@ -331,10 +332,10 @@ class fulltext_sphinx array('morphology', 'none'), array('stopwords', ''), array('min_word_len', '2'), - array('charset_type', 'utf-8'), array('charset_table', 'U+FF10..U+FF19->0..9, 0..9, U+FF41..U+FF5A->a..z, U+FF21..U+FF3A->a..z, A..Z->a..z, a..z, U+0149, U+017F, U+0138, U+00DF, U+00FF, U+00C0..U+00D6->U+00E0..U+00F6, U+00E0..U+00F6, U+00D8..U+00DE->U+00F8..U+00FE, U+00F8..U+00FE, U+0100->U+0101, U+0101, U+0102->U+0103, U+0103, U+0104->U+0105, U+0105, U+0106->U+0107, U+0107, U+0108->U+0109, U+0109, U+010A->U+010B, U+010B, U+010C->U+010D, U+010D, U+010E->U+010F, U+010F, U+0110->U+0111, U+0111, U+0112->U+0113, U+0113, U+0114->U+0115, U+0115, U+0116->U+0117, U+0117, U+0118->U+0119, U+0119, U+011A->U+011B, U+011B, U+011C->U+011D, U+011D, U+011E->U+011F, U+011F, U+0130->U+0131, U+0131, U+0132->U+0133, U+0133, U+0134->U+0135, U+0135, U+0136->U+0137, U+0137, U+0139->U+013A, U+013A, U+013B->U+013C, U+013C, U+013D->U+013E, U+013E, U+013F->U+0140, U+0140, U+0141->U+0142, U+0142, U+0143->U+0144, U+0144, U+0145->U+0146, U+0146, U+0147->U+0148, U+0148, U+014A->U+014B, U+014B, U+014C->U+014D, U+014D, U+014E->U+014F, U+014F, U+0150->U+0151, U+0151, U+0152->U+0153, U+0153, U+0154->U+0155, U+0155, U+0156->U+0157, U+0157, U+0158->U+0159, U+0159, U+015A->U+015B, U+015B, U+015C->U+015D, U+015D, U+015E->U+015F, U+015F, U+0160->U+0161, U+0161, U+0162->U+0163, U+0163, U+0164->U+0165, U+0165, U+0166->U+0167, U+0167, U+0168->U+0169, U+0169, U+016A->U+016B, U+016B, U+016C->U+016D, U+016D, U+016E->U+016F, U+016F, U+0170->U+0171, U+0171, U+0172->U+0173, U+0173, U+0174->U+0175, U+0175, U+0176->U+0177, U+0177, U+0178->U+00FF, U+00FF, U+0179->U+017A, U+017A, U+017B->U+017C, U+017C, U+017D->U+017E, U+017E, U+0410..U+042F->U+0430..U+044F, U+0430..U+044F, U+4E00..U+9FFF'), array('min_prefix_len', '0'), array('min_infix_len', '0'), + array('html_strip', '1'), ), 'index index_phpbb_' . $this->id . '_delta : index_phpbb_' . $this->id . '_main' => array( array('path', $this->config['fulltext_sphinx_data_path'] . 'index_phpbb_' . $this->id . '_delta'), @@ -344,14 +345,12 @@ class fulltext_sphinx array('mem_limit', $this->config['fulltext_sphinx_indexer_mem_limit'] . 'M'), ), 'searchd' => array( - array('compat_sphinxql_magics' , '0'), array('listen' , ($this->config['fulltext_sphinx_host'] ? $this->config['fulltext_sphinx_host'] : 'localhost') . ':' . ($this->config['fulltext_sphinx_port'] ? $this->config['fulltext_sphinx_port'] : '9312')), array('log', $this->config['fulltext_sphinx_data_path'] . 'log/searchd.log'), array('query_log', $this->config['fulltext_sphinx_data_path'] . 'log/sphinx-query.log'), array('read_timeout', '5'), array('max_children', '30'), array('pid_file', $this->config['fulltext_sphinx_data_path'] . 'searchd.pid'), - array('max_matches', (string) SPHINX_MAX_MATCHES), array('binlog_path', $this->config['fulltext_sphinx_data_path']), ), ); @@ -403,7 +402,7 @@ class fulltext_sphinx $variable = $section->get_variable_by_name($key); if (!$variable) { - $variable = $section->create_variable($key, $value); + $section->create_variable($key, $value); } else { @@ -412,7 +411,7 @@ class fulltext_sphinx } else { - $variable = $section->create_variable($key, $value); + $section->create_variable($key, $value); } } } @@ -436,7 +435,6 @@ class fulltext_sphinx $match = array('#\sand\s#i', '#\sor\s#i', '#\snot\s#i', '#\+#', '#-#', '#\|#', '#@#'); $replace = array(' & ', ' | ', ' - ', ' +', ' -', ' |', ''); - $replacements = 0; $keywords = preg_replace($match, $replace, $keywords); $this->sphinx->SetMatchMode(SPH_MATCH_EXTENDED); } @@ -479,16 +477,16 @@ class fulltext_sphinx */ public function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) { + global $user, $phpbb_log; + // No keywords? No posts. - if (!strlen($this->search_query) && !sizeof($author_ary)) + if (!strlen($this->search_query) && !count($author_ary)) { return false; } $id_ary = array(); - $join_topic = ($type != 'posts'); - // Sorting if ($type == 'topics') @@ -622,7 +620,7 @@ class fulltext_sphinx break; } - if (sizeof($author_ary)) + if (count($author_ary)) { $this->sphinx->SetFilter('poster_id', $author_ary); } @@ -632,14 +630,14 @@ class fulltext_sphinx // but at least it will also cause the same for normal users. $this->sphinx->SetFilter('post_visibility', array(ITEM_APPROVED)); - if (sizeof($ex_fid_ary)) + if (count($ex_fid_ary)) { // All forums that a user is allowed to access $fid_ary = array_unique(array_intersect(array_keys($this->auth->acl_getf('f_read', true)), array_keys($this->auth->acl_getf('f_search', true)))); // All forums that the user wants to and can search in $search_forums = array_diff($fid_ary, $ex_fid_ary); - if (sizeof($search_forums)) + if (count($search_forums)) { $this->sphinx->SetFilter('forum_id', $search_forums); } @@ -647,8 +645,8 @@ class fulltext_sphinx $this->sphinx->SetFilter('deleted', array(0)); - $this->sphinx->SetLimits($start, (int) $per_page, SPHINX_MAX_MATCHES); - $result = $this->sphinx->Query($search_query_prefix . str_replace('"', '"', $this->search_query), $this->indexes); + $this->sphinx->SetLimits((int) $start, (int) $per_page, max(SPHINX_MAX_MATCHES, (int) $start + $per_page)); + $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('"', '"', $this->search_query)), $this->indexes); // Could be connection to localhost:9312 failed (errno=111, // msg=Connection refused) during rotate, retry if so @@ -656,12 +654,12 @@ class fulltext_sphinx while (!$result && (strpos($this->sphinx->GetLastError(), "errno=111,") !== false) && $retries--) { usleep(SPHINX_CONNECT_WAIT_TIME); - $result = $this->sphinx->Query($search_query_prefix . str_replace('"', '"', $this->search_query), $this->indexes); + $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('"', '"', $this->search_query)), $this->indexes); } if ($this->sphinx->GetLastError()) { - add_log('critical', 'LOG_SPHINX_ERROR', $this->sphinx->GetLastError()); + $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_SPHINX_ERROR', false, array($this->sphinx->GetLastError())); if ($this->auth->acl_get('a_')) { trigger_error($this->user->lang('SPHINX_SEARCH_FAILED', $this->sphinx->GetLastError())); @@ -678,8 +676,8 @@ class fulltext_sphinx { $start = floor(($result_count - 1) / $per_page) * $per_page; - $this->sphinx->SetLimits((int) $start, (int) $per_page, SPHINX_MAX_MATCHES); - $result = $this->sphinx->Query($search_query_prefix . str_replace('"', '"', $this->search_query), $this->indexes); + $this->sphinx->SetLimits((int) $start, (int) $per_page, max(SPHINX_MAX_MATCHES, (int) $start + $per_page)); + $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('"', '"', $this->search_query)), $this->indexes); // Could be connection to localhost:9312 failed (errno=111, // msg=Connection refused) during rotate, retry if so @@ -687,7 +685,7 @@ class fulltext_sphinx while (!$result && (strpos($this->sphinx->GetLastError(), "errno=111,") !== false) && $retries--) { usleep(SPHINX_CONNECT_WAIT_TIME); - $result = $this->sphinx->Query($search_query_prefix . str_replace('"', '"', $this->search_query), $this->indexes); + $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('"', '"', $this->search_query)), $this->indexes); } } @@ -757,6 +755,28 @@ class fulltext_sphinx */ public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) { + /** + * Event to modify method arguments before the Sphinx search index is updated + * + * @event core.search_sphinx_index_before + * @var string mode Contains the post mode: edit, post, reply, quote + * @var int post_id The id of the post which is modified/created + * @var string message New or updated post content + * @var string subject New or updated post subject + * @var int poster_id Post author's user id + * @var int forum_id The id of the forum in which the post is located + * @since 3.2.3-RC1 + */ + $vars = array( + 'mode', + 'post_id', + 'message', + 'subject', + 'poster_id', + 'forum_id', + ); + extract($this->phpbb_dispatcher->trigger_event('core.search_sphinx_index_before', compact($vars))); + if ($mode == 'edit') { $this->sphinx->UpdateAttributes($this->indexes, array('forum_id', 'poster_id'), array((int) $post_id => array((int) $forum_id, (int) $poster_id))); @@ -789,7 +809,7 @@ class fulltext_sphinx } $this->db->sql_freeresult($result); - if (sizeof($post_updates)) + if (count($post_updates)) { $this->sphinx->UpdateAttributes($this->indexes, array('topic_last_post_time'), $post_updates); } @@ -815,7 +835,7 @@ class fulltext_sphinx */ public function tidy($create = false) { - set_config('search_last_gc', time(), true); + $this->config->set('search_last_gc', time(), false); } /** diff --git a/phpBB/phpbb/search/sphinx/config.php b/phpBB/phpbb/search/sphinx/config.php index 675649b460..3205574b45 100644 --- a/phpBB/phpbb/search/sphinx/config.php +++ b/phpBB/phpbb/search/sphinx/config.php @@ -46,7 +46,7 @@ class config */ function get_section_by_name($name) { - for ($i = 0, $size = sizeof($this->sections); $i < $size; $i++) + for ($i = 0, $size = count($this->sections); $i < $size; $i++) { // Make sure this is really a section object and not a comment if (($this->sections[$i] instanceof \phpbb\search\sphinx\config_section) && $this->sections[$i]->get_name() == $name) @@ -67,7 +67,7 @@ class config function add_section($name) { $this->sections[] = new \phpbb\search\sphinx\config_section($name, ''); - return $this->sections[sizeof($this->sections) - 1]; + return $this->sections[count($this->sections) - 1]; } /** diff --git a/phpBB/phpbb/search/sphinx/config_section.php b/phpBB/phpbb/search/sphinx/config_section.php index 14ab3a752c..2fc8b2da17 100644 --- a/phpBB/phpbb/search/sphinx/config_section.php +++ b/phpBB/phpbb/search/sphinx/config_section.php @@ -87,7 +87,7 @@ class config_section */ function get_variable_by_name($name) { - for ($i = 0, $size = sizeof($this->variables); $i < $size; $i++) + for ($i = 0, $size = count($this->variables); $i < $size; $i++) { // Make sure this is a variable object and not a comment if (($this->variables[$i] instanceof \phpbb\search\sphinx\config_variable) && $this->variables[$i]->get_name() == $name) @@ -106,7 +106,7 @@ class config_section */ function delete_variables_by_name($name) { - for ($i = 0, $size = sizeof($this->variables); $i < $size; $i++) + for ($i = 0, $size = count($this->variables); $i < $size; $i++) { // Make sure this is a variable object and not a comment if (($this->variables[$i] instanceof \phpbb\search\sphinx\config_variable) && $this->variables[$i]->get_name() == $name) @@ -129,7 +129,7 @@ class config_section function create_variable($name, $value) { $this->variables[] = new \phpbb\search\sphinx\config_variable($name, $value, ''); - return $this->variables[sizeof($this->variables) - 1]; + return $this->variables[count($this->variables) - 1]; } /** |