2005-01-13 22:30:42 +00:00
< ? php
2007-06-09 11:11:20 +00:00
/**
2005-04-09 12:26:45 +00:00
*
* @ package search
2007-06-09 11:11:20 +00:00
* @ copyright ( c ) 2005 phpBB Group
2012-01-12 22:25:14 -05:00
* @ license http :// opensource . org / licenses / gpl - 2.0 . php GNU General Public License v2
2005-04-09 12:26:45 +00:00
*
*/
2005-01-13 22:30:42 +00:00
2006-03-19 14:23:21 +00:00
/**
2007-10-05 14:36:34 +00:00
* @ ignore
2006-03-19 14:23:21 +00:00
*/
if ( ! defined ( 'IN_PHPBB' ))
{
exit ;
}
2005-04-09 12:26:45 +00:00
/**
* fulltext_mysql
2006-01-22 19:13:12 +00:00
* Fulltext search for MySQL
2006-06-13 21:06:29 +00:00
* @ package search
2005-04-09 12:26:45 +00:00
*/
2011-08-15 20:00:47 -04:00
class phpbb_search_fulltext_mysql extends phpbb_search_base
2005-01-13 22:30:42 +00:00
{
2012-08-10 16:07:24 +05:30
/**
* Associative array holding index stats
* @ var array
*/
2012-08-14 17:35:24 +05:30
protected $stats = array ();
2012-08-10 16:07:24 +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:07:24 +05:30
* @ var array
*/
2012-08-14 17:35:24 +05:30
protected $split_words = array ();
2012-08-10 16:07:24 +05:30
/**
2012-08-19 12:07:06 +05:30
* Config object
2012-08-14 23:54:46 +05:30
* @ var phpbb_config
2012-08-10 16:07:24 +05:30
*/
2012-08-14 17:35:24 +05:30
protected $config ;
2012-08-10 16:07:24 +05:30
/**
2012-12-04 04:29:31 -05:00
* Database connection
* @ var phpbb_db_driver
2012-08-10 16:07:24 +05:30
*/
2012-08-14 17:35:24 +05:30
protected $db ;
2012-08-10 16:07:24 +05:30
/**
2012-08-19 12:07:06 +05:30
* User object
2012-08-16 00:07:11 +05:30
* @ var phpbb_user
2012-08-10 16:07:24 +05:30
*/
2012-08-14 17:35:24 +05:30
protected $user ;
2012-08-10 16:07:24 +05:30
/**
2012-08-20 00:58:41 +05:30
* Associative array stores the min and max word length to be searched
2012-08-10 16:07:24 +05:30
* @ var array
*/
2012-11-09 16:22:32 +05:30
protected $word_length = array ();
2012-08-10 16:07:24 +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:07:24 +05:30
* @ var string
*/
2012-11-09 16:22:32 +05:30
protected $search_query ;
2012-08-10 16:07:24 +05:30
/**
2012-08-19 13:13:03 +05:30
* Contains common words .
* Common words are words with length less / more than min / max length
2012-08-10 16:07:24 +05:30
* @ var array
*/
2012-11-09 16:22:32 +05:30
protected $common_words = array ();
2006-03-15 23:20:04 +00:00
2012-07-21 17:38:28 +05:30
/**
* Constructor
2012-08-15 23:49:51 +05:30
* Creates a new phpbb_search_fulltext_mysql , which is used as a search backend
2012-07-21 17:38:28 +05:30
*
* @ param string | bool $error Any error that occurs is passed on through this reference variable otherwise false
*/
2012-08-08 11:07:47 +05:30
public function __construct ( & $error , $phpbb_root_path , $phpEx , $auth , $config , $db , $user )
2005-01-13 22:30:42 +00:00
{
2012-07-21 18:32:52 +05:30
$this -> config = $config ;
$this -> db = $db ;
$this -> user = $user ;
2006-03-18 14:30:47 +00:00
2012-07-21 18:32:52 +05:30
$this -> word_length = array ( 'min' => $this -> config [ 'fulltext_mysql_min_word_len' ], 'max' => $this -> config [ 'fulltext_mysql_max_word_len' ]);
2006-03-18 14:30:47 +00:00
2012-11-12 13:41:58 +01:00
/**
* Load the UTF tools
*/
if ( ! function_exists ( 'utf8_strlen' ))
{
include ( $phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx );
}
2006-03-15 23:20:04 +00:00
$error = false ;
}
2005-01-13 22:30:42 +00:00
2011-11-18 14:46:30 +01:00
/**
* Returns the name of this search backend to be displayed to administrators
*
* @ return string Name
*/
public function get_name ()
2011-08-15 20:00:47 -04:00
{
return 'MySQL Fulltext' ;
}
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 ;
}
/**
* Returns the common_words array
*
* @ return array common words that are ignored by search backend
*/
public function get_common_words ()
{
return $this -> common_words ;
}
/**
* Returns the word_length array
*
* @ return array min and max word length for searching
*/
public function get_word_length ()
{
return $this -> word_length ;
}
2006-03-15 23:20:04 +00:00
/**
2006-03-26 01:36:26 +00:00
* Checks for correct MySQL version and stores min / max word length in the config
2012-07-21 17:38:28 +05:30
*
2013-07-12 17:51:29 +02:00
* @ return string | bool Language key of the error / incompatiblity occurred
2006-03-15 23:20:04 +00:00
*/
2012-08-10 11:35:50 +05:30
public function init ()
2006-03-15 23:20:04 +00:00
{
2012-07-21 18:32:52 +05:30
if ( $this -> db -> sql_layer != 'mysql4' && $this -> db -> sql_layer != 'mysqli' )
2006-03-15 23:20:04 +00:00
{
2012-07-21 18:32:52 +05:30
return $this -> user -> lang [ 'FULLTEXT_MYSQL_INCOMPATIBLE_DATABASE' ];
2006-03-15 23:20:04 +00:00
}
2012-07-21 18:32:52 +05:30
$result = $this -> db -> sql_query ( 'SHOW TABLE STATUS LIKE \'' . POSTS_TABLE . '\'' );
$info = $this -> db -> sql_fetchrow ( $result );
$this -> db -> sql_freeresult ( $result );
2006-03-26 01:36:26 +00:00
$engine = '' ;
if ( isset ( $info [ 'Engine' ]))
2006-03-16 16:22:32 +00:00
{
2006-03-26 01:36:26 +00:00
$engine = $info [ 'Engine' ];
}
else if ( isset ( $info [ 'Type' ]))
{
$engine = $info [ 'Type' ];
2006-03-16 16:22:32 +00:00
}
2013-06-01 04:09:33 +02:00
$fulltext_supported =
$engine === 'MyISAM' ||
// FULLTEXT is supported on InnoDB since MySQL 5.6.4 according to
// http://dev.mysql.com/doc/refman/5.6/en/innodb-storage-engine.html
$engine === 'InnoDB' &&
2013-06-05 01:55:49 +05:30
phpbb_version_compare ( $this -> db -> sql_server_info ( true ), '5.6.4' , '>=' );
2013-06-01 04:09:33 +02:00
if ( ! $fulltext_supported )
2006-03-16 16:22:32 +00:00
{
2013-06-05 01:55:49 +05:30
return $this -> user -> lang [ 'FULLTEXT_MYSQL_NOT_SUPPORTED' ];
2006-03-16 16:22:32 +00:00
}
2006-01-22 19:13:12 +00:00
$sql = ' SHOW VARIABLES
LIKE \ 'ft\_%\'' ;
2012-07-21 18:32:52 +05:30
$result = $this -> db -> sql_query ( $sql );
2006-01-22 19:13:12 +00:00
2006-03-15 23:20:04 +00:00
$mysql_info = array ();
2012-07-21 18:32:52 +05:30
while ( $row = $this -> db -> sql_fetchrow ( $result ))
2006-01-22 19:13:12 +00:00
{
2006-03-15 23:20:04 +00:00
$mysql_info [ $row [ 'Variable_name' ]] = $row [ 'Value' ];
2006-01-22 19:13:12 +00:00
}
2012-07-21 18:32:52 +05:30
$this -> db -> sql_freeresult ( $result );
2005-01-13 22:30:42 +00:00
2006-03-15 23:20:04 +00:00
set_config ( 'fulltext_mysql_max_word_len' , $mysql_info [ 'ft_max_word_len' ]);
set_config ( 'fulltext_mysql_min_word_len' , $mysql_info [ 'ft_min_word_len' ]);
return false ;
2005-01-13 22:30:42 +00:00
}
2005-10-02 16:48:17 +00:00
2006-01-22 19:13:12 +00:00
/**
* Splits keywords entered by a user into an array of words stored in $this -> split_words
2006-07-27 19:02:47 +00:00
* Stores the tidied search query in $this -> search_query
2006-01-22 19:13:12 +00:00
*
2006-11-17 19:37:57 +00:00
* @ param string & $keywords Contains the keyword as entered by the user
2006-01-22 19:13:12 +00:00
* @ param string $terms is either 'all' or 'any'
2006-11-17 19:37:57 +00:00
* @ return bool false if no valid keywords were found and otherwise true
2006-01-22 19:13:12 +00:00
*/
2012-08-10 11:35:50 +05:30
public function split_keywords ( & $keywords , $terms )
2005-01-13 22:30:42 +00:00
{
2006-01-22 19:13:12 +00:00
if ( $terms == 'all' )
2005-01-13 22:30:42 +00:00
{
2010-07-29 10:13:17 -05:00
$match = array ( '#\sand\s#iu' , '#\sor\s#iu' , '#\snot\s#iu' , '#(^|\s)\+#' , '#(^|\s)-#' , '#(^|\s)\|#' );
2006-01-22 19:13:12 +00:00
$replace = array ( ' +' , ' |' , ' -' , ' +' , ' -' , ' |' );
2005-01-13 22:30:42 +00:00
2006-01-22 19:13:12 +00:00
$keywords = preg_replace ( $match , $replace , $keywords );
}
2005-01-13 22:30:42 +00:00
2006-01-22 19:13:12 +00:00
// Filter out as above
2007-04-22 17:12:31 +00:00
$split_keywords = preg_replace ( " #[ \n \r \t ]+# " , ' ' , trim ( htmlspecialchars_decode ( $keywords )));
2006-01-22 19:13:12 +00:00
// Split words
2012-06-13 01:43:32 +05:30
$split_keywords = preg_replace ( '#([^\p{L}\p{N}\'*"()])#u' , '$1$1' , str_replace ( '\'\'' , '\' \'' , trim ( $split_keywords )));
$matches = array ();
preg_match_all ( '#(?:[^\p{L}\p{N}*"()]|^)([+\-|]?(?:[\p{L}\p{N}*"()]+\'?)*[\p{L}\p{N}*"()])(?:[^\p{L}\p{N}*"()]|$)#u' , $split_keywords , $matches );
$this -> split_words = $matches [ 1 ];
2007-03-31 14:36:01 +00:00
2009-04-11 11:09:45 +00:00
// We limit the number of allowed keywords to minimize load on the database
2012-07-21 18:32:52 +05:30
if ( $this -> config [ 'max_num_search_keywords' ] && sizeof ( $this -> split_words ) > $this -> config [ 'max_num_search_keywords' ])
2009-04-11 11:09:45 +00:00
{
2012-07-21 18:32:52 +05:30
trigger_error ( $this -> user -> lang ( 'MAX_NUM_SEARCH_KEYWORDS_REFINE' , $this -> config [ 'max_num_search_keywords' ], sizeof ( $this -> split_words )));
2009-04-11 11:09:45 +00:00
}
2007-04-22 17:12:31 +00:00
// to allow phrase search, we need to concatenate quoted words
$tmp_split_words = array ();
$phrase = '' ;
foreach ( $this -> split_words as $word )
{
if ( $phrase )
{
$phrase .= ' ' . $word ;
if ( strpos ( $word , '"' ) !== false && substr_count ( $word , '"' ) % 2 == 1 )
{
$tmp_split_words [] = $phrase ;
$phrase = '' ;
}
}
else if ( strpos ( $word , '"' ) !== false && substr_count ( $word , '"' ) % 2 == 1 )
{
$phrase = $word ;
}
else
{
2012-11-12 13:43:13 +01:00
$tmp_split_words [] = $word ;
2007-04-22 17:12:31 +00:00
}
}
if ( $phrase )
{
$tmp_split_words [] = $phrase ;
}
$this -> split_words = $tmp_split_words ;
unset ( $tmp_split_words );
unset ( $phrase );
2006-01-22 19:13:12 +00:00
foreach ( $this -> split_words as $i => $word )
{
2007-04-22 17:12:31 +00:00
$clean_word = preg_replace ( '#^[+\-|"]#' , '' , $word );
2006-01-22 19:13:12 +00:00
// check word length
2006-10-07 12:36:31 +00:00
$clean_len = utf8_strlen ( str_replace ( '*' , '' , $clean_word ));
2012-07-21 18:32:52 +05:30
if (( $clean_len < $this -> config [ 'fulltext_mysql_min_word_len' ]) || ( $clean_len > $this -> config [ 'fulltext_mysql_max_word_len' ]))
2005-01-13 22:30:42 +00:00
{
2006-01-22 19:13:12 +00:00
$this -> common_words [] = $word ;
unset ( $this -> split_words [ $i ]);
2005-01-13 22:30:42 +00:00
}
2006-01-22 19:13:12 +00:00
}
2005-01-13 22:30:42 +00:00
2007-04-22 17:12:31 +00:00
if ( $terms == 'any' )
{
$this -> search_query = '' ;
foreach ( $this -> split_words as $word )
{
if (( strpos ( $word , '+' ) === 0 ) || ( strpos ( $word , '-' ) === 0 ) || ( strpos ( $word , '|' ) === 0 ))
{
$word = substr ( $word , 1 );
}
$this -> search_query .= $word . ' ' ;
}
}
else
{
$this -> search_query = '' ;
foreach ( $this -> split_words as $word )
{
if (( strpos ( $word , '+' ) === 0 ) || ( strpos ( $word , '-' ) === 0 ))
{
$this -> search_query .= $word . ' ' ;
}
else if ( strpos ( $word , '|' ) === 0 )
{
$this -> search_query .= substr ( $word , 1 ) . ' ' ;
}
else
{
$this -> search_query .= '+' . $word . ' ' ;
}
}
}
$this -> search_query = utf8_htmlspecialchars ( $this -> search_query );
2006-07-27 19:02:47 +00:00
2007-04-22 17:12:31 +00:00
if ( $this -> search_query )
2006-01-22 19:13:12 +00:00
{
$this -> split_words = array_values ( $this -> split_words );
2006-05-28 19:06:21 +00:00
sort ( $this -> split_words );
2006-01-22 19:13:12 +00:00
return true ;
}
return false ;
}
2005-01-13 22:30:42 +00:00
2006-01-22 19:13:12 +00:00
/**
2006-03-26 01:36:26 +00:00
* Turns text into an array of words
2012-07-21 17:38:28 +05:30
* @ param string $text contains post text / subject
2006-01-22 19:13:12 +00:00
*/
2012-08-10 11:35:50 +05:30
public function split_message ( $text )
2006-01-22 19:13:12 +00:00
{
// Split words
2012-06-13 01:43:32 +05:30
$text = preg_replace ( '#([^\p{L}\p{N}\'*])#u' , '$1$1' , str_replace ( '\'\'' , '\' \'' , trim ( $text )));
$matches = array ();
preg_match_all ( '#(?:[^\p{L}\p{N}*]|^)([+\-|]?(?:[\p{L}\p{N}*]+\'?)*[\p{L}\p{N}*])(?:[^\p{L}\p{N}*]|$)#u' , $text , $matches );
$text = $matches [ 1 ];
2005-01-13 22:30:42 +00:00
2006-01-22 19:13:12 +00:00
// remove too short or too long words
$text = array_values ( $text );
for ( $i = 0 , $n = sizeof ( $text ); $i < $n ; $i ++ )
{
$text [ $i ] = trim ( $text [ $i ]);
2012-07-21 18:32:52 +05:30
if ( utf8_strlen ( $text [ $i ]) < $this -> config [ 'fulltext_mysql_min_word_len' ] || utf8_strlen ( $text [ $i ]) > $this -> config [ 'fulltext_mysql_max_word_len' ])
2005-01-13 22:30:42 +00:00
{
2006-01-22 19:13:12 +00:00
unset ( $text [ $i ]);
2005-01-13 22:30:42 +00:00
}
}
2006-01-22 19:13:12 +00:00
return array_values ( $text );
}
/**
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
2006-01-22 19:13:12 +00:00
*
2007-04-22 17:12:31 +00:00
* @ param string $type contains either posts or topics depending on what should be searched for
2009-07-02 10:28:32 +00:00
* @ 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
2009-07-02 10:28:32 +00:00
* @ 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
2007-04-22 17:12:31 +00:00
* @ 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
2006-01-22 19:13:12 +00:00
*/
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 )
2006-01-22 19:13:12 +00:00
{
2012-08-15 23:49:51 +05:30
// No keywords? No posts
2007-04-22 17:12:31 +00:00
if ( ! $this -> search_query )
2005-01-13 22:30:42 +00:00
{
2006-01-22 19:13:12 +00:00
return false ;
2005-01-13 22:30:42 +00:00
}
2006-01-22 19:13:12 +00:00
// generate a search_key from all the options to identify the results
$search_key = md5 ( implode ( '#' , array (
2007-04-22 17:12:31 +00:00
implode ( ', ' , $this -> split_words ),
2006-01-22 19:13:12 +00:00
$type ,
$fields ,
$terms ,
$sort_days ,
$sort_key ,
$topic_id ,
implode ( ',' , $ex_fid_ary ),
2012-08-30 22:20:52 +02:00
$post_visibility ,
2006-01-22 19:13:12 +00:00
implode ( ',' , $author_ary )
)));
2012-11-10 14:17:38 +01:00
if ( $start < 0 )
{
$start = 0 ;
}
2006-01-22 19:13:12 +00:00
// try reading the results from cache
$result_count = 0 ;
if ( $this -> obtain_ids ( $search_key , $result_count , $id_ary , $start , $per_page , $sort_dir ) == SEARCH_RESULT_IN_CACHE )
2005-01-13 22:30:42 +00:00
{
2006-01-22 19:13:12 +00:00
return $result_count ;
}
2005-01-13 22:30:42 +00:00
2006-01-22 19:13:12 +00:00
$id_ary = array ();
2005-01-13 22:30:42 +00:00
2006-01-22 19:13:12 +00:00
$join_topic = ( $type == 'posts' ) ? false : true ;
2006-06-16 16:54:51 +00:00
2006-01-22 19:13:12 +00:00
// Build sql strings for sorting
$sql_sort = $sort_by_sql [ $sort_key ] . (( $sort_dir == 'a' ) ? ' ASC' : ' DESC' );
$sql_sort_table = $sql_sort_join = '' ;
2006-06-16 16:54:51 +00:00
2006-01-22 19:13:12 +00:00
switch ( $sql_sort [ 0 ])
{
case 'u' :
$sql_sort_table = USERS_TABLE . ' u, ' ;
$sql_sort_join = ( $type == 'posts' ) ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster ' ;
break ;
2005-10-02 16:48:17 +00:00
2006-01-22 19:13:12 +00:00
case 't' :
$join_topic = true ;
break ;
case 'f' :
$sql_sort_table = FORUMS_TABLE . ' f, ' ;
$sql_sort_join = ' AND f.forum_id = p.forum_id ' ;
break ;
}
// Build some display specific sql strings
switch ( $fields )
{
case 'titleonly' :
$sql_match = 'p.post_subject' ;
$sql_match_where = ' AND p.post_id = t.topic_first_post_id' ;
$join_topic = true ;
break ;
case 'msgonly' :
$sql_match = 'p.post_text' ;
$sql_match_where = '' ;
break ;
case 'firstpost' :
$sql_match = 'p.post_subject, p.post_text' ;
$sql_match_where = ' AND p.post_id = t.topic_first_post_id' ;
$join_topic = true ;
break ;
default :
$sql_match = 'p.post_subject, p.post_text' ;
$sql_match_where = '' ;
2006-06-16 16:54:51 +00:00
break ;
2006-01-22 19:13:12 +00:00
}
$sql_select = ( ! $result_count ) ? 'SQL_CALC_FOUND_ROWS ' : '' ;
$sql_select = ( $type == 'posts' ) ? $sql_select . 'p.post_id' : 'DISTINCT ' . $sql_select . 't.topic_id' ;
$sql_from = ( $join_topic ) ? TOPICS_TABLE . ' t, ' : '' ;
2006-03-06 18:21:54 +00:00
$field = ( $type == 'posts' ) ? 'post_id' : 'topic_id' ;
2009-07-02 10:28:32 +00:00
if ( sizeof ( $author_ary ) && $author_name )
{
// first one matches post of registered users, second one guests and deleted users
2012-07-21 18:32:52 +05:30
$sql_author = ' AND (' . $this -> db -> sql_in_set ( 'p.poster_id' , array_diff ( $author_ary , array ( ANONYMOUS )), false , true ) . ' OR p.post_username ' . $author_name . ')' ;
2009-07-02 10:28:32 +00:00
}
else if ( sizeof ( $author_ary ))
{
2012-07-21 18:32:52 +05:30
$sql_author = ' AND ' . $this -> db -> sql_in_set ( 'p.poster_id' , $author_ary );
2009-07-02 10:28:32 +00:00
}
else
{
$sql_author = '' ;
}
2006-01-22 19:13:12 +00:00
$sql_where_options = $sql_sort_join ;
$sql_where_options .= ( $topic_id ) ? ' AND p.topic_id = ' . $topic_id : '' ;
$sql_where_options .= ( $join_topic ) ? ' AND t.topic_id = p.topic_id' : '' ;
2012-07-21 18:32:52 +05:30
$sql_where_options .= ( sizeof ( $ex_fid_ary )) ? ' AND ' . $this -> db -> sql_in_set ( 'p.forum_id' , $ex_fid_ary , true ) : '' ;
2012-08-30 22:20:52 +02:00
$sql_where_options .= ' AND ' . $post_visibility ;
2009-07-02 10:28:32 +00:00
$sql_where_options .= $sql_author ;
2006-01-22 19:13:12 +00:00
$sql_where_options .= ( $sort_days ) ? ' AND p.post_time >= ' . ( time () - ( $sort_days * 86400 )) : '' ;
$sql_where_options .= $sql_match_where ;
$sql = " SELECT $sql_select
FROM $sql_from $sql_sort_table " . POSTS_TABLE . " p
2012-07-21 18:32:52 +05:30
WHERE MATCH ( $sql_match ) AGAINST ( '" . $this->db->sql_escape(htmlspecialchars_decode($this->search_query)) . "' IN BOOLEAN MODE )
2006-01-22 19:13:12 +00:00
$sql_where_options
ORDER BY $sql_sort " ;
2012-07-21 18:32:52 +05:30
$result = $this -> db -> sql_query_limit ( $sql , $this -> config [ 'search_block_size' ], $start );
2005-01-13 22:30:42 +00:00
2012-07-21 18:32:52 +05:30
while ( $row = $this -> db -> sql_fetchrow ( $result ))
2006-01-22 19:13:12 +00:00
{
2010-01-11 23:26:56 +00:00
$id_ary [] = ( int ) $row [ $field ];
2006-01-22 19:13:12 +00:00
}
2012-07-21 18:32:52 +05:30
$this -> db -> sql_freeresult ( $result );
2006-01-22 19:13:12 +00:00
$id_ary = array_unique ( $id_ary );
2005-01-13 22:30:42 +00:00
2006-01-22 19:13:12 +00:00
// if the total result count is not cached yet, retrieve it from the db
if ( ! $result_count )
{
2012-11-10 14:17:38 +01:00
$sql_found_rows = 'SELECT FOUND_ROWS() as result_count' ;
$result = $this -> db -> sql_query ( $sql_found_rows );
2012-07-21 18:32:52 +05:30
$result_count = ( int ) $this -> db -> sql_fetchfield ( 'result_count' );
$this -> db -> sql_freeresult ( $result );
2006-01-22 19:13:12 +00:00
2006-03-22 17:30:20 +00:00
if ( ! $result_count )
2005-01-13 22:30:42 +00:00
{
2006-01-22 19:13:12 +00:00
return false ;
2005-01-13 22:30:42 +00:00
}
2006-01-22 19:13:12 +00:00
}
2005-01-13 22:30:42 +00:00
2012-11-10 14:17:38 +01:00
if ( $start >= $result_count )
{
$start = floor (( $result_count - 1 ) / $per_page ) * $per_page ;
2012-12-02 14:15:04 +05:30
$result = $this -> db -> sql_query_limit ( $sql , $this -> config [ 'search_block_size' ], $start );
2012-11-10 14:17:38 +01:00
2012-12-02 14:15:04 +05:30
while ( $row = $this -> db -> sql_fetchrow ( $result ))
{
$id_ary [] = ( int ) $row [ $field ];
}
$this -> db -> sql_freeresult ( $result );
2012-11-10 14:17:38 +01:00
2012-12-02 14:15:04 +05:30
$id_ary = array_unique ( $id_ary );
}
2012-11-10 14:17:38 +01:00
2006-01-22 19:13:12 +00:00
// store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page
$this -> save_ids ( $search_key , implode ( ' ' , $this -> split_words ), $author_ary , $result_count , $id_ary , $start , $sort_dir );
$id_ary = array_slice ( $id_ary , 0 , ( int ) $per_page );
2005-01-13 22:30:42 +00:00
2006-01-22 19:13:12 +00:00
return $result_count ;
}
/**
* Performs a search on an author ' s posts without caring about message contents . Depends on display specific params
*
2009-08-31 12:07:18 +00:00
* @ 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
2009-08-31 12:07:18 +00:00
* @ 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
2006-01-22 19:13:12 +00:00
*/
2013-07-14 10:57:19 -04: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 )
2006-01-22 19:13:12 +00:00
{
2012-08-15 23:49:51 +05:30
// No author? No posts
2006-01-22 19:13:12 +00:00
if ( ! sizeof ( $author_ary ))
{
return 0 ;
2005-01-13 22:30:42 +00:00
}
2006-01-22 19:13:12 +00:00
// generate a search_key from all the options to identify the results
$search_key = md5 ( implode ( '#' , array (
'' ,
$type ,
2007-07-23 17:03:37 +00:00
( $firstpost_only ) ? 'firstpost' : '' ,
2006-01-22 19:13:12 +00:00
'' ,
'' ,
$sort_days ,
$sort_key ,
$topic_id ,
implode ( ',' , $ex_fid_ary ),
2012-08-30 22:20:52 +02:00
$post_visibility ,
2009-07-02 10:28:32 +00:00
implode ( ',' , $author_ary ),
$author_name ,
2006-01-22 19:13:12 +00:00
)));
2012-11-10 14:28:29 +01:00
if ( $start < 0 )
{
$start = 0 ;
}
2006-01-22 19:13:12 +00:00
// try reading the results from cache
$result_count = 0 ;
if ( $this -> obtain_ids ( $search_key , $result_count , $id_ary , $start , $per_page , $sort_dir ) == SEARCH_RESULT_IN_CACHE )
2005-01-13 22:30:42 +00:00
{
2006-01-22 19:13:12 +00:00
return $result_count ;
}
2005-01-13 22:30:42 +00:00
2006-01-22 19:13:12 +00:00
$id_ary = array ();
// Create some display specific sql strings
2009-07-02 10:28:32 +00:00
if ( $author_name )
{
// first one matches post of registered users, second one guests and deleted users
2012-07-21 18:32:52 +05:30
$sql_author = '(' . $this -> db -> sql_in_set ( 'p.poster_id' , array_diff ( $author_ary , array ( ANONYMOUS )), false , true ) . ' OR p.post_username ' . $author_name . ')' ;
2009-07-02 10:28:32 +00:00
}
else
{
2012-07-21 18:32:52 +05:30
$sql_author = $this -> db -> sql_in_set ( 'p.poster_id' , $author_ary );
2009-07-02 10:28:32 +00:00
}
2012-07-21 18:32:52 +05:30
$sql_fora = ( sizeof ( $ex_fid_ary )) ? ' AND ' . $this -> db -> sql_in_set ( 'p.forum_id' , $ex_fid_ary , true ) : '' ;
2006-03-06 18:21:54 +00:00
$sql_topic_id = ( $topic_id ) ? ' AND p.topic_id = ' . ( int ) $topic_id : '' ;
2006-01-22 19:13:12 +00:00
$sql_time = ( $sort_days ) ? ' AND p.post_time >= ' . ( time () - ( $sort_days * 86400 )) : '' ;
2007-07-23 17:03:37 +00:00
$sql_firstpost = ( $firstpost_only ) ? ' AND p.post_id = t.topic_first_post_id' : '' ;
2006-01-22 19:13:12 +00:00
// Build sql strings for sorting
$sql_sort = $sort_by_sql [ $sort_key ] . (( $sort_dir == 'a' ) ? ' ASC' : ' DESC' );
$sql_sort_table = $sql_sort_join = '' ;
switch ( $sql_sort [ 0 ])
{
case 'u' :
$sql_sort_table = USERS_TABLE . ' u, ' ;
$sql_sort_join = ( $type == 'posts' ) ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster ' ;
break ;
case 't' :
2008-06-04 17:25:50 +00:00
$sql_sort_table = ( $type == 'posts' && ! $firstpost_only ) ? TOPICS_TABLE . ' t, ' : '' ;
$sql_sort_join = ( $type == 'posts' && ! $firstpost_only ) ? ' AND t.topic_id = p.topic_id ' : '' ;
2006-01-22 19:13:12 +00:00
break ;
case 'f' :
$sql_sort_table = FORUMS_TABLE . ' f, ' ;
$sql_sort_join = ' AND f.forum_id = p.forum_id ' ;
break ;
}
2012-08-30 22:20:52 +02:00
$m_approve_fid_sql = ' AND ' . $post_visibility ;
2006-03-06 18:21:54 +00:00
2006-01-22 19:13:12 +00:00
// If the cache was completely empty count the results
$calc_results = ( $result_count ) ? '' : 'SQL_CALC_FOUND_ROWS ' ;
// Build the query for really selecting the post_ids
if ( $type == 'posts' )
{
$sql = " SELECT { $calc_results } p.post_id
2007-07-23 17:03:37 +00:00
FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (( $firstpost_only ) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . "
2006-01-22 19:13:12 +00:00
WHERE $sql_author
2006-03-06 18:21:54 +00:00
$sql_topic_id
2007-07-23 17:03:37 +00:00
$sql_firstpost
2006-03-06 18:21:54 +00:00
$m_approve_fid_sql
2006-01-22 19:13:12 +00:00
$sql_fora
$sql_sort_join
$sql_time
ORDER BY $sql_sort " ;
$field = 'post_id' ;
}
else
{
$sql = " SELECT { $calc_results } t.topic_id
FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
WHERE $sql_author
2006-03-06 18:21:54 +00:00
$sql_topic_id
2007-07-23 17:03:37 +00:00
$sql_firstpost
2006-03-06 18:21:54 +00:00
$m_approve_fid_sql
2006-01-22 19:13:12 +00:00
$sql_fora
AND t . topic_id = p . topic_id
$sql_sort_join
$sql_time
GROUP BY t . topic_id
ORDER BY $sql_sort " ;
$field = 'topic_id' ;
}
// Only read one block of posts from the db and then cache it
2012-07-21 18:32:52 +05:30
$result = $this -> db -> sql_query_limit ( $sql , $this -> config [ 'search_block_size' ], $start );
2006-01-22 19:13:12 +00:00
2012-07-21 18:32:52 +05:30
while ( $row = $this -> db -> sql_fetchrow ( $result ))
2006-01-22 19:13:12 +00:00
{
2010-01-11 23:26:56 +00:00
$id_ary [] = ( int ) $row [ $field ];
2006-01-22 19:13:12 +00:00
}
2012-07-21 18:32:52 +05:30
$this -> db -> sql_freeresult ( $result );
2006-01-22 19:13:12 +00:00
// retrieve the total result count if needed
if ( ! $result_count )
{
2012-11-10 14:28:29 +01:00
$sql_found_rows = 'SELECT FOUND_ROWS() as result_count' ;
$result = $this -> db -> sql_query ( $sql_found_rows );
2012-07-21 18:32:52 +05:30
$result_count = ( int ) $this -> db -> sql_fetchfield ( 'result_count' );
$this -> db -> sql_freeresult ( $result );
2006-01-22 19:13:12 +00:00
2006-03-22 17:30:20 +00:00
if ( ! $result_count )
2005-01-13 22:30:42 +00:00
{
2006-01-22 19:13:12 +00:00
return false ;
2005-01-13 22:30:42 +00:00
}
2006-01-22 19:13:12 +00:00
}
2005-01-13 22:30:42 +00:00
2012-11-10 14:28:29 +01:00
if ( $start >= $result_count )
{
$start = floor (( $result_count - 1 ) / $per_page ) * $per_page ;
2012-12-02 14:15:04 +05:30
$result = $this -> db -> sql_query_limit ( $sql , $this -> config [ 'search_block_size' ], $start );
while ( $row = $this -> db -> sql_fetchrow ( $result ))
{
$id_ary [] = ( int ) $row [ $field ];
}
$this -> db -> sql_freeresult ( $result );
2012-11-10 14:28:29 +01:00
2012-12-02 14:15:04 +05:30
$id_ary = array_unique ( $id_ary );
}
2012-11-10 14:28:29 +01:00
2006-01-22 19:13:12 +00:00
if ( sizeof ( $id_ary ))
{
$this -> save_ids ( $search_key , '' , $author_ary , $result_count , $id_ary , $start , $sort_dir );
$id_ary = array_slice ( $id_ary , 0 , $per_page );
return $result_count ;
}
return false ;
}
/**
2012-08-15 23:49:51 +05:30
* Destroys cached search results , that contained one of the new words in a post so the results won ' t be outdated
2006-01-22 19:13:12 +00:00
*
2012-07-21 17:38:28 +05:30
* @ param string $mode contains the post mode : edit , post , reply , quote ...
* @ param int $post_id contains the post id of the post to index
* @ param string $message contains the post text of the post
* @ param string $subject contains the subject of the post to index
* @ param int $poster_id contains the user id of the poster
* @ param int $forum_id contains the forum id of parent forum of the post
2006-01-22 19:13:12 +00:00
*/
2012-08-10 11:35:50 +05:30
public function index ( $mode , $post_id , & $message , & $subject , $poster_id , $forum_id )
2006-01-22 19:13:12 +00:00
{
// Split old and new post/subject to obtain array of words
$split_text = $this -> split_message ( $message );
$split_title = ( $subject ) ? $this -> split_message ( $subject ) : array ();
2007-04-22 17:12:31 +00:00
$words = array_unique ( array_merge ( $split_text , $split_title ));
2006-01-22 19:13:12 +00:00
unset ( $split_text );
unset ( $split_title );
2005-01-13 22:30:42 +00:00
2006-01-22 19:13:12 +00:00
// destroy cached search results containing any of the words removed or added
$this -> destroy_cache ( $words , array ( $poster_id ));
unset ( $words );
}
/**
* Destroy cached results , that might be outdated after deleting a post
*/
2012-08-10 11:35:50 +05:30
public function index_remove ( $post_ids , $author_ids , $forum_ids )
2006-01-22 19:13:12 +00:00
{
2012-02-20 02:14:23 +01:00
$this -> destroy_cache ( array (), array_unique ( $author_ids ));
2006-01-22 19:13:12 +00:00
}
/**
* Destroy old cache entries
*/
2012-08-10 11:35:50 +05:30
public function tidy ()
2006-01-22 19:13:12 +00:00
{
// destroy too old cached search results
$this -> destroy_cache ( array ());
2006-05-18 18:18:32 +00:00
set_config ( 'search_last_gc' , time (), true );
2005-01-13 22:30:42 +00:00
}
2006-03-15 23:20:04 +00:00
/**
* Create fulltext index
2012-07-21 17:38:28 +05:30
*
* @ return string | bool error string is returned incase of errors otherwise false
2006-03-15 23:20:04 +00:00
*/
2012-08-10 11:35:50 +05:30
public function create_index ( $acp_module , $u_action )
2006-03-15 23:20:04 +00:00
{
2006-03-26 01:36:26 +00:00
// Make sure we can actually use MySQL with fulltext indexes
if ( $error = $this -> init ())
2006-03-15 23:20:04 +00:00
{
2006-03-26 01:36:26 +00:00
return $error ;
2006-03-15 23:20:04 +00:00
}
2006-07-27 19:02:47 +00:00
if ( empty ( $this -> stats ))
2006-03-15 23:20:04 +00:00
{
$this -> get_stats ();
}
2006-12-16 20:24:34 +00:00
$alter = array ();
2006-03-15 23:20:04 +00:00
if ( ! isset ( $this -> stats [ 'post_subject' ]))
{
2012-07-21 18:32:52 +05:30
if ( $this -> db -> sql_layer == 'mysqli' || version_compare ( $this -> db -> sql_server_info ( true ), '4.1.3' , '>=' ))
2006-12-16 20:24:34 +00:00
{
2012-06-19 20:03:57 +05:30
$alter [] = 'MODIFY post_subject varchar(255) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL' ;
2006-12-16 20:24:34 +00:00
}
2007-04-18 20:21:50 +00:00
else
{
2007-04-18 21:11:17 +00:00
$alter [] = 'MODIFY post_subject text NOT NULL' ;
2007-04-18 20:21:50 +00:00
}
2006-12-16 20:24:34 +00:00
$alter [] = 'ADD FULLTEXT (post_subject)' ;
2006-03-15 23:20:04 +00:00
}
2013-08-26 15:16:56 +05:30
if ( ! isset ( $this -> stats [ 'post_content' ]))
2006-03-15 23:20:04 +00:00
{
2012-07-21 18:32:52 +05:30
if ( $this -> db -> sql_layer == 'mysqli' || version_compare ( $this -> db -> sql_server_info ( true ), '4.1.3' , '>=' ))
2006-12-16 20:24:34 +00:00
{
$alter [] = 'MODIFY post_text mediumtext COLLATE utf8_unicode_ci NOT NULL' ;
}
2007-04-18 20:21:50 +00:00
else
{
2007-04-18 21:11:17 +00:00
$alter [] = 'MODIFY post_text mediumtext NOT NULL' ;
2007-04-18 20:21:50 +00:00
}
2006-12-16 20:24:34 +00:00
2007-04-22 17:12:31 +00:00
$alter [] = 'ADD FULLTEXT post_content (post_subject, post_text)' ;
}
2006-12-16 20:24:34 +00:00
if ( sizeof ( $alter ))
{
2012-07-21 18:32:52 +05:30
$this -> db -> sql_query ( 'ALTER TABLE ' . POSTS_TABLE . ' ' . implode ( ', ' , $alter ));
2006-03-15 23:20:04 +00:00
}
2012-07-21 18:32:52 +05:30
$this -> db -> sql_query ( 'TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE );
2006-05-26 15:04:27 +00:00
return false ;
2006-03-15 23:20:04 +00:00
}
/**
* Drop fulltext index
2012-07-21 17:38:28 +05:30
*
* @ return string | bool error string is returned incase of errors otherwise false
2006-03-15 23:20:04 +00:00
*/
2012-08-10 11:35:50 +05:30
public function delete_index ( $acp_module , $u_action )
2006-03-15 23:20:04 +00:00
{
2006-03-26 01:36:26 +00:00
// Make sure we can actually use MySQL with fulltext indexes
if ( $error = $this -> init ())
2006-03-15 23:20:04 +00:00
{
2006-03-26 01:36:26 +00:00
return $error ;
2006-03-15 23:20:04 +00:00
}
2006-07-27 19:02:47 +00:00
if ( empty ( $this -> stats ))
2006-03-15 23:20:04 +00:00
{
$this -> get_stats ();
}
2006-12-16 20:24:34 +00:00
$alter = array ();
2006-03-15 23:20:04 +00:00
if ( isset ( $this -> stats [ 'post_subject' ]))
{
2006-12-16 20:24:34 +00:00
$alter [] = 'DROP INDEX post_subject' ;
2006-03-15 23:20:04 +00:00
}
2007-04-22 17:12:31 +00:00
if ( isset ( $this -> stats [ 'post_content' ]))
{
$alter [] = 'DROP INDEX post_content' ;
}
2006-12-16 20:24:34 +00:00
if ( sizeof ( $alter ))
{
2012-07-21 18:32:52 +05:30
$this -> db -> sql_query ( 'ALTER TABLE ' . POSTS_TABLE . ' ' . implode ( ', ' , $alter ));
2006-03-15 23:20:04 +00:00
}
2012-07-21 18:32:52 +05:30
$this -> db -> sql_query ( 'TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE );
2006-05-26 15:04:27 +00:00
return false ;
2006-03-15 23:20:04 +00:00
}
/**
* Returns true if both FULLTEXT indexes exist
*/
2012-08-10 11:35:50 +05:30
public function index_created ()
2006-03-15 23:20:04 +00:00
{
2006-07-27 19:02:47 +00:00
if ( empty ( $this -> stats ))
2006-03-15 23:20:04 +00:00
{
$this -> get_stats ();
}
2013-08-26 15:16:56 +05:30
return ( isset ( $this -> stats [ 'post_subject' ]) && isset ( $this -> stats [ 'post_content' ])) ? true : false ;
2006-03-15 23:20:04 +00:00
}
/**
* Returns an associative array containing information about the indexes
*/
2012-08-10 11:35:50 +05:30
public function index_stats ()
2006-03-15 23:20:04 +00:00
{
2006-07-27 19:02:47 +00:00
if ( empty ( $this -> stats ))
2006-03-15 23:20:04 +00:00
{
$this -> get_stats ();
}
return array (
2012-07-21 18:32:52 +05:30
$this -> user -> lang [ 'FULLTEXT_MYSQL_TOTAL_POSTS' ] => ( $this -> index_created ()) ? $this -> stats [ 'total_posts' ] : 0 ,
2006-06-16 16:54:51 +00:00
);
2006-03-15 23:20:04 +00:00
}
2012-07-21 17:38:28 +05:30
/**
* Computes the stats and store them in the $this -> stats associative array
*/
2012-08-14 17:35:24 +05:30
protected function get_stats ()
2006-03-15 23:20:04 +00:00
{
2012-07-21 18:32:52 +05:30
if ( strpos ( $this -> db -> sql_layer , 'mysql' ) === false )
2006-03-26 01:36:26 +00:00
{
$this -> stats = array ();
return ;
}
2006-03-15 23:20:04 +00:00
$sql = ' SHOW INDEX
FROM ' . POSTS_TABLE ;
2012-07-21 18:32:52 +05:30
$result = $this -> db -> sql_query ( $sql );
2006-03-15 23:20:04 +00:00
2012-07-21 18:32:52 +05:30
while ( $row = $this -> db -> sql_fetchrow ( $result ))
2006-03-15 23:20:04 +00:00
{
2006-04-23 13:10:34 +00:00
// deal with older MySQL versions which didn't use Index_type
$index_type = ( isset ( $row [ 'Index_type' ])) ? $row [ 'Index_type' ] : $row [ 'Comment' ];
if ( $index_type == 'FULLTEXT' )
2006-03-15 23:20:04 +00:00
{
2013-08-26 15:16:56 +05:30
if ( $row [ 'Key_name' ] == 'post_subject' )
2006-03-15 23:20:04 +00:00
{
$this -> stats [ 'post_subject' ] = $row ;
}
2007-04-28 21:16:32 +00:00
else if ( $row [ 'Key_name' ] == 'post_content' )
2007-04-22 17:12:31 +00:00
{
$this -> stats [ 'post_content' ] = $row ;
}
2006-03-15 23:20:04 +00:00
}
}
2012-07-21 18:32:52 +05:30
$this -> db -> sql_freeresult ( $result );
2006-03-15 23:20:04 +00:00
2012-07-21 18:32:52 +05:30
$this -> stats [ 'total_posts' ] = empty ( $this -> stats ) ? 0 : $this -> db -> get_estimated_row_count ( POSTS_TABLE );
2006-03-15 23:20:04 +00:00
}
2007-01-27 17:38:45 +00:00
/**
* Display a note , that UTF - 8 support is not available with certain versions of PHP
2012-07-21 17:38:28 +05:30
*
* @ return associative array containing template and config variables
2007-01-27 17:38:45 +00:00
*/
2012-08-10 11:35:50 +05:30
public function acp ()
2007-01-27 17:38:45 +00:00
{
$tpl = '
2010-10-21 20:31:00 +02:00
< dl >
2012-11-10 00:30:46 +01:00
< dt >< label > ' . $this->user->lang[' MIN_SEARCH_CHARS '] . $this->user->lang[' COLON '] . ' </ label >< br />< span > ' . $this->user->lang[' FULLTEXT_MYSQL_MIN_SEARCH_CHARS_EXPLAIN '] . ' </ span ></ dt >
2012-07-21 18:32:52 +05:30
< dd > ' . $this->config[' fulltext_mysql_min_word_len '] . ' </ dd >
2010-10-21 20:31:00 +02:00
</ dl >
< dl >
2012-11-10 00:30:46 +01:00
< dt >< label > ' . $this->user->lang[' MAX_SEARCH_CHARS '] . $this->user->lang[' COLON '] . ' </ label >< br />< span > ' . $this->user->lang[' FULLTEXT_MYSQL_MAX_SEARCH_CHARS_EXPLAIN '] . ' </ span ></ dt >
2012-07-21 18:32:52 +05:30
< dd > ' . $this->config[' fulltext_mysql_max_word_len '] . ' </ dd >
2010-10-21 20:31:00 +02:00
</ dl >
2007-01-27 17:38:45 +00:00
' ;
// These are fields required in the config table
return array (
'tpl' => $tpl ,
'config' => array ()
);
}
2005-01-13 22:30:42 +00:00
}