2012-05-04 18:39:41 +05:30
< ? php
/**
*
2014-05-27 20:18:06 +02:00
* This file is part of the phpBB Forum Software package .
*
* @ copyright ( c ) phpBB Limited < https :// www . phpbb . com >
* @ license GNU General Public License , version 2 ( GPL - 2.0 )
*
* For full copyright and license information , please see
* the docs / CREDITS . txt file .
2012-05-04 18:39:41 +05:30
*
*/
2013-09-10 14:01:09 +02:00
namespace phpbb\search ;
2012-07-10 03:55:23 +05:30
define ( 'SPHINX_MAX_MATCHES' , 20000 );
define ( 'SPHINX_CONNECT_RETRIES' , 3 );
define ( 'SPHINX_CONNECT_WAIT_TIME' , 300 );
2012-05-04 18:39:41 +05:30
/**
2017-08-15 15:00:12 -04:00
* Fulltext search based on the sphinx search daemon
2012-05-04 18:39:41 +05:30
*/
2013-09-10 14:01:09 +02:00
class fulltext_sphinx
2012-05-04 18:39:41 +05:30
{
2012-08-10 16:26:57 +05:30
/**
* Associative array holding index stats
* @ var array
*/
2012-08-14 17:33:44 +05:30
protected $stats = array ();
2012-08-10 16:26:57 +05:30
/**
2012-08-19 13:04:34 +05:30
* Holds the words entered by user , obtained by splitting the entered query on whitespace
2012-08-10 16:26:57 +05:30
* @ var array
*/
2012-08-14 17:33:44 +05:30
protected $split_words = array ();
2012-08-10 16:26:57 +05:30
/**
* Holds unique sphinx id
* @ var string
*/
2012-08-14 17:33:44 +05:30
protected $id ;
2012-08-10 16:26:57 +05:30
/**
* Stores the names of both main and delta sphinx indexes
2012-08-19 13:08:28 +05:30
* separated by a semicolon
2012-08-10 16:26:57 +05:30
* @ var string
*/
2012-08-14 17:33:44 +05:30
protected $indexes ;
2012-08-10 16:26:57 +05:30
/**
2012-08-19 12:07:06 +05:30
* Sphinx searchd client object
2012-08-10 16:26:57 +05:30
* @ var SphinxClient
*/
2012-08-14 17:33:44 +05:30
protected $sphinx ;
2012-08-10 16:26:57 +05:30
/**
2012-08-14 23:54:46 +05:30
* Relative path to board root
* @ var string
2012-08-10 16:26:57 +05:30
*/
2012-08-14 17:33:44 +05:30
protected $phpbb_root_path ;
2012-08-10 16:26:57 +05:30
/**
2012-08-14 23:54:46 +05:30
* PHP Extension
* @ var string
2012-08-10 16:26:57 +05:30
*/
2012-08-14 17:33:44 +05:30
protected $php_ext ;
2012-08-10 16:26:57 +05:30
/**
2012-08-19 12:07:06 +05:30
* Auth object
2013-09-10 14:01:09 +02:00
* @ var \phpbb\auth\auth
2012-08-10 16:26:57 +05:30
*/
2012-08-14 17:33:44 +05:30
protected $auth ;
2012-08-10 16:26:57 +05:30
/**
2012-08-19 12:07:06 +05:30
* Config object
2013-09-10 14:01:09 +02:00
* @ var \phpbb\config\config
2012-08-10 16:26:57 +05:30
*/
2012-08-14 17:33:44 +05:30
protected $config ;
2012-08-10 16:26:57 +05:30
/**
2012-12-04 04:29:31 -05:00
* Database connection
2014-03-17 13:29:35 +01:00
* @ var \phpbb\db\driver\driver_interface
2012-08-10 16:26:57 +05:30
*/
2012-08-14 17:33:44 +05:30
protected $db ;
2012-08-10 16:26:57 +05:30
/**
2012-08-19 12:07:06 +05:30
* Database Tools object
2014-12-06 16:34:02 +01:00
* @ var \phpbb\db\tools\tools_interface
2012-08-10 16:26:57 +05:30
*/
2012-08-14 17:33:44 +05:30
protected $db_tools ;
2012-08-10 16:26:57 +05:30
/**
* Stores the database type if supported by sphinx
* @ var string
*/
2012-08-14 17:33:44 +05:30
protected $dbtype ;
2012-08-10 16:26:57 +05:30
2015-03-11 17:46:42 +00:00
/**
2015-06-09 12:55:27 +01:00
* phpBB event dispatcher object
2015-03-11 17:46:42 +00:00
* @ var \phpbb\event\dispatcher_interface
*/
protected $phpbb_dispatcher ;
2012-08-10 16:26:57 +05:30
/**
2012-08-19 12:07:06 +05:30
* User object
2013-09-10 14:01:09 +02:00
* @ var \phpbb\user
2012-08-10 16:26:57 +05:30
*/
2012-08-14 17:33:44 +05:30
protected $user ;
2012-08-10 16:26:57 +05:30
/**
* Stores the generated content of the sphinx config file
2012-08-14 17:26:12 +05:30
* @ var string
2012-08-10 16:26:57 +05:30
*/
2012-08-14 17:33:44 +05:30
protected $config_file_data = '' ;
2012-08-10 16:26:57 +05:30
/**
2012-08-20 01:04:43 +05:30
* Contains tidied search query .
* Operators are prefixed in search query and common words excluded
2012-08-10 16:26:57 +05:30
* @ var string
*/
2012-11-09 16:22:32 +05:30
protected $search_query ;
2012-05-04 18:39:41 +05:30
2012-07-01 12:01:14 +05:30
/**
* Constructor
2013-09-10 14:01:09 +02:00
* Creates a new \phpbb\search\fulltext_postgres , which is used as a search backend
2012-07-01 12:01:14 +05:30
*
* @ param string | bool $error Any error that occurs is passed on through this reference variable otherwise false
2014-05-19 04:07:08 +03:00
* @ param string $phpbb_root_path Relative path to phpBB root
2014-08-07 13:19:49 +03:00
* @ param string $phpEx PHP file extension
2014-05-19 04:07:08 +03:00
* @ param \phpbb\auth\auth $auth Auth object
* @ param \phpbb\config\config $config Config object
2021-04-10 10:22:54 +02:00
* @ param \phpbb\db\driver\driver_interface $db Database object
2014-05-19 04:07:08 +03:00
* @ param \phpbb\user $user User object
2015-03-11 17:46:42 +00:00
* @ param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object
2012-07-01 12:01:14 +05:30
*/
2015-03-11 17:46:42 +00:00
public function __construct ( & $error , $phpbb_root_path , $phpEx , $auth , $config , $db , $user , $phpbb_dispatcher )
2012-05-04 18:39:41 +05:30
{
2012-07-28 18:25:26 +05:30
$this -> phpbb_root_path = $phpbb_root_path ;
2012-08-08 11:16:46 +05:30
$this -> php_ext = $phpEx ;
2012-07-10 05:16:42 +05:30
$this -> config = $config ;
2015-03-11 17:46:42 +00:00
$this -> phpbb_dispatcher = $phpbb_dispatcher ;
2012-07-10 05:16:42 +05:30
$this -> user = $user ;
$this -> db = $db ;
$this -> auth = $auth ;
2012-05-04 18:39:41 +05:30
2014-12-06 16:34:02 +01:00
// Initialize \phpbb\db\tools\tools object
2015-01-24 12:06:45 +01:00
global $phpbb_container ; // TODO inject into object
$this -> db_tools = $phpbb_container -> get ( 'dbal.tools' );
2012-07-10 05:23:23 +05:30
2015-06-07 22:53:41 +02:00
if ( ! $this -> config [ 'fulltext_sphinx_id' ])
2012-07-11 16:57:18 +05:30
{
2015-01-11 17:32:31 +01:00
$this -> config -> set ( 'fulltext_sphinx_id' , unique_id ());
2012-07-11 16:57:18 +05:30
}
$this -> id = $this -> config [ 'fulltext_sphinx_id' ];
2012-05-04 18:39:41 +05:30
$this -> indexes = 'index_phpbb_' . $this -> id . '_delta;index_phpbb_' . $this -> id . '_main' ;
2012-07-28 18:50:56 +05:30
if ( ! class_exists ( 'SphinxClient' ))
{
2012-08-08 11:16:46 +05:30
require ( $this -> phpbb_root_path . 'includes/sphinxapi.' . $this -> php_ext );
2012-07-28 18:50:56 +05:30
}
// Initialize sphinx client
2013-09-10 14:01:09 +02:00
$this -> sphinx = new \SphinxClient ();
2012-05-04 18:39:41 +05:30
2012-07-27 02:48:25 +05:30
$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 ));
2012-05-04 18:39:41 +05:30
$error = false ;
}
2012-08-15 14:13:31 +05:30
2012-05-09 19:13:36 +05:30
/**
* Returns the name of this search backend to be displayed to administrators
*
* @ return string Name
*/
public function get_name ()
{
return 'Sphinx Fulltext' ;
}
2012-05-04 18:39:41 +05:30
2012-08-15 14:13:31 +05:30
/**
* Returns the search_query
*
* @ return string search query
*/
public function get_search_query ()
{
return $this -> search_query ;
}
2012-10-04 01:51:57 +05:30
/**
* Returns false as there is no word_len array
*
* @ return false
*/
public function get_word_length ()
{
return false ;
}
2012-08-15 14:13:31 +05:30
/**
2012-11-09 16:08:32 +05:30
* Returns an empty array as there are no common_words
2012-08-15 14:13:31 +05:30
*
* @ return array common words that are ignored by search backend
*/
public function get_common_words ()
{
2012-11-09 16:08:32 +05:30
return array ();
2012-08-15 14:13:31 +05:30
}
2012-05-04 18:39:41 +05:30
/**
* Checks permissions and paths , if everything is correct it generates the config file
2012-07-01 12:01:14 +05:30
*
2017-08-15 15:00:12 -04:00
* @ return string | bool Language key of the error / incompatibility encountered , or false if successful
2012-05-04 18:39:41 +05:30
*/
2012-08-10 14:06:25 +05:30
public function init ()
2012-05-04 18:39:41 +05:30
{
2019-10-06 12:07:35 +02:00
if ( $this -> db -> get_sql_layer () != 'mysqli' && $this -> db -> get_sql_layer () != 'postgres' )
2012-05-04 18:39:41 +05:30
{
2012-07-10 05:16:42 +05:30
return $this -> user -> lang [ 'FULLTEXT_SPHINX_WRONG_DATABASE' ];
2012-05-04 18:39:41 +05:30
}
2012-07-10 05:51:52 +05:30
// Move delta to main index each hour
2015-01-11 17:32:31 +01:00
$this -> config -> set ( 'search_gc' , 3600 );
2012-05-04 18:39:41 +05:30
return false ;
}
2012-07-01 12:01:14 +05:30
/**
2012-07-11 16:25:19 +05:30
* Generates content of sphinx . conf
2012-07-01 12:01:14 +05:30
*
2012-07-11 16:25:19 +05:30
* @ return bool True if sphinx . conf content is correctly generated , false otherwise
2012-07-01 12:01:14 +05:30
*/
2012-08-14 17:33:44 +05:30
protected function config_generate ()
2012-05-04 18:39:41 +05:30
{
2012-07-12 18:08:50 +05:30
// Check if Database is supported by Sphinx
2019-10-06 12:07:35 +02:00
if ( $this -> db -> get_sql_layer () == 'mysqli' )
2012-07-12 18:08:50 +05:30
{
$this -> dbtype = 'mysql' ;
}
2014-06-26 17:17:35 +02:00
else if ( $this -> db -> get_sql_layer () == 'postgres' )
2012-07-12 18:08:50 +05:30
{
$this -> dbtype = 'pgsql' ;
}
else
{
$this -> config_file_data = $this -> user -> lang ( 'FULLTEXT_SPHINX_WRONG_DATABASE' );
return false ;
}
// Check if directory paths have been filled
2012-07-22 03:16:03 +05:30
if ( ! $this -> config [ 'fulltext_sphinx_data_path' ])
2012-07-11 16:25:19 +05:30
{
2012-07-12 18:08:50 +05:30
$this -> config_file_data = $this -> user -> lang ( 'FULLTEXT_SPHINX_NO_CONFIG_DATA' );
2012-07-11 16:25:19 +05:30
return false ;
}
2012-08-08 11:16:46 +05:30
include ( $this -> phpbb_root_path . 'config.' . $this -> php_ext );
2012-05-04 18:39:41 +05:30
2012-07-10 06:38:36 +05:30
/* Now that we ' re sure everything was entered correctly ,
2012-07-11 16:57:18 +05:30
generate a config for the index . We use a config value
fulltext_sphinx_id for this , as it should be unique . */
2013-09-10 14:01:09 +02:00
$config_object = new \phpbb\search\sphinx\config ( $this -> config_file_data );
2012-07-10 06:38:36 +05:30
$config_data = array (
'source source_phpbb_' . $this -> id . '_main' => array (
2013-03-16 01:18:15 +01:00
array ( 'type' , $this -> dbtype . ' # mysql or pgsql' ),
2012-07-26 17:32:06 +05:30
// This config value sql_host needs to be changed incase sphinx and sql are on different servers
2013-03-16 01:18:15 +01:00
array ( 'sql_host' , $dbhost . ' # SQL server host sphinx connects to' ),
2014-10-18 12:32:39 -04:00
array ( 'sql_user' , '[dbuser]' ),
array ( 'sql_pass' , '[dbpassword]' ),
2012-07-10 06:38:36 +05:30
array ( 'sql_db' , $dbname ),
2013-03-16 01:18:15 +01:00
array ( 'sql_port' , $dbport . ' # optional, default is 3306 for mysql and 5432 for pgsql' ),
2012-07-12 04:28:55 +05:30
array ( 'sql_query_pre' , 'SET NAMES \'utf8\'' ),
2012-07-12 17:22:03 +05:30
array ( 'sql_query_pre' , 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = (SELECT MAX(post_id) FROM ' . POSTS_TABLE . ') WHERE counter_id = 1' ),
2012-07-10 06:38:36 +05:30
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 ,
2013-03-14 12:10:07 +01:00
p . post_visibility ,
2012-07-12 16:30:45 +05:30
CASE WHEN p . post_id = t . topic_first_post_id THEN 1 ELSE 0 END as topic_first_post ,
2012-07-10 06:38:36 +05:30
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' , '' ),
2012-07-12 17:22:03 +05:30
array ( 'sql_query_post_index' , 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = $maxid WHERE counter_id = 1' ),
2012-07-10 06:38:36 +05:30
array ( 'sql_attr_uint' , 'forum_id' ),
array ( 'sql_attr_uint' , 'topic_id' ),
array ( 'sql_attr_uint' , 'poster_id' ),
2013-03-14 12:10:07 +01:00
array ( 'sql_attr_uint' , 'post_visibility' ),
2012-07-10 06:38:36 +05:30
array ( 'sql_attr_bool' , 'topic_first_post' ),
array ( 'sql_attr_bool' , 'deleted' ),
2014-03-09 01:17:36 +05:30
array ( 'sql_attr_timestamp' , 'post_time' ),
array ( 'sql_attr_timestamp' , 'topic_last_post_time' ),
2014-03-09 01:16:13 +05:30
array ( 'sql_attr_string' , 'post_subject' ),
2012-07-10 06:38:36 +05:30
),
'source source_phpbb_' . $this -> id . '_delta : source_phpbb_' . $this -> id . '_main' => array (
2017-10-24 20:35:25 +07:00
array ( 'sql_query_pre' , 'SET NAMES \'utf8\'' ),
2012-07-10 06:38:36 +05:30
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 ,
2013-03-14 12:10:07 +01:00
p . post_visibility ,
2012-07-12 16:30:45 +05:30
CASE WHEN p . post_id = t . topic_first_post_id THEN 1 ELSE 0 END as topic_first_post ,
2012-07-10 06:38:36 +05:30
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 ) ' ),
2017-10-24 20:35:25 +07:00
array ( 'sql_query_post_index' , '' ),
2012-07-10 06:38:36 +05:30
),
'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' ),
2012-07-22 03:16:03 +05:30
array ( 'stopwords' , '' ),
2020-01-04 00:29:24 +11:00
array ( 'wordforms' , ' # optional, specify path to wordforms file. See ./docs/sphinx_wordforms.txt for example' ),
array ( 'exceptions' , ' # optional, specify path to exceptions file. See ./docs/sphinx_exceptions.txt for example' ),
2012-07-10 06:38:36 +05:30
array ( 'min_word_len' , '2' ),
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' ),
2020-01-04 00:29:24 +11:00
array ( 'ignore_chars' , 'U+0027, U+002C' ),
array ( 'min_prefix_len' , '3 # Minimum number of characters for wildcard searches by prefix (min 1). Default is 3. If specified, set min_infix_len to 0' ),
array ( 'min_infix_len' , '0 # Minimum number of characters for wildcard searches by infix (min 2). If specified, set min_prefix_len to 0' ),
2019-12-27 09:45:45 +11:00
array ( 'html_strip' , '1' ),
2020-01-04 00:29:24 +11:00
array ( 'index_exact_words' , '0 # Set to 1 to enable exact search operator. Requires wordforms or morphology' ),
array ( 'blend_chars' , 'U+23, U+24, U+25, U+26, U+40' ),
2012-07-10 06:38:36 +05:30
),
'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 (
2012-07-27 02:48:25 +05:30
array ( 'listen' , ( $this -> config [ 'fulltext_sphinx_host' ] ? $this -> config [ 'fulltext_sphinx_host' ] : 'localhost' ) . ':' . ( $this -> config [ 'fulltext_sphinx_port' ] ? $this -> config [ 'fulltext_sphinx_port' ] : '9312' )),
2012-07-10 06:38:36 +05:30
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 ( 'binlog_path' , $this -> config [ 'fulltext_sphinx_data_path' ]),
),
);
2012-05-04 18:39:41 +05:30
2012-07-10 06:38:36 +05:30
$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 );
2015-08-15 14:46:09 +07:00
/**
* Allow adding / changing the Sphinx configuration data
*
* @ event core . search_sphinx_modify_config_data
* @ var array config_data Array with the Sphinx configuration data
* @ var array non_unique Array with the Sphinx non - unique variables to delete
* @ var array delete Array with the Sphinx variables to delete
* @ since 3.1 . 7 - RC1
*/
$vars = array (
'config_data' ,
'non_unique' ,
'delete' ,
);
extract ( $this -> phpbb_dispatcher -> trigger_event ( 'core.search_sphinx_modify_config_data' , compact ( $vars )));
2012-07-10 06:38:36 +05:30
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 );
}
2012-05-04 18:39:41 +05:30
2012-07-10 06:38:36 +05:30
foreach ( $delete as $key => $void )
2012-05-04 18:39:41 +05:30
{
2012-07-10 06:38:36 +05:30
$section -> delete_variables_by_name ( $key );
}
2012-05-04 18:39:41 +05:30
2012-07-10 06:38:36 +05:30
foreach ( $non_unique as $key => $void )
{
$section -> delete_variables_by_name ( $key );
}
2012-05-04 18:39:41 +05:30
2012-07-10 06:38:36 +05:30
foreach ( $section_data as $entry )
{
$key = $entry [ 0 ];
$value = $entry [ 1 ];
2012-05-04 18:39:41 +05:30
2012-07-10 06:38:36 +05:30
if ( ! isset ( $non_unique [ $key ]))
2012-05-04 18:39:41 +05:30
{
2012-07-10 06:38:36 +05:30
$variable = $section -> get_variable_by_name ( $key );
if ( ! $variable )
2012-05-04 18:39:41 +05:30
{
2015-12-03 18:19:02 +01:00
$section -> create_variable ( $key , $value );
2012-05-04 18:39:41 +05:30
}
else
{
2012-07-10 06:38:36 +05:30
$variable -> set_value ( $value );
2012-05-04 18:39:41 +05:30
}
}
2012-07-10 06:38:36 +05:30
else
{
2015-12-03 18:19:02 +01:00
$section -> create_variable ( $key , $value );
2012-07-10 06:38:36 +05:30
}
2012-05-04 18:39:41 +05:30
}
2012-07-10 06:38:36 +05:30
}
$this -> config_file_data = $config_object -> get_data ();
2012-05-04 18:39:41 +05:30
2012-07-11 16:25:19 +05:30
return true ;
2012-05-04 18:39:41 +05:30
}
/**
* 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
*/
2012-08-10 14:06:25 +05:30
public function split_keywords ( & $keywords , $terms )
2012-05-04 18:39:41 +05:30
{
2020-01-04 00:29:24 +11:00
// Keep quotes and new lines
2020-01-04 04:15:10 +11:00
$keywords = str_replace ([ '"' , " \n " ], [ '"' , ' ' ], trim ( $keywords ));
2020-01-04 00:29:24 +11:00
2012-05-04 18:39:41 +05:30
if ( $terms == 'all' )
{
2020-01-04 00:29:24 +11:00
// Replaces verbal operators OR and NOT with special characters | and -, unless appearing within quotation marks
2020-01-04 04:15:10 +11:00
$match = [ '#\sor\s(?=([^"]*"[^"]*")*[^"]*$)#i' , '#\snot\s(?=([^"]*"[^"]*")*[^"]*$)#i' ];
$replace = [ ' | ' , ' -' ];
2012-05-04 18:39:41 +05:30
$keywords = preg_replace ( $match , $replace , $keywords );
$this -> sphinx -> SetMatchMode ( SPH_MATCH_EXTENDED );
}
else
{
2020-02-12 16:42:53 +11:00
$match = [ '\\' , '(' , ')' , '|' , '!' , '@' , '~' , '/' , '^' , '$' , '=' , '&' , '<' , '>' ];
2020-01-04 00:29:24 +11:00
2020-02-12 16:42:53 +11:00
$keywords = str_replace ( $match , ' ' , $keywords );
2012-05-04 18:39:41 +05:30
$this -> sphinx -> SetMatchMode ( SPH_MATCH_ANY );
}
if ( strlen ( $keywords ) > 0 )
{
$this -> search_query = str_replace ( '"' , '"' , $keywords );
return true ;
}
return false ;
}
2020-01-04 00:29:24 +11:00
/**
* Cleans search query passed into Sphinx search engine , as follows :
2020-01-04 03:36:35 +11:00
* 1. Hyphenated words are replaced with keyword search for either the exact phrase with spaces
* or as a single word without spaces eg search for " know-it-all " becomes ( " know it all " | " knowitall* " )
2020-01-04 00:29:24 +11:00
* 2. Words with apostrophes are contracted eg " it's " becomes " its "
* 3. < , > , " and & are decoded from HTML entities.
* 4. Following special characters used as search operators in Sphinx are preserved when used with correct syntax :
2020-01-04 03:36:35 +11:00
* ( a ) quorum matching : " the world is a wonderful place " / 3
* Finds 3 of the words within the phrase . Number must be between 1 and 9.
* ( b ) proximity search : " hello world " ~ 10
* Finds hello and world within 10 words of each other . Number can be between 1 and 99.
* ( c ) strict word order : aaa << bbb << ccc
* Finds " aaa " only where it appears before " bbb " and only where " bbb " appears before " ccc " .
* ( d ) exact match operator : if lemmatizer or stemming enabled ,
* search will find exact match only and ignore other grammatical forms of the same word stem .
* eg . raining = cats and = dogs
* will not return " raining cat and dog "
* eg . = " search this exact phrase "
* will not return " searched this exact phrase " , " searching these exact phrases " .
* 5. Special characters / , ~ , << and = not complying with the correct syntax
* and other reserved operators are escaped and searched literally .
* Special characters not explicitly listed in charset_table or blend_chars in sphinx . conf
* will not be indexed and keywords containing them will be ignored by Sphinx .
* By default , only $ , % , & and @ characters are indexed and searchable .
* String transformation is in backend only and not visible to the end user
* nor reflected in the results page URL or keyword highlighting .
*
* @ param string $search_string
* @ return string
2020-01-04 00:29:24 +11:00
*/
public function sphinx_clean_search_string ( $search_string )
{
2020-01-04 04:15:10 +11:00
$from = [ '@' , '^' , '$' , '!' , '<' , '>' , '"' , '&' , '\'' ];
$to = [ '\@' , '\^' , '\$' , '\!' , '<' , '>' , '"' , '&' , '' ];
2020-01-04 03:36:35 +11:00
2020-01-04 00:29:24 +11:00
$search_string = str_replace ( $from , $to , $search_string );
2020-01-04 03:36:35 +11:00
2020-01-04 00:29:24 +11:00
$search_string = strrev ( $search_string );
2020-01-04 04:15:10 +11:00
$search_string = preg_replace ([ '#\/(?!"[^"]+")#' , '#~(?!"[^"]+")#' ], [ '/\\' , '~\\' ], $search_string );
2020-01-04 00:29:24 +11:00
$search_string = strrev ( $search_string );
2020-01-04 03:36:35 +11:00
2020-01-04 04:15:10 +11:00
$match = [ '#(/|\\\\/)(?)#' , '#(~|\\\\~)(?!\d{1,2}(\s|$))#' , '#((?:\p{L}|\p{N})+)-((?:\p{L}|\p{N})+)(?:-((?:\p{L}|\p{N})+))?(?:-((?:\p{L}|\p{N})+))?#i' , '#<<\s*$#' , '#(\S\K=|=(?=\s)|=$)#' ];
$replace = [ '\/' , '\~' , '("$1 $2 $3 $4"|$1$2$3$4*)' , '\<\<' , '\=' ];
2020-01-04 03:36:35 +11:00
2020-01-04 00:29:24 +11:00
$search_string = preg_replace ( $match , $replace , $search_string );
$search_string = preg_replace ( '#\s+"\|#' , '"|' , $search_string );
2020-01-04 03:36:35 +11:00
2020-01-04 00:29:24 +11:00
/**
2020-01-04 03:36:35 +11:00
* OPTIONAL : Thousands separator stripped from numbers , eg search for '90,000' is queried as '90000' .
2020-01-04 00:29:24 +11:00
* By default commas are stripped from search index so that '90,000' is indexed as '90000'
*/
2020-01-04 03:36:35 +11:00
// $search_string = preg_replace('#[0-9]{1,3}\K,(?=[0-9]{3})#', '', $search_string);
2020-01-04 00:29:24 +11:00
return $search_string ;
}
2012-05-04 18:39:41 +05:30
/**
2012-08-15 23:49:51 +05:30
* Performs a search on keywords depending on display specific params . You have to run split_keywords () first
2012-05-04 18:39:41 +05:30
*
* @ 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
2012-08-30 22:20:52 +02:00
* @ param string $post_visibility specifies which types of posts the user can view in which forums
2012-05-04 18:39:41 +05:30
* @ 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
*/
2013-03-03 20:06:52 +01:00
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 )
2012-05-04 18:39:41 +05:30
{
2015-01-05 22:21:31 +01:00
global $user , $phpbb_log ;
2012-05-04 18:39:41 +05:30
// No keywords? No posts.
2017-06-28 00:58:03 +07:00
if ( ! strlen ( $this -> search_query ) && ! count ( $author_ary ))
2012-05-04 18:39:41 +05:30
{
return false ;
}
$id_ary = array ();
2012-07-10 06:07:42 +05:30
// Sorting
2012-05-04 18:39:41 +05:30
if ( $type == 'topics' )
{
switch ( $sort_key )
{
case 'a' :
$this -> sphinx -> SetGroupBy ( 'topic_id' , SPH_GROUPBY_ATTR , 'poster_id ' . (( $sort_dir == 'a' ) ? 'ASC' : 'DESC' ));
break ;
2012-07-26 16:55:11 +05:30
2012-05-04 18:39:41 +05:30
case 'f' :
$this -> sphinx -> SetGroupBy ( 'topic_id' , SPH_GROUPBY_ATTR , 'forum_id ' . (( $sort_dir == 'a' ) ? 'ASC' : 'DESC' ));
break ;
2012-07-26 16:55:11 +05:30
2012-05-04 18:39:41 +05:30
case 'i' :
2012-07-26 16:55:11 +05:30
2012-05-04 18:39:41 +05:30
case 's' :
$this -> sphinx -> SetGroupBy ( 'topic_id' , SPH_GROUPBY_ATTR , 'post_subject ' . (( $sort_dir == 'a' ) ? 'ASC' : 'DESC' ));
break ;
2012-07-26 16:55:11 +05:30
2012-05-04 18:39:41 +05:30
case 't' :
2012-07-26 16:55:11 +05:30
2012-05-04 18:39:41 +05:30
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 ;
2012-07-26 16:55:11 +05:30
2012-05-04 18:39:41 +05:30
case 'f' :
$this -> sphinx -> SetSortMode (( $sort_dir == 'a' ) ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC , 'forum_id' );
break ;
2012-07-26 16:55:11 +05:30
2012-05-04 18:39:41 +05:30
case 'i' :
2012-07-26 16:55:11 +05:30
2012-05-04 18:39:41 +05:30
case 's' :
$this -> sphinx -> SetSortMode (( $sort_dir == 'a' ) ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC , 'post_subject' );
break ;
2012-07-26 16:55:11 +05:30
2012-05-04 18:39:41 +05:30
case 't' :
2012-07-26 16:55:11 +05:30
2012-05-04 18:39:41 +05:30
default :
$this -> sphinx -> SetSortMode (( $sort_dir == 'a' ) ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC , 'post_time' );
break ;
}
}
2012-07-10 05:51:52 +05:30
// Most narrow filters first
2012-05-04 18:39:41 +05:30
if ( $topic_id )
{
$this -> sphinx -> SetFilter ( 'topic_id' , array ( $topic_id ));
}
2015-08-15 14:46:09 +07:00
/**
* Allow modifying the Sphinx search options
*
* @ event core . search_sphinx_keywords_modify_options
* @ var string type Searching type ( 'posts' , 'topics' )
* @ var string fields Searching fields ( 'titleonly' , 'msgonly' , 'firstpost' , 'all' )
* @ var string terms Searching terms ( 'all' , 'any' )
* @ var int sort_days Time , in days , of the oldest possible post to list
* @ var string sort_key The sort type used from the possible sort types
* @ var int topic_id Limit the search to this topic_id only
* @ var array ex_fid_ary Which forums not to search on
* @ var string post_visibility Post visibility data
* @ var array author_ary Array of user_id containing the users to filter the results to
* @ var string author_name The username to search on
* @ var object sphinx The Sphinx searchd client object
* @ since 3.1 . 7 - RC1
*/
$sphinx = $this -> sphinx ;
$vars = array (
'type' ,
'fields' ,
'terms' ,
'sort_days' ,
'sort_key' ,
'topic_id' ,
'ex_fid_ary' ,
'post_visibility' ,
'author_ary' ,
'author_name' ,
'sphinx' ,
);
extract ( $this -> phpbb_dispatcher -> trigger_event ( 'core.search_sphinx_keywords_modify_options' , compact ( $vars )));
$this -> sphinx = $sphinx ;
unset ( $sphinx );
2012-05-04 18:39:41 +05:30
$search_query_prefix = '' ;
2012-07-10 06:07:42 +05:30
switch ( $fields )
2012-05-04 18:39:41 +05:30
{
case 'titleonly' :
2012-07-10 05:51:52 +05:30
// Only search the title
2012-05-04 18:39:41 +05:30
if ( $terms == 'all' )
{
$search_query_prefix = '@title ' ;
}
2012-07-10 05:51:52 +05:30
// 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 ));
2012-05-04 18:39:41 +05:30
break ;
case 'msgonly' :
2012-07-10 05:51:52 +05:30
// Only search the body
2012-05-04 18:39:41 +05:30
if ( $terms == 'all' )
{
$search_query_prefix = '@data ' ;
}
2012-07-10 05:51:52 +05:30
// Weight for the body
$this -> sphinx -> SetFieldWeights ( array ( " title " => 1 , " data " => 5 ));
2012-05-04 18:39:41 +05:30
break ;
case 'firstpost' :
2012-07-10 05:51:52 +05:30
// 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 ));
2012-05-04 18:39:41 +05:30
break ;
default :
2012-07-10 05:51:52 +05:30
// More relative weight for the title, also search the body
$this -> sphinx -> SetFieldWeights ( array ( " title " => 5 , " data " => 1 ));
2012-05-04 18:39:41 +05:30
break ;
}
2017-06-28 00:58:03 +07:00
if ( count ( $author_ary ))
2012-05-04 18:39:41 +05:30
{
$this -> sphinx -> SetFilter ( 'poster_id' , $author_ary );
}
2013-03-14 12:10:07 +01:00
// As this is not simply possible at the moment, we limit the result to approved posts.
// This will make it impossible for moderators to search unapproved and softdeleted posts,
// but at least it will also cause the same for normal users.
$this -> sphinx -> SetFilter ( 'post_visibility' , array ( ITEM_APPROVED ));
2017-06-28 00:58:03 +07:00
if ( count ( $ex_fid_ary ))
2012-05-04 18:39:41 +05:30
{
// All forums that a user is allowed to access
2012-07-27 10:50:20 +05:30
$fid_ary = array_unique ( array_intersect ( array_keys ( $this -> auth -> acl_getf ( 'f_read' , true )), array_keys ( $this -> auth -> acl_getf ( 'f_search' , true ))));
2012-05-04 18:39:41 +05:30
// All forums that the user wants to and can search in
$search_forums = array_diff ( $fid_ary , $ex_fid_ary );
2017-06-28 00:58:03 +07:00
if ( count ( $search_forums ))
2012-05-04 18:39:41 +05:30
{
$this -> sphinx -> SetFilter ( 'forum_id' , $search_forums );
}
}
$this -> sphinx -> SetFilter ( 'deleted' , array ( 0 ));
2019-12-23 21:36:13 +01:00
$this -> sphinx -> SetLimits (( int ) $start , ( int ) $per_page , max ( SPHINX_MAX_MATCHES , ( int ) $start + $per_page ));
2020-06-02 07:43:27 +02:00
$result = $this -> sphinx -> Query ( $search_query_prefix . $this -> sphinx_clean_search_string ( str_replace ( '"' , '"' , $this -> search_query )), $this -> indexes );
2012-05-04 18:39:41 +05:30
2012-08-10 12:33:25 +05:30
// 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 -> GetLastError (), " errno=111, " ) !== false ) && $retries -- )
{
usleep ( SPHINX_CONNECT_WAIT_TIME );
2020-06-02 07:43:27 +02:00
$result = $this -> sphinx -> Query ( $search_query_prefix . $this -> sphinx_clean_search_string ( str_replace ( '"' , '"' , $this -> search_query )), $this -> indexes );
2012-08-10 12:33:25 +05:30
}
2012-08-01 22:18:12 +05:30
if ( $this -> sphinx -> GetLastError ())
{
2015-01-05 22:21:31 +01:00
$phpbb_log -> add ( 'critical' , $user -> data [ 'user_id' ], $user -> ip , 'LOG_SPHINX_ERROR' , false , array ( $this -> sphinx -> GetLastError ()));
2012-08-10 10:46:32 +05:30
if ( $this -> auth -> acl_get ( 'a_' ))
{
trigger_error ( $this -> user -> lang ( 'SPHINX_SEARCH_FAILED' , $this -> sphinx -> GetLastError ()));
}
else
{
2012-08-15 22:57:02 +05:30
trigger_error ( $this -> user -> lang ( 'SPHINX_SEARCH_FAILED_LOG' ));
2012-08-10 10:46:32 +05:30
}
2012-08-01 22:18:12 +05:30
}
2012-12-21 21:54:41 +05:30
$result_count = $result [ 'total_found' ];
2013-04-20 19:26:01 +05:30
if ( $result_count && $start >= $result_count )
2012-12-21 21:54:41 +05:30
{
$start = floor (( $result_count - 1 ) / $per_page ) * $per_page ;
2019-12-24 00:33:44 +01:00
$this -> sphinx -> SetLimits (( int ) $start , ( int ) $per_page , max ( SPHINX_MAX_MATCHES , ( int ) $start + $per_page ));
2020-06-02 07:43:27 +02:00
$result = $this -> sphinx -> Query ( $search_query_prefix . $this -> sphinx_clean_search_string ( str_replace ( '"' , '"' , $this -> search_query )), $this -> indexes );
2012-12-21 21:54:41 +05:30
// 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 -> GetLastError (), " errno=111, " ) !== false ) && $retries -- )
{
usleep ( SPHINX_CONNECT_WAIT_TIME );
2020-06-02 07:43:27 +02:00
$result = $this -> sphinx -> Query ( $search_query_prefix . $this -> sphinx_clean_search_string ( str_replace ( '"' , '"' , $this -> search_query )), $this -> indexes );
2012-12-21 21:54:41 +05:30
}
}
2012-05-04 18:39:41 +05:30
$id_ary = array ();
if ( isset ( $result [ 'matches' ]))
{
if ( $type == 'posts' )
{
$id_ary = array_keys ( $result [ 'matches' ]);
}
else
{
2012-07-10 06:07:42 +05:30
foreach ( $result [ 'matches' ] as $key => $value )
2012-05-04 18:39:41 +05:30
{
$id_ary [] = $value [ 'attrs' ][ 'topic_id' ];
}
}
}
else
{
return false ;
}
$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
2012-08-30 22:20:52 +02:00
* @ param string $post_visibility specifies which types of posts the user can view in which forums
2012-05-04 18:39:41 +05:30
* @ 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
*/
2012-08-30 22:20:52 +02:00
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 )
2012-05-04 18:39:41 +05:30
{
$this -> search_query = '' ;
$this -> sphinx -> SetMatchMode ( SPH_MATCH_FULLSCAN );
$fields = ( $firstpost_only ) ? 'firstpost' : 'all' ;
$terms = 'all' ;
2012-08-30 22:20:52 +02:00
return $this -> 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 );
2012-05-04 18:39:41 +05:30
}
/**
* Updates wordlist and wordmatch tables when a message is posted or changed
*
2012-07-01 12:01:14 +05:30
* @ 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
2012-05-04 18:39:41 +05:30
*/
2012-08-10 14:06:25 +05:30
public function index ( $mode , $post_id , & $message , & $subject , $poster_id , $forum_id )
2012-05-04 18:39:41 +05:30
{
2018-01-28 16:14:29 +01:00
/**
* 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 )));
2012-05-04 18:39:41 +05:30
if ( $mode == 'edit' )
{
2014-06-15 19:46:12 +02:00
$this -> sphinx -> UpdateAttributes ( $this -> indexes , array ( 'forum_id' , 'poster_id' ), array (( int ) $post_id => array (( int ) $forum_id , ( int ) $poster_id )));
2012-05-04 18:39:41 +05:30
}
else if ( $mode != 'post' && $post_id )
{
2012-06-27 03:44:03 +05:30
// 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' ,
)),
2014-10-20 12:20:44 -04:00
'WHERE' => 'p2.post_id = ' . (( int ) $post_id ),
2012-06-27 03:44:03 +05:30
);
2012-07-10 05:16:42 +05:30
$sql = $this -> db -> sql_build_query ( 'SELECT' , $sql_array );
$result = $this -> db -> sql_query ( $sql );
2012-05-04 18:39:41 +05:30
$post_updates = array ();
$post_time = time ();
2012-07-10 05:16:42 +05:30
while ( $row = $this -> db -> sql_fetchrow ( $result ))
2012-05-04 18:39:41 +05:30
{
2014-06-15 19:46:12 +02:00
$post_updates [( int ) $row [ 'post_id' ]] = array ( $post_time );
2012-05-04 18:39:41 +05:30
}
2012-07-10 05:16:42 +05:30
$this -> db -> sql_freeresult ( $result );
2012-05-04 18:39:41 +05:30
2017-06-28 00:58:03 +07:00
if ( count ( $post_updates ))
2012-05-04 18:39:41 +05:30
{
$this -> sphinx -> UpdateAttributes ( $this -> indexes , array ( 'topic_last_post_time' ), $post_updates );
}
}
}
/**
* Delete a post from the index after it was deleted
*/
2012-08-10 14:06:25 +05:30
public function index_remove ( $post_ids , $author_ids , $forum_ids )
2012-05-04 18:39:41 +05:30
{
$values = array ();
foreach ( $post_ids as $post_id )
{
$values [ $post_id ] = array ( 1 );
}
$this -> sphinx -> UpdateAttributes ( $this -> indexes , array ( 'deleted' ), $values );
}
/**
2012-07-26 16:55:11 +05:30
* Nothing needs to be destroyed
2012-05-04 18:39:41 +05:30
*/
2012-08-10 14:06:25 +05:30
public function tidy ( $create = false )
2012-05-04 18:39:41 +05:30
{
2015-01-11 17:32:31 +01:00
$this -> config -> set ( 'search_last_gc' , time (), false );
2012-05-04 18:39:41 +05:30
}
/**
* Create sphinx table
2012-07-01 12:01:14 +05:30
*
* @ return string | bool error string is returned incase of errors otherwise false
2012-05-04 18:39:41 +05:30
*/
2012-08-10 14:06:25 +05:30
public function create_index ( $acp_module , $u_action )
2012-05-04 18:39:41 +05:30
{
if ( ! $this -> index_created ())
{
2012-07-10 05:23:23 +05:30
$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 );
2012-05-04 18:39:41 +05:30
$sql = 'TRUNCATE TABLE ' . SPHINX_TABLE ;
2012-07-10 05:16:42 +05:30
$this -> db -> sql_query ( $sql );
2012-07-12 17:22:03 +05:30
$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 );
2012-05-04 18:39:41 +05:30
}
return false ;
}
/**
* Drop sphinx table
2012-07-01 12:01:14 +05:30
*
* @ return string | bool error string is returned incase of errors otherwise false
2012-05-04 18:39:41 +05:30
*/
2012-08-10 14:06:25 +05:30
public function delete_index ( $acp_module , $u_action )
2012-05-04 18:39:41 +05:30
{
if ( ! $this -> index_created ())
{
return false ;
}
2012-07-10 05:23:23 +05:30
$this -> db_tools -> sql_table_drop ( SPHINX_TABLE );
2012-05-04 18:39:41 +05:30
return false ;
}
/**
* Returns true if the sphinx table was created
2012-07-01 12:01:14 +05:30
*
* @ return bool true if sphinx table was created
2012-05-04 18:39:41 +05:30
*/
2012-08-10 14:06:25 +05:30
public function index_created ( $allow_new_files = true )
2012-05-04 18:39:41 +05:30
{
$created = false ;
2012-07-12 04:13:34 +05:30
if ( $this -> db_tools -> sql_table_exists ( SPHINX_TABLE ))
2012-05-04 18:39:41 +05:30
{
2012-07-10 03:51:40 +05:30
$created = true ;
2012-05-04 18:39:41 +05:30
}
return $created ;
}
/**
* Returns an associative array containing information about the indexes
2012-07-01 12:01:14 +05:30
*
* @ return string | bool Language string of error false otherwise
2012-05-04 18:39:41 +05:30
*/
2012-08-10 14:06:25 +05:30
public function index_stats ()
2012-05-04 18:39:41 +05:30
{
if ( empty ( $this -> stats ))
{
$this -> get_stats ();
}
return array (
2012-07-10 05:16:42 +05:30
$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 ,
2012-05-04 18:39:41 +05:30
);
}
/**
* Collects stats that can be displayed on the index maintenance page
*/
2012-08-14 17:33:44 +05:30
protected function get_stats ()
2012-05-04 18:39:41 +05:30
{
if ( $this -> index_created ())
{
$sql = ' SELECT COUNT ( post_id ) as total_posts
FROM ' . POSTS_TABLE ;
2012-07-10 05:16:42 +05:30
$result = $this -> db -> sql_query ( $sql );
$this -> stats [ 'total_posts' ] = ( int ) $this -> db -> sql_fetchfield ( 'total_posts' );
$this -> db -> sql_freeresult ( $result );
2012-05-04 18:39:41 +05:30
$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 ' ;
2012-07-10 05:16:42 +05:30
$result = $this -> db -> sql_query ( $sql );
$this -> stats [ 'main_posts' ] = ( int ) $this -> db -> sql_fetchfield ( 'main_posts' );
$this -> db -> sql_freeresult ( $result );
2012-05-04 18:39:41 +05:30
}
}
/**
* Returns a list of options for the ACP to display
2012-07-01 12:01:14 +05:30
*
* @ return associative array containing template and config variables
2012-05-04 18:39:41 +05:30
*/
2012-08-10 14:06:25 +05:30
public function acp ()
2012-05-04 18:39:41 +05:30
{
$config_vars = array (
'fulltext_sphinx_data_path' => 'string' ,
2012-07-22 02:50:53 +05:30
'fulltext_sphinx_host' => 'string' ,
2012-07-22 03:43:50 +05:30
'fulltext_sphinx_port' => 'string' ,
2012-05-04 18:39:41 +05:30
'fulltext_sphinx_indexer_mem_limit' => 'int' ,
);
$tpl = '
2012-07-11 17:46:58 +05:30
< span class = " error " > ' . $this->user->lang[' FULLTEXT_SPHINX_CONFIGURE ']. ' </ span >
2012-05-04 18:39:41 +05:30
< dl >
2012-11-10 00:30:46 +01:00
< dt >< label for = " fulltext_sphinx_data_path " > ' . $this->user->lang[' FULLTEXT_SPHINX_DATA_PATH '] . $this->user->lang[' COLON '] . ' </ label >< br />< span > ' . $this->user->lang[' FULLTEXT_SPHINX_DATA_PATH_EXPLAIN '] . ' </ span ></ dt >
2012-07-10 05:16:42 +05:30
< 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 >
2012-05-04 18:39:41 +05:30
</ dl >
2012-07-22 02:50:53 +05:30
< dl >
2012-11-10 00:30:46 +01:00
< dt >< label for = " fulltext_sphinx_host " > ' . $this->user->lang[' FULLTEXT_SPHINX_HOST '] . $this->user->lang[' COLON '] . ' </ label >< br />< span > ' . $this->user->lang[' FULLTEXT_SPHINX_HOST_EXPLAIN '] . ' </ span ></ dt >
2012-07-22 02:50:53 +05:30
< 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 >
2012-05-04 18:39:41 +05:30
< dl >
2012-11-10 00:30:46 +01:00
< dt >< label for = " fulltext_sphinx_port " > ' . $this->user->lang[' FULLTEXT_SPHINX_PORT '] . $this->user->lang[' COLON '] . ' </ label >< br />< span > ' . $this->user->lang[' FULLTEXT_SPHINX_PORT_EXPLAIN '] . ' </ span ></ dt >
2015-11-06 10:31:56 +01:00
< dd >< input id = " fulltext_sphinx_port " type = " number " min = " 0 " max = " 9999999999 " name = " config[fulltext_sphinx_port] " value = " ' . $this->config ['fulltext_sphinx_port'] . ' " /></ dd >
2012-05-04 18:39:41 +05:30
</ dl >
< dl >
2012-11-10 00:30:46 +01:00
< dt >< label for = " fulltext_sphinx_indexer_mem_limit " > ' . $this->user->lang[' FULLTEXT_SPHINX_INDEXER_MEM_LIMIT '] . $this->user->lang[' COLON '] . ' </ label >< br />< span > ' . $this->user->lang[' FULLTEXT_SPHINX_INDEXER_MEM_LIMIT_EXPLAIN '] . ' </ span ></ dt >
2015-11-06 10:31:56 +01:00
< dd >< input id = " fulltext_sphinx_indexer_mem_limit " type = " number " min = " 0 " max = " 9999999999 " name = " config[fulltext_sphinx_indexer_mem_limit] " value = " ' . $this->config ['fulltext_sphinx_indexer_mem_limit'] . ' " /> ' . $this->user->lang[' MIB '] . ' </ dd >
2012-05-04 18:39:41 +05:30
</ dl >
2012-07-11 16:25:19 +05:30
< dl >
2013-02-18 14:01:46 +05:30
< dt >< label for = " fulltext_sphinx_config_file " > ' . $this->user->lang[' FULLTEXT_SPHINX_CONFIG_FILE '] . $this->user->lang[' COLON '] . ' </ label >< br />< span > ' . $this->user->lang[' FULLTEXT_SPHINX_CONFIG_FILE_EXPLAIN '] . ' </ span ></ dt >
2021-01-20 00:01:20 +07:00
< dd > ' . (($this->config_generate()) ? ' < textarea readonly = " readonly " rows = " 6 " id = " sphinx_config_data " > ' . htmlspecialchars($this->config_file_data, ENT_COMPAT) . ' </ textarea > ' : $this->config_file_data) . ' </ dd >
2012-07-11 16:25:19 +05:30
< dl >
2012-05-04 18:39:41 +05:30
' ;
// These are fields required in the config table
return array (
'tpl' => $tpl ,
'config' => $config_vars
);
}
}