Merge PR #865 branch 'dhruvgoel92/feature/sphinx-fulltext-search' into develop

* dhruvgoel92/feature/sphinx-fulltext-search: (57 commits)
  [feature/sphinx-fulltext-search] add sphinx to Authors file
  [feature/sphinx-fulltext-search] add sphinxapi.php file
  [feature/sphinx-fulltext-search] fix auth bug
  [feature/sphinx-fulltext-search] remove unused property
  [feature/sphinx-fulltext-search] use 9312 as default port
  [feature/sphinx-fulltext-search] fix language of host config
  [feature/sphinx-fulltext-search] fix sphinx for arbitary host
  [feature/sphinx-fulltext-search] coding changes acc to phbb conventions
  [feature/sphinx-fulltext-search] fixing comments
  [feature/sphinx-fulltext-search] add trailing slash in language
  [feature/sphinx-fulltext-search] improve port option
  [feature/sphinx-fulltext-search] remove stopwords and config path
  [feature/sphinx-fulltext-search] makes sql host configurable
  [feature/sphinx-fulltext-search] use readonly instead of disabled
  [feature/sphinx-fulltext-search] fix language keys' typo
  [feature/sphinx-fulltext-search] remove note from db_tools
  [feature/sphinx-fulltext-search] add support for postgres
  [feature/sphinx-fulltext-search] add pgsql functionality
  [feature/sphinx-fulltext-search] use Update in sphinx query
  [feature/sphinx-fulltext-search] use CASE instead of IF
  ...
This commit is contained in:
Oleg Pudeyev 2012-07-27 22:27:26 -04:00
commit 7fd1a166da
14 changed files with 3222 additions and 2 deletions

View file

@ -75,6 +75,7 @@ Jabber Class (c) 2006 Flyspray.org, http://www.flyspray.org/
Chora (c) 2000-2006, The Horde Project. http://horde.org/chora/
Horde Project (c) 2000-2006, The Horde Project. http://horde.org/
jQuery (c) 2011, John Resig. http://jquery.com/
Sphinx Technologies Inc (c) 2001-2012 Andrew Aksyonoff, http://sphinxsearch.com/
PHP License, version 3.0:
Pear (c) 2001-2004 PHP Group, http://pear.php.net

View file

@ -0,0 +1,96 @@
source source_phpbb_{SPHINX_ID}_main
{
type = mysql #mysql or pgsql
sql_host = localhost #SQL server host sphinx connects to
sql_user = username
sql_pass = password
sql_db = db_name
sql_port = 3306 #optional, default is 3306 for mysql and 5432 for pgsql
sql_query_pre = SET NAMES 'utf8'
sql_query_pre = UPDATE phpbb_sphinx SET max_doc_id = MAX(post_id) WHERE counter_id = 1
sql_query_range = SELECT MIN(post_id), MAX(post_id) FROM phpbb_posts
sql_range_step = 5000
sql_query = SELECT \
p.post_id AS id, \
p.forum_id, \
p.topic_id, \
p.poster_id, \
CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, \
p.post_time, \
p.post_subject, \
p.post_subject as title, \
p.post_text as data, \
t.topic_last_post_time, \
0 as deleted \
FROM phpbb_posts p, phpbb_topics t \
WHERE \
p.topic_id = t.topic_id \
AND p.post_id >= $start AND p.post_id <= $end
sql_query_post =
sql_query_post_index = UPDATE phpbb_sphinx SET max_doc_id = $maxid WHERE counter_id = 1
sql_query_info = SELECT * FROM phpbb_posts WHERE post_id = $id
sql_attr_uint = forum_id
sql_attr_uint = topic_id
sql_attr_uint = poster_id
sql_attr_bool = topic_first_post
sql_attr_bool = deleted
sql_attr_timestamp = post_time
sql_attr_timestamp = topic_last_post_time
sql_attr_str2ordinal = post_subject
}
source source_phpbb_{SPHINX_ID}_delta : source_phpbb_{SPHINX_ID}_main
{
sql_query_range =
sql_range_step =
sql_query = SELECT \
p.post_id AS id, \
p.forum_id, \
p.topic_id, \
p.poster_id, \
CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, \
p.post_time, \
p.post_subject, \
p.post_subject as title, \
p.post_text as data, \
t.topic_last_post_time, \
0 as deleted \
FROM phpbb_posts p, phpbb_topics t \
WHERE \
p.topic_id = t.topic_id \
AND p.post_id >= ( SELECT max_doc_id FROM phpbb_sphinx WHERE counter_id=1 )
sql_query_pre =
}
index index_phpbb_{SPHINX_ID}_main
{
path = {DATA_PATH}/index_phpbb_{SPHINX_ID}_main
source = source_phpbb_{SPHINX_ID}_main
docinfo = extern
morphology = none
stopwords =
min_word_len = 2
charset_type = utf-8
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
min_prefix_len = 0
min_infix_len = 0
}
index index_phpbb_{SPHINX_ID}_delta : index_phpbb_{SPHINX_ID}_main
{
path = {DATA_PATH}/index_phpbb_{SPHINX_ID}_delta
source = source_phpbb_{SPHINX_ID}_delta
}
indexer
{
mem_limit = 512M
}
searchd
{
compat_sphinxql_magics = 0
listen = localhost:9312
log = {DATA_PATH}/log/searchd.log
query_log = {DATA_PATH}/log/sphinx-query.log
read_timeout = 5
max_children = 30
pid_file = {DATA_PATH}/searchd.pid
max_matches = 20000
binlog_path = {DATA_PATH}
}

View file

@ -598,7 +598,7 @@ class acp_search
{
global $phpbb_root_path, $phpEx, $user;
if (!class_exists($type) || !method_exists($type, 'get_name'))
if (!class_exists($type) || !method_exists($type, 'keyword_search'))
{
$error = $user->lang['NO_SUCH_SEARCH_MODULE'];
return $error;

View file

@ -260,6 +260,7 @@ define('SESSIONS_TABLE', $table_prefix . 'sessions');
define('SESSIONS_KEYS_TABLE', $table_prefix . 'sessions_keys');
define('SITELIST_TABLE', $table_prefix . 'sitelist');
define('SMILIES_TABLE', $table_prefix . 'smilies');
define('SPHINX_TABLE', $table_prefix . 'sphinx');
define('STYLES_TABLE', $table_prefix . 'styles');
define('STYLES_TEMPLATE_TABLE', $table_prefix . 'styles_template');
define('STYLES_TEMPLATE_DATA_TABLE',$table_prefix . 'styles_template_data');

View file

@ -20,7 +20,6 @@ if (!defined('IN_PHPBB'))
* Currently not supported is returning SQL for creating tables.
*
* @package dbal
* @note currently not used within phpBB3, but may be utilized later.
*/
class phpbb_db_tools
{

View file

@ -0,0 +1,804 @@
<?php
/**
*
* @package search
* @copyright (c) 2005 phpBB Group
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
/**
*/
if (!defined('IN_PHPBB'))
{
exit;
}
/**
* @ignore
*/
/**
* This statement is necessary as this file is sometimes included from within a
* function and the variables used are in global space.
*/
global $phpbb_root_path, $phpEx, $table_prefix;
require($phpbb_root_path . 'includes/sphinxapi.' . $phpEx);
define('SPHINX_MAX_MATCHES', 20000);
define('SPHINX_CONNECT_RETRIES', 3);
define('SPHINX_CONNECT_WAIT_TIME', 300);
/**
* fulltext_sphinx
* Fulltext search based on the sphinx search deamon
* @package search
*/
class phpbb_search_fulltext_sphinx
{
private $stats = array();
private $split_words = array();
private $id;
private $indexes;
private $sphinx;
private $auth;
private $config;
private $db;
private $db_tools;
private $dbtype;
private $user;
private $config_file_data = '';
public $search_query;
public $common_words = array();
/**
* Constructor
* Creates a new phpbb_search_fulltext_postgres, which is used as a search backend.
*
* @param string|bool $error Any error that occurs is passed on through this reference variable otherwise false
*/
public function __construct(&$error)
{
global $config, $db, $user, $auth, $phpbb_root_path, $phpEx;
$this->config = $config;
$this->user = $user;
$this->db = $db;
$this->auth = $auth;
if (!class_exists('phpbb_db_tools'))
{
require($phpbb_root_path . 'includes/db/db_tools.' . $phpEx);
}
// Initialize phpbb_db_tools object
$this->db_tools = new phpbb_db_tools($this->db);
if(!$this->config['fulltext_sphinx_id'])
{
set_config('fulltext_sphinx_id', unique_id());
}
$this->id = $this->config['fulltext_sphinx_id'];
$this->indexes = 'index_phpbb_' . $this->id . '_delta;index_phpbb_' . $this->id . '_main';
$this->sphinx = new SphinxClient();
$this->sphinx->SetServer(($this->config['fulltext_sphinx_host'] ? $this->config['fulltext_sphinx_host'] : 'localhost'), ($this->config['fulltext_sphinx_port'] ? (int) $this->config['fulltext_sphinx_port'] : 9312));
$error = false;
}
/**
* Returns the name of this search backend to be displayed to administrators
*
* @return string Name
*
* @access public
*/
public function get_name()
{
return 'Sphinx Fulltext';
}
/**
* Checks permissions and paths, if everything is correct it generates the config file
*
* @return string|bool Language key of the error/incompatiblity encountered, or false if successful
*
* @access public
*/
function init()
{
if ($this->db->sql_layer != 'mysql' && $this->db->sql_layer != 'mysql4' && $this->db->sql_layer != 'mysqli' && $this->db->sql_layer != 'postgres')
{
return $this->user->lang['FULLTEXT_SPHINX_WRONG_DATABASE'];
}
// Move delta to main index each hour
set_config('search_gc', 3600);
return false;
}
/**
* Generates content of sphinx.conf
*
* @return bool True if sphinx.conf content is correctly generated, false otherwise
*
* @access private
*/
function config_generate()
{
global $phpbb_root_path, $phpEx;
// Check if Database is supported by Sphinx
if ($this->db->sql_layer =='mysql' || $this->db->sql_layer == 'mysql4' || $this->db->sql_layer == 'mysqli')
{
$this->dbtype = 'mysql';
}
else if ($this->db->sql_layer == 'postgres')
{
$this->dbtype = 'pgsql';
}
else
{
$this->config_file_data = $this->user->lang('FULLTEXT_SPHINX_WRONG_DATABASE');
return false;
}
// Check if directory paths have been filled
if (!$this->config['fulltext_sphinx_data_path'])
{
$this->config_file_data = $this->user->lang('FULLTEXT_SPHINX_NO_CONFIG_DATA');
return false;
}
include($phpbb_root_path . 'config.' . $phpEx);
/* Now that we're sure everything was entered correctly,
generate a config for the index. We use a config value
fulltext_sphinx_id for this, as it should be unique. */
$config_object = new phpbb_search_sphinx_config($this->config_file_data);
$config_data = array(
'source source_phpbb_' . $this->id . '_main' => array(
array('type', $this->dbtype),
// This config value sql_host needs to be changed incase sphinx and sql are on different servers
array('sql_host', $dbhost),
array('sql_user', $dbuser),
array('sql_pass', $dbpasswd),
array('sql_db', $dbname),
array('sql_port', $dbport),
array('sql_query_pre', 'SET NAMES \'utf8\''),
array('sql_query_pre', 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = (SELECT MAX(post_id) FROM ' . POSTS_TABLE . ') WHERE counter_id = 1'),
array('sql_query_range', 'SELECT MIN(post_id), MAX(post_id) FROM ' . POSTS_TABLE . ''),
array('sql_range_step', '5000'),
array('sql_query', 'SELECT
p.post_id AS id,
p.forum_id,
p.topic_id,
p.poster_id,
CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post,
p.post_time,
p.post_subject,
p.post_subject as title,
p.post_text as data,
t.topic_last_post_time,
0 as deleted
FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t
WHERE
p.topic_id = t.topic_id
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'),
array('sql_attr_bool', 'topic_first_post'),
array('sql_attr_bool', 'deleted'),
array('sql_attr_timestamp' , 'post_time'),
array('sql_attr_timestamp' , 'topic_last_post_time'),
array('sql_attr_str2ordinal', 'post_subject'),
),
'source source_phpbb_' . $this->id . '_delta : source_phpbb_' . $this->id . '_main' => array(
array('sql_query_pre', ''),
array('sql_query_range', ''),
array('sql_range_step', ''),
array('sql_query', 'SELECT
p.post_id AS id,
p.forum_id,
p.topic_id,
p.poster_id,
CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post,
p.post_time,
p.post_subject,
p.post_subject as title,
p.post_text as data,
t.topic_last_post_time,
0 as deleted
FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t
WHERE
p.topic_id = t.topic_id
AND p.post_id >= ( SELECT max_doc_id FROM ' . SPHINX_TABLE . ' WHERE counter_id=1 )'),
),
'index index_phpbb_' . $this->id . '_main' => array(
array('path', $this->config['fulltext_sphinx_data_path'] . 'index_phpbb_' . $this->id . '_main'),
array('source', 'source_phpbb_' . $this->id . '_main'),
array('docinfo', 'extern'),
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'),
),
'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'),
array('source', 'source_phpbb_' . $this->id . '_delta'),
),
'indexer' => array(
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']),
),
);
$non_unique = array('sql_query_pre' => true, 'sql_attr_uint' => true, 'sql_attr_timestamp' => true, 'sql_attr_str2ordinal' => true, 'sql_attr_bool' => true);
$delete = array('sql_group_column' => true, 'sql_date_column' => true, 'sql_str2ordinal_column' => true);
foreach ($config_data as $section_name => $section_data)
{
$section = $config_object->get_section_by_name($section_name);
if (!$section)
{
$section = $config_object->add_section($section_name);
}
foreach ($delete as $key => $void)
{
$section->delete_variables_by_name($key);
}
foreach ($non_unique as $key => $void)
{
$section->delete_variables_by_name($key);
}
foreach ($section_data as $entry)
{
$key = $entry[0];
$value = $entry[1];
if (!isset($non_unique[$key]))
{
$variable = $section->get_variable_by_name($key);
if (!$variable)
{
$variable = $section->create_variable($key, $value);
}
else
{
$variable->set_value($value);
}
}
else
{
$variable = $section->create_variable($key, $value);
}
}
}
$this->config_file_data = $config_object->get_data();
return true;
}
/**
* Splits keywords entered by a user into an array of words stored in $this->split_words
* Stores the tidied search query in $this->search_query
*
* @param string $keywords Contains the keyword as entered by the user
* @param string $terms is either 'all' or 'any'
* @return false if no valid keywords were found and otherwise true
*
* @access public
*/
function split_keywords(&$keywords, $terms)
{
if ($terms == 'all')
{
$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);
}
else
{
$this->sphinx->SetMatchMode(SPH_MATCH_ANY);
}
// Keep quotes and new lines
$keywords = str_replace(array('&quot;', "\n"), array('"', ' '), trim($keywords));
if (strlen($keywords) > 0)
{
$this->search_query = str_replace('"', '&quot;', $keywords);
return true;
}
return false;
}
/**
* Performs a search on keywords depending on display specific params. You have to run split_keywords() first.
*
* @param string $type contains either posts or topics depending on what should be searched for
* @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched)
* @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words)
* @param array $sort_by_sql contains SQL code for the ORDER BY part of a query
* @param string $sort_key is the key of $sort_by_sql for the selected sorting
* @param string $sort_dir is either a or d representing ASC and DESC
* @param string $sort_days specifies the maximum amount of days a post may be old
* @param array $ex_fid_ary specifies an array of forum ids which should not be searched
* @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts
* @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched
* @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty
* @param string $author_name specifies the author match, when ANONYMOUS is also a search-match
* @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered
* @param int $start indicates the first index of the page
* @param int $per_page number of ids each page is supposed to contain
* @return boolean|int total number of results
*
* @access public
*/
function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page)
{
// No keywords? No posts.
if (!strlen($this->search_query) && !sizeof($author_ary))
{
return false;
}
$id_ary = array();
$join_topic = ($type != 'posts');
// Sorting
if ($type == 'topics')
{
switch ($sort_key)
{
case 'a':
$this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'poster_id ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'));
break;
case 'f':
$this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'forum_id ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'));
break;
case 'i':
case 's':
$this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'post_subject ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'));
break;
case 't':
default:
$this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'topic_last_post_time ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'));
break;
}
}
else
{
switch ($sort_key)
{
case 'a':
$this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'poster_id');
break;
case 'f':
$this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'forum_id');
break;
case 'i':
case 's':
$this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'post_subject');
break;
case 't':
default:
$this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'post_time');
break;
}
}
// Most narrow filters first
if ($topic_id)
{
$this->sphinx->SetFilter('topic_id', array($topic_id));
}
$search_query_prefix = '';
switch ($fields)
{
case 'titleonly':
// Only search the title
if ($terms == 'all')
{
$search_query_prefix = '@title ';
}
// Weight for the title
$this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1));
// 1 is first_post, 0 is not first post
$this->sphinx->SetFilter('topic_first_post', array(1));
break;
case 'msgonly':
// Only search the body
if ($terms == 'all')
{
$search_query_prefix = '@data ';
}
// Weight for the body
$this->sphinx->SetFieldWeights(array("title" => 1, "data" => 5));
break;
case 'firstpost':
// More relative weight for the title, also search the body
$this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1));
// 1 is first_post, 0 is not first post
$this->sphinx->SetFilter('topic_first_post', array(1));
break;
default:
// More relative weight for the title, also search the body
$this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1));
break;
}
if (sizeof($author_ary))
{
$this->sphinx->SetFilter('poster_id', $author_ary);
}
if (sizeof($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))
{
$this->sphinx->SetFilter('forum_id', $search_forums);
}
}
$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('&quot;', '"', $this->search_query), $this->indexes);
// Could be connection to localhost:9312 failed (errno=111,
// msg=Connection refused) during rotate, retry if so
$retries = SPHINX_CONNECT_RETRIES;
while (!$result && (strpos($this->sphinx->_error, "errno=111,") !== false) && $retries--)
{
usleep(SPHINX_CONNECT_WAIT_TIME);
$result = $this->sphinx->Query($search_query_prefix . str_replace('&quot;', '"', $this->search_query), $this->indexes);
}
$id_ary = array();
if (isset($result['matches']))
{
if ($type == 'posts')
{
$id_ary = array_keys($result['matches']);
}
else
{
foreach ($result['matches'] as $key => $value)
{
$id_ary[] = $value['attrs']['topic_id'];
}
}
}
else
{
return false;
}
$result_count = $result['total_found'];
$id_ary = array_slice($id_ary, 0, (int) $per_page);
return $result_count;
}
/**
* Performs a search on an author's posts without caring about message contents. Depends on display specific params
*
* @param string $type contains either posts or topics depending on what should be searched for
* @param boolean $firstpost_only if true, only topic starting posts will be considered
* @param array $sort_by_sql contains SQL code for the ORDER BY part of a query
* @param string $sort_key is the key of $sort_by_sql for the selected sorting
* @param string $sort_dir is either a or d representing ASC and DESC
* @param string $sort_days specifies the maximum amount of days a post may be old
* @param array $ex_fid_ary specifies an array of forum ids which should not be searched
* @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts
* @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched
* @param array $author_ary an array of author ids
* @param string $author_name specifies the author match, when ANONYMOUS is also a search-match
* @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered
* @param int $start indicates the first index of the page
* @param int $per_page number of ids each page is supposed to contain
* @return boolean|int total number of results
*
* @access public
*/
function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page)
{
$this->search_query = '';
$this->sphinx->SetMatchMode(SPH_MATCH_FULLSCAN);
$fields = ($firstpost_only) ? 'firstpost' : 'all';
$terms = 'all';
return $this->keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, $id_ary, $start, $per_page);
}
/**
* Updates wordlist and wordmatch tables when a message is posted or changed
*
* @param string $mode Contains the post mode: edit, post, reply, quote
* @param int $post_id The id of the post which is modified/created
* @param string &$message New or updated post content
* @param string &$subject New or updated post subject
* @param int $poster_id Post author's user id
* @param int $forum_id The id of the forum in which the post is located
*
* @access public
*/
function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id)
{
if ($mode == 'edit')
{
$this->sphinx->UpdateAttributes($this->indexes, array('forum_id', 'poster_id'), array((int)$post_id => array((int)$forum_id, (int)$poster_id)));
}
else if ($mode != 'post' && $post_id)
{
// Update topic_last_post_time for full topic
$sql_array = array(
'SELECT' => 'p1.post_id',
'FROM' => array(
POSTS_TABLE => 'p1',
),
'LEFT_JOIN' => array(array(
'FROM' => array(
POSTS_TABLE => 'p2'
),
'ON' => 'p1.topic_id = p2.topic_id',
)),
);
$sql = $this->db->sql_build_query('SELECT', $sql_array);
$result = $this->db->sql_query($sql);
$post_updates = array();
$post_time = time();
while ($row = $this->db->sql_fetchrow($result))
{
$post_updates[(int)$row['post_id']] = array($post_time);
}
$this->db->sql_freeresult($result);
if (sizeof($post_updates))
{
$this->sphinx->UpdateAttributes($this->indexes, array('topic_last_post_time'), $post_updates);
}
}
}
/**
* Delete a post from the index after it was deleted
*
* @access public
*/
function index_remove($post_ids, $author_ids, $forum_ids)
{
$values = array();
foreach ($post_ids as $post_id)
{
$values[$post_id] = array(1);
}
$this->sphinx->UpdateAttributes($this->indexes, array('deleted'), $values);
}
/**
* Nothing needs to be destroyed
*
* @access public
*/
function tidy($create = false)
{
set_config('search_last_gc', time(), true);
}
/**
* Create sphinx table
*
* @return string|bool error string is returned incase of errors otherwise false
*
* @access public
*/
function create_index($acp_module, $u_action)
{
if (!$this->index_created())
{
$table_data = array(
'COLUMNS' => array(
'counter_id' => array('UINT', 0),
'max_doc_id' => array('UINT', 0),
),
'PRIMARY_KEY' => 'counter_id',
);
$this->db_tools->sql_create_table(SPHINX_TABLE, $table_data);
$sql = 'TRUNCATE TABLE ' . SPHINX_TABLE;
$this->db->sql_query($sql);
$data = array(
'counter_id' => '1',
'max_doc_id' => '0',
);
$sql = 'INSERT INTO ' . SPHINX_TABLE . ' ' . $this->db->sql_build_array('INSERT', $data);
$this->db->sql_query($sql);
}
return false;
}
/**
* Drop sphinx table
*
* @return string|bool error string is returned incase of errors otherwise false
*
* @access public
*/
function delete_index($acp_module, $u_action)
{
if (!$this->index_created())
{
return false;
}
$this->db_tools->sql_table_drop(SPHINX_TABLE);
return false;
}
/**
* Returns true if the sphinx table was created
*
* @return bool true if sphinx table was created
*
* @access public
*/
function index_created($allow_new_files = true)
{
$created = false;
if ($this->db_tools->sql_table_exists(SPHINX_TABLE))
{
$created = true;
}
return $created;
}
/**
* Returns an associative array containing information about the indexes
*
* @return string|bool Language string of error false otherwise
*
* @access public
*/
function index_stats()
{
if (empty($this->stats))
{
$this->get_stats();
}
return array(
$this->user->lang['FULLTEXT_SPHINX_MAIN_POSTS'] => ($this->index_created()) ? $this->stats['main_posts'] : 0,
$this->user->lang['FULLTEXT_SPHINX_DELTA_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] - $this->stats['main_posts'] : 0,
$this->user->lang['FULLTEXT_MYSQL_TOTAL_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] : 0,
);
}
/**
* Collects stats that can be displayed on the index maintenance page
*
* @access private
*/
function get_stats()
{
if ($this->index_created())
{
$sql = 'SELECT COUNT(post_id) as total_posts
FROM ' . POSTS_TABLE;
$result = $this->db->sql_query($sql);
$this->stats['total_posts'] = (int) $this->db->sql_fetchfield('total_posts');
$this->db->sql_freeresult($result);
$sql = 'SELECT COUNT(p.post_id) as main_posts
FROM ' . POSTS_TABLE . ' p, ' . SPHINX_TABLE . ' m
WHERE p.post_id <= m.max_doc_id
AND m.counter_id = 1';
$result = $this->db->sql_query($sql);
$this->stats['main_posts'] = (int) $this->db->sql_fetchfield('main_posts');
$this->db->sql_freeresult($result);
}
}
/**
* Returns a list of options for the ACP to display
*
* @return associative array containing template and config variables
*
* @access public
*/
function acp()
{
$config_vars = array(
'fulltext_sphinx_data_path' => 'string',
'fulltext_sphinx_host' => 'string',
'fulltext_sphinx_port' => 'string',
'fulltext_sphinx_indexer_mem_limit' => 'int',
);
$tpl = '
<span class="error">' . $this->user->lang['FULLTEXT_SPHINX_CONFIGURE']. '</span>
<dl>
<dt><label for="fulltext_sphinx_data_path">' . $this->user->lang['FULLTEXT_SPHINX_DATA_PATH'] . ':</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_DATA_PATH_EXPLAIN'] . '</span></dt>
<dd><input id="fulltext_sphinx_data_path" type="text" size="40" maxlength="255" name="config[fulltext_sphinx_data_path]" value="' . $this->config['fulltext_sphinx_data_path'] . '" /></dd>
</dl>
<dl>
<dt><label for="fulltext_sphinx_host">' . $this->user->lang['FULLTEXT_SPHINX_HOST'] . ':</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_HOST_EXPLAIN'] . '</span></dt>
<dd><input id="fulltext_sphinx_host" type="text" size="40" maxlength="255" name="config[fulltext_sphinx_host]" value="' . $this->config['fulltext_sphinx_host'] . '" /></dd>
</dl>
<dl>
<dt><label for="fulltext_sphinx_port">' . $this->user->lang['FULLTEXT_SPHINX_PORT'] . ':</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_PORT_EXPLAIN'] . '</span></dt>
<dd><input id="fulltext_sphinx_port" type="text" size="4" maxlength="10" name="config[fulltext_sphinx_port]" value="' . $this->config['fulltext_sphinx_port'] . '" /></dd>
</dl>
<dl>
<dt><label for="fulltext_sphinx_indexer_mem_limit">' . $this->user->lang['FULLTEXT_SPHINX_INDEXER_MEM_LIMIT'] . ':</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_INDEXER_MEM_LIMIT_EXPLAIN'] . '</span></dt>
<dd><input id="fulltext_sphinx_indexer_mem_limit" type="text" size="4" maxlength="10" name="config[fulltext_sphinx_indexer_mem_limit]" value="' . $this->config['fulltext_sphinx_indexer_mem_limit'] . '" />' . $this->user->lang['MIB'] . '</dd>
</dl>
<dl>
<dt><label for="fulltext_sphinx_config_file">' . $this->user->lang['FULLTEXT_SPHINX_CONFIG_FILE'] . ':</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_CONFIG_FILE_EXPLAIN'] . '</dt>
<dd>' . (($this->config_generate()) ? '<textarea readonly="readonly" rows="6">' . $this->config_file_data . '</textarea>' : $this->config_file_data) . '</dd>
<dl>
';
// These are fields required in the config table
return array(
'tpl' => $tpl,
'config' => $config_vars
);
}
}

View file

@ -0,0 +1,288 @@
<?php
/**
*
* @package search
* @copyright (c) 2005 phpBB Group
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
/**
* phpbb_search_sphinx_config
* An object representing the sphinx configuration
* Can read it from file and write it back out after modification
* @package search
*/
class phpbb_search_sphinx_config
{
private $sections = array();
/**
* Constructor which optionally loads data from a variable
*
* @param string $config_data Variable containing the sphinx configuration data
*
* @access public
*/
function __construct($config_data)
{
if ($config_data != '')
{
$this->read($config_data);
}
}
/**
* Get a section object by its name
*
* @param string $name The name of the section that shall be returned
* @return phpbb_search_sphinx_config_section The section object or null if none was found
*
* @access public
*/
function get_section_by_name($name)
{
for ($i = 0, $size = sizeof($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)
{
return $this->sections[$i];
}
}
}
/**
* Appends a new empty section to the end of the config
*
* @param string $name The name for the new section
* @return phpbb_search_sphinx_config_section The newly created section object
*
* @access public
*/
function add_section($name)
{
$this->sections[] = new phpbb_search_sphinx_config_section($name, '');
return $this->sections[sizeof($this->sections) - 1];
}
/**
* Reads the config file data
*
* @param string $config_data The config file data
*
* @access private
*/
function read($config_data)
{
$this->sections = array();
$section = null;
$found_opening_bracket = false;
$in_value = false;
foreach ($config_data as $i => $line)
{
// If the value of a variable continues to the next line because the line
// break was escaped then we don't trim leading space but treat it as a part of the value
if ($in_value)
{
$line = rtrim($line);
}
else
{
$line = trim($line);
}
// If we're not inside a section look for one
if (!$section)
{
// Add empty lines and comments as comment objects to the section list
// that way they're not deleted when reassembling the file from the sections
if (!$line || $line[0] == '#')
{
$this->sections[] = new phpbb_search_sphinx_config_comment($config_file[$i]);
continue;
}
else
{
// Otherwise we scan the line reading the section name until we find
// an opening curly bracket or a comment
$section_name = '';
$section_name_comment = '';
$found_opening_bracket = false;
for ($j = 0, $length = strlen($line); $j < $length; $j++)
{
if ($line[$j] == '#')
{
$section_name_comment = substr($line, $j);
break;
}
if ($found_opening_bracket)
{
continue;
}
if ($line[$j] == '{')
{
$found_opening_bracket = true;
continue;
}
$section_name .= $line[$j];
}
// And then we create the new section object
$section_name = trim($section_name);
$section = new phpbb_search_sphinx_config_section($section_name, $section_name_comment);
}
}
else
{
// If we're looking for variables inside a section
$skip_first = false;
// If we're not in a value continuing over the line feed
if (!$in_value)
{
// Then add empty lines and comments as comment objects to the variable list
// of this section so they're not deleted on reassembly
if (!$line || $line[0] == '#')
{
$section->add_variable(new phpbb_search_sphinx_config_comment($config_file[$i]));
continue;
}
// As long as we haven't yet actually found an opening bracket for this section
// we treat everything as comments so it's not deleted either
if (!$found_opening_bracket)
{
if ($line[0] == '{')
{
$skip_first = true;
$line = substr($line, 1);
$found_opening_bracket = true;
}
else
{
$section->add_variable(new phpbb_search_sphinx_config_comment($config_file[$i]));
continue;
}
}
}
// If we did not find a comment in this line or still add to the previous
// line's value ...
if ($line || $in_value)
{
if (!$in_value)
{
$name = '';
$value = '';
$comment = '';
$found_assignment = false;
}
$in_value = false;
$end_section = false;
/* ... then we should prase this line char by char:
- first there's the variable name
- then an equal sign
- the variable value
- possibly a backslash before the linefeed in this case we need to continue
parsing the value in the next line
- a # indicating that the rest of the line is a comment
- a closing curly bracket indicating the end of this section*/
for ($j = 0, $length = strlen($line); $j < $length; $j++)
{
if ($line[$j] == '#')
{
$comment = substr($line, $j);
break;
}
else if ($line[$j] == '}')
{
$comment = substr($line, $j + 1);
$end_section = true;
break;
}
else if (!$found_assignment)
{
if ($line[$j] == '=')
{
$found_assignment = true;
}
else
{
$name .= $line[$j];
}
}
else
{
if ($line[$j] == '\\' && $j == $length - 1)
{
$value .= "\n";
$in_value = true;
// Go to the next line and keep processing the value in there
continue 2;
}
$value .= $line[$j];
}
}
// If a name and an equal sign were found then we have append a
// new variable object to the section
if ($name && $found_assignment)
{
$section->add_variable(new phpbb_search_sphinx_config_variable(trim($name), trim($value), ($end_section) ? '' : $comment));
continue;
}
/* If we found a closing curly bracket this section has been completed
and we can append it to the section list and continue with looking for
the next section */
if ($end_section)
{
$section->set_end_comment($comment);
$this->sections[] = $section;
$section = null;
continue;
}
}
// If we did not find anything meaningful up to here, then just treat it
// as a comment
$comment = ($skip_first) ? "\t" . substr(ltrim($config_file[$i]), 1) : $config_file[$i];
$section->add_variable(new phpbb_search_sphinx_config_comment($comment));
}
}
}
/**
* Returns the config data
*
* @return string $data The config data that is generated
*
* @access public
*/
function get_data()
{
$data = "";
foreach ($this->sections as $section)
{
$data .= $section->to_string();
}
return $data;
}
}

View file

@ -0,0 +1,49 @@
<?php
/**
*
* @package search
* @copyright (c) 2005 phpBB Group
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
/**
* phpbb_search_sphinx_config_comment
* Represents a comment inside the sphinx configuration
*/
class phpbb_search_sphinx_config_comment
{
private $exact_string;
/**
* Create a new comment
*
* @param string $exact_string The content of the comment including newlines, leading whitespace, etc.
*
* @access public
*/
function __construct($exact_string)
{
$this->exact_string = $exact_string;
}
/**
* Simply returns the comment as it was created
*
* @return string The exact string that was specified in the constructor
*
* @access public
*/
function to_string()
{
return $this->exact_string;
}
}

View file

@ -0,0 +1,162 @@
<?php
/**
*
* @package search
* @copyright (c) 2005 phpBB Group
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
/**
* phpbb_search_sphinx_config_section
* Represents a single section inside the sphinx configuration
*/
class phpbb_search_sphinx_config_section
{
private $name;
private $comment;
private $end_comment;
private $variables = array();
/**
* Construct a new section
*
* @param string $name Name of the section
* @param string $comment Comment that should be appended after the name in the
* textual format.
*
* @access public
*/
function __construct($name, $comment)
{
$this->name = $name;
$this->comment = $comment;
$this->end_comment = '';
}
/**
* Add a variable object to the list of variables in this section
*
* @param phpbb_search_sphinx_config_variable $variable The variable object
*
* @access public
*/
function add_variable($variable)
{
$this->variables[] = $variable;
}
/**
* Adds a comment after the closing bracket in the textual representation
*
* @param string $end_comment
*
* @access public
*/
function set_end_comment($end_comment)
{
$this->end_comment = $end_comment;
}
/**
* Getter for the name of this section
*
* @return string Section's name
*
* @access public
*/
function get_name()
{
return $this->name;
}
/**
* Get a variable object by its name
*
* @param string $name The name of the variable that shall be returned
* @return phpbb_search_sphinx_config_section The first variable object from this section with the
* given name or null if none was found
*
* @access public
*/
function get_variable_by_name($name)
{
for ($i = 0, $size = sizeof($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)
{
return $this->variables[$i];
}
}
}
/**
* Deletes all variables with the given name
*
* @param string $name The name of the variable objects that are supposed to be removed
*
* @access public
*/
function delete_variables_by_name($name)
{
for ($i = 0, $size = sizeof($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)
{
array_splice($this->variables, $i, 1);
$i--;
}
}
}
/**
* Create a new variable object and append it to the variable list of this section
*
* @param string $name The name for the new variable
* @param string $value The value for the new variable
* @return phpbb_search_sphinx_config_variable Variable object that was created
*
* @access public
*/
function create_variable($name, $value)
{
$this->variables[] = new phpbb_search_sphinx_config_variable($name, $value, '');
return $this->variables[sizeof($this->variables) - 1];
}
/**
* Turns this object into a string which can be written to a config file
*
* @return string Config data in textual form, parsable for sphinx
*
* @access public
*/
function to_string()
{
$content = $this->name . ' ' . $this->comment . "\n{\n";
// Make sure we don't get too many newlines after the opening bracket
while (trim($this->variables[0]->to_string()) == '')
{
array_shift($this->variables);
}
foreach ($this->variables as $variable)
{
$content .= $variable->to_string();
}
$content .= '}' . $this->end_comment . "\n";
return $content;
}
}

View file

@ -0,0 +1,80 @@
<?php
/**
*
* @package search
* @copyright (c) 2005 phpBB Group
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
/**
* phpbb_search_sphinx_config_variable
* Represents a single variable inside the sphinx configuration
*/
class phpbb_search_sphinx_config_variable
{
private $name;
private $value;
private $comment;
/**
* Constructs a new variable object
*
* @param string $name Name of the variable
* @param string $value Value of the variable
* @param string $comment Optional comment after the variable in the
* config file
*
* @access public
*/
function __construct($name, $value, $comment)
{
$this->name = $name;
$this->value = $value;
$this->comment = $comment;
}
/**
* Getter for the variable's name
*
* @return string The variable object's name
*
* @access public
*/
function get_name()
{
return $this->name;
}
/**
* Allows changing the variable's value
*
* @param string $value New value for this variable
*
* @access public
*/
function set_value($value)
{
$this->value = $value;
}
/**
* Turns this object into a string readable by sphinx
*
* @return string Config data in textual form
*
* @access public
*/
function to_string()
{
return "\t" . $this->name . ' = ' . str_replace("\n", "\\\n", $this->value) . ' ' . $this->comment . "\n";
}
}

1712
phpBB/includes/sphinxapi.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -2277,6 +2277,16 @@ function change_database_data(&$no_updates, $version)
set_config('fulltext_postgres_max_word_len', 254);
}
if (!isset($config['fulltext_sphinx_stopwords']))
{
set_config('fulltext_sphinx_stopwords', 0);
}
if (!isset($config['fulltext_sphinx_indexer_mem_limit']))
{
set_config('fulltext_sphinx_indexer_mem_limit', 512);
}
if (!isset($config['load_jquery_cdn']))
{
set_config('load_jquery_cdn', 0);

View file

@ -127,6 +127,8 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_native_mi
INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_postgres_max_word_len', '254');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_postgres_min_word_len', '4');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_postgres_ts_name', 'simple');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_sphinx_indexer_mem_limit', '512');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_sphinx_stopwords', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('gzip_compress', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('hot_threshold', '25');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('icons_path', 'images/icons');

View file

@ -69,6 +69,22 @@ $lang = array_merge($lang, array(
'FULLTEXT_POSTGRES_MIN_WORD_LEN_EXPLAIN' => 'Words with at least this many characters will be included in the query to the database.',
'FULLTEXT_POSTGRES_MAX_WORD_LEN_EXPLAIN' => 'Words with no more than this many characters will be included in the query to the database.',
'FULLTEXT_SPHINX_CONFIGURE' => 'Configure the following settings to generate sphinx config file',
'FULLTEXT_SPHINX_DATA_PATH' => 'Path to data directory',
'FULLTEXT_SPHINX_DATA_PATH_EXPLAIN' => 'It will be used to store the indexes and log files. You should create this directory outside the web accessible directories. (should have a trailing slash)',
'FULLTEXT_SPHINX_DELTA_POSTS' => 'Number of posts in frequently updated delta index',
'FULLTEXT_SPHINX_HOST' => 'Sphinx search daemon host',
'FULLTEXT_SPHINX_HOST_EXPLAIN' => 'Host on which the sphinx search daemon (searchd) listens. Leave empty to use the default localhost',
'FULLTEXT_SPHINX_INDEXER_MEM_LIMIT' => 'Indexer memory limit',
'FULLTEXT_SPHINX_INDEXER_MEM_LIMIT_EXPLAIN' => 'This number should at all times be lower than the RAM available on your machine. If you experience periodic performance problems this might be due to the indexer consuming too many resources. It might help to lower the amount of memory available to the indexer.',
'FULLTEXT_SPHINX_MAIN_POSTS' => 'Number of posts in main index',
'FULLTEXT_SPHINX_PORT' => 'Sphinx search daemon port',
'FULLTEXT_SPHINX_PORT_EXPLAIN' => 'Port on which the sphinx search daemon (searchd) listens. Leave empty to use the default Sphinx API port 9312',
'FULLTEXT_SPHINX_WRONG_DATABASE' => 'The sphinx search for phpBB supports MySQL and PostgreSQL only.',
'FULLTEXT_SPHINX_CONFIG_FILE' => 'Sphinx config file',
'FULLTEXT_SPHINX_CONFIG_FILE_EXPLAIN' => 'The generated content of the sphinx config file. This data needs to be pasted into the sphinx.conf which is used by sphinx search daemon.',
'FULLTEXT_SPHINX_NO_CONFIG_DATA' => 'The sphinx data and config directory paths are not defined. Please define them to generate the config file.',
'GENERAL_SEARCH_SETTINGS' => 'General search settings',
'GO_TO_SEARCH_INDEX' => 'Go to search index page',