Verzeichnisstruktur phpBB-3.0.0


Veröffentlicht
12.12.2007

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

fulltext_mysql.php

Zuletzt modifiziert: 09.10.2024, 12:51 - Dateigröße: 23.68 KiB


001  <?php
002  /**
003  *
004  * @package search
005  * @version $Id$
006  * @copyright (c) 2005 phpBB Group
007  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
008  *
009  */
010   
011  /**
012  * @ignore
013  */
014  if (!defined('IN_PHPBB'))
015  {
016      exit;
017  }
018   
019  /**
020  * @ignore
021  */
022  include_once($phpbb_root_path . 'includes/search/search.' . $phpEx);
023   
024  /**
025  * fulltext_mysql
026  * Fulltext search for MySQL
027  * @package search
028  */
029  class fulltext_mysql extends search_backend
030  {
031      var $stats = array();
032      var $word_length = array();
033      var $split_words = array();
034      var $search_query;
035      var $common_words = array();
036      var $pcre_properties = false;
037      var $mbstring_regex = false;
038   
039      function fulltext_mysql(&$error)
040      {
041          global $config;
042   
043          $this->word_length = array('min' => $config['fulltext_mysql_min_word_len'], 'max' => $config['fulltext_mysql_max_word_len']);
044   
045          if (version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.0', '>=')))
046          {
047              // While this is the proper range of PHP versions, PHP may not be linked with the bundled PCRE lib and instead with an older version
048              if (@preg_match('/\p{L}/u', 'a') !== false)
049              {
050                  $this->pcre_properties = true;
051              }
052          }
053   
054          if (function_exists('mb_ereg'))
055          {
056              $this->mbstring_regex = true;
057              mb_regex_encoding('UTF-8');
058          }
059   
060          $error = false;
061      }
062   
063      /**
064      * Checks for correct MySQL version and stores min/max word length in the config
065      */
066      function init()
067      {
068          global $db, $user;
069   
070          if ($db->sql_layer != 'mysql4' && $db->sql_layer != 'mysqli')
071          {
072              return $user->lang['FULLTEXT_MYSQL_INCOMPATIBLE_VERSION'];
073          }
074   
075          $result = $db->sql_query('SHOW TABLE STATUS LIKE \'' . POSTS_TABLE . '\'');
076          $info = $db->sql_fetchrow($result);
077          $db->sql_freeresult($result);
078   
079          $engine = '';
080          if (isset($info['Engine']))
081          {
082              $engine = $info['Engine'];
083          }
084          else if (isset($info['Type']))
085          {
086              $engine = $info['Type'];
087          }
088   
089          if ($engine != 'MyISAM')
090          {
091              return $user->lang['FULLTEXT_MYSQL_NOT_MYISAM'];
092          }
093   
094          $sql = 'SHOW VARIABLES
095              LIKE \'ft\_%\'';
096          $result = $db->sql_query($sql);
097   
098          $mysql_info = array();
099          while ($row = $db->sql_fetchrow($result))
100          {
101              $mysql_info[$row['Variable_name']] = $row['Value'];
102          }
103          $db->sql_freeresult($result);
104   
105          set_config('fulltext_mysql_max_word_len', $mysql_info['ft_max_word_len']);
106          set_config('fulltext_mysql_min_word_len', $mysql_info['ft_min_word_len']);
107   
108          return false;
109      }
110   
111      /**
112      * Splits keywords entered by a user into an array of words stored in $this->split_words
113      * Stores the tidied search query in $this->search_query
114      *
115      * @param string &$keywords Contains the keyword as entered by the user
116      * @param string $terms is either 'all' or 'any'
117      * @return bool false if no valid keywords were found and otherwise true
118      */
119      function split_keywords(&$keywords, $terms)
120      {
121          global $config;
122   
123          if ($terms == 'all')
124          {
125              $match        = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#\+#', '#-#', '#\|#');
126              $replace    = array(' +', ' |', ' -', ' +', ' -', ' |');
127   
128              $keywords = preg_replace($match, $replace, $keywords);
129          }
130   
131          // Filter out as above
132          $split_keywords = preg_replace("#[\n\r\t]+#", ' ', trim(htmlspecialchars_decode($keywords)));
133   
134          // Split words
135          if ($this->pcre_properties)
136          {
137              $split_keywords = preg_replace('#([^\p{L}\p{N}\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords)));
138          }
139          else if ($this->mbstring_regex)
140          {
141              $split_keywords = mb_ereg_replace('([^\w\'*"()])', '\\1\\1', str_replace('\'\'', '\' \'', trim($split_keywords)));
142          }
143          else
144          {
145              $split_keywords = preg_replace('#([^\w\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords)));
146          }
147   
148          if ($this->pcre_properties)
149          {
150              $matches = array();
151              preg_match_all('#(?:[^\p{L}\p{N}*"()]|^)([+\-|]?(?:[\p{L}\p{N}*"()]+\'?)*[\p{L}\p{N}*"()])(?:[^\p{L}\p{N}*"()]|$)#u', $split_keywords, $matches);
152              $this->split_words = $matches[1];
153          }
154          else if ($this->mbstring_regex)
155          {
156              mb_ereg_search_init($split_keywords, '(?:[^\w*"()]|^)([+\-|]?(?:[\w*"()]+\'?)*[\w*"()])(?:[^\w*"()]|$)');
157   
158              while (($word = mb_ereg_search_regs()))
159              {
160                  $this->split_words[] = $word[1];
161              }
162          }
163          else
164          {
165              $matches = array();
166              preg_match_all('#(?:[^\w*"()]|^)([+\-|]?(?:[\w*"()]+\'?)*[\w*"()])(?:[^\w*"()]|$)#u', $split_keywords, $matches);
167              $this->split_words = $matches[1];
168          }
169   
170          // to allow phrase search, we need to concatenate quoted words
171          $tmp_split_words = array();
172          $phrase = '';
173          foreach ($this->split_words as $word)
174          {
175              if ($phrase)
176              {
177                  $phrase .= ' ' . $word;
178                  if (strpos($word, '"') !== false && substr_count($word, '"') % 2 == 1)
179                  {
180                      $tmp_split_words[] = $phrase;
181                      $phrase = '';
182                  }
183              }
184              else if (strpos($word, '"') !== false && substr_count($word, '"') % 2 == 1)
185              {
186                  $phrase = $word;
187              }
188              else
189              {
190                  $tmp_split_words[] = $word . ' ';
191              }
192          }
193          if ($phrase)
194          {
195              $tmp_split_words[] = $phrase;
196          }
197   
198          $this->split_words = $tmp_split_words;
199   
200          unset($tmp_split_words);
201          unset($phrase);
202   
203          foreach ($this->split_words as $i => $word)
204          {
205              $clean_word = preg_replace('#^[+\-|"]#', '', $word);
206   
207              // check word length
208              $clean_len = utf8_strlen(str_replace('*', '', $clean_word));
209              if (($clean_len < $config['fulltext_mysql_min_word_len']) || ($clean_len > $config['fulltext_mysql_max_word_len']))
210              {
211                  $this->common_words[] = $word;
212                  unset($this->split_words[$i]);
213              }
214          }
215   
216          if ($terms == 'any')
217          {
218              $this->search_query = '';
219              foreach ($this->split_words as $word)
220              {
221                  if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0) || (strpos($word, '|') === 0))
222                  {
223                      $word = substr($word, 1);
224                  }
225                  $this->search_query .= $word . ' ';
226              }
227          }
228          else
229          {
230              $this->search_query = '';
231              foreach ($this->split_words as $word)
232              {
233                  if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0))
234                  {
235                      $this->search_query .= $word . ' ';
236                  }
237                  else if (strpos($word, '|') === 0)
238                  {
239                      $this->search_query .= substr($word, 1) . ' ';
240                  }
241                  else
242                  {
243                      $this->search_query .= '+' . $word . ' ';
244                  }
245              }
246          }
247   
248          $this->search_query = utf8_htmlspecialchars($this->search_query);
249   
250          if ($this->search_query)
251          {
252              $this->split_words = array_values($this->split_words);
253              sort($this->split_words);
254              return true;
255          }
256          return false;
257      }
258   
259      /**
260      * Turns text into an array of words
261      */
262      function split_message($text)
263      {
264          global $config;
265   
266          // Split words
267          if ($this->pcre_properties)
268          {
269              $text = preg_replace('#([^\p{L}\p{N}\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text)));
270          }
271          else if ($this->mbstring_regex)
272          {
273              $text = mb_ereg_replace('([^\w\'*])', '\\1\\1', str_replace('\'\'', '\' \'', trim($text)));
274          }
275          else
276          {
277              $text = preg_replace('#([^\w\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text)));
278          }
279   
280          if ($this->pcre_properties)
281          {
282              $matches = array();
283              preg_match_all('#(?:[^\p{L}\p{N}*]|^)([+\-|]?(?:[\p{L}\p{N}*]+\'?)*[\p{L}\p{N}*])(?:[^\p{L}\p{N}*]|$)#u', $text, $matches);
284              $text = $matches[1];
285          }
286          else if ($this->mbstring_regex)
287          {
288              mb_ereg_search_init($text, '(?:[^\w*]|^)([+\-|]?(?:[\w*]+\'?)*[\w*])(?:[^\w*]|$)');
289   
290              $text = array();
291              while (($word = mb_ereg_search_regs()))
292              {
293                  $text[] = $word[1];
294              }
295          }
296          else
297          {
298              $matches = array();
299              preg_match_all('#(?:[^\w*]|^)([+\-|]?(?:[\w*]+\'?)*[\w*])(?:[^\w*]|$)#u', $text, $matches);
300              $text = $matches[1];
301          }
302   
303          // remove too short or too long words
304          $text = array_values($text);
305          for ($i = 0, $n = sizeof($text); $i < $n; $i++)
306          {
307              $text[$i] = trim($text[$i]);
308              if (utf8_strlen($text[$i]) < $config['fulltext_mysql_min_word_len'] || utf8_strlen($text[$i]) > $config['fulltext_mysql_max_word_len'])
309              {
310                  unset($text[$i]);
311              }
312          }
313   
314          return array_values($text);
315      }
316   
317      /**
318      * Performs a search on keywords depending on display specific params. You have to run split_keywords() first.
319      *
320      * @param    string        $type                contains either posts or topics depending on what should be searched for
321      * @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)
322      * @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)
323      * @param    array        &$sort_by_sql        contains SQL code for the ORDER BY part of a query
324      * @param    string        &$sort_key            is the key of $sort_by_sql for the selected sorting
325      * @param    string        &$sort_dir            is either a or d representing ASC and DESC
326      * @param    string        &$sort_days            specifies the maximum amount of days a post may be old
327      * @param    array        &$ex_fid_ary        specifies an array of forum ids which should not be searched
328      * @param    array        &$m_approve_fid_ary    specifies an array of forum ids in which the searcher is allowed to view unapproved posts
329      * @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
330      * @param    array        &$author_ary        an array of author ids if the author should be ignored during the search the array is empty
331      * @param    array        &$id_ary            passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered
332      * @param    int            $start                indicates the first index of the page
333      * @param    int            $per_page            number of ids each page is supposed to contain
334      * @return    boolean|int                        total number of results
335      *
336      * @access    public
337      */
338      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, &$id_ary, $start, $per_page)
339      {
340          global $config, $db;
341   
342          // No keywords? No posts.
343          if (!$this->search_query)
344          {
345              return false;
346          }
347   
348          // generate a search_key from all the options to identify the results
349          $search_key = md5(implode('#', array(
350              implode(', ', $this->split_words),
351              $type,
352              $fields,
353              $terms,
354              $sort_days,
355              $sort_key,
356              $topic_id,
357              implode(',', $ex_fid_ary),
358              implode(',', $m_approve_fid_ary),
359              implode(',', $author_ary)
360          )));
361   
362          // try reading the results from cache
363          $result_count = 0;
364          if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE)
365          {
366              return $result_count;
367          }
368   
369          $id_ary = array();
370   
371          $join_topic = ($type == 'posts') ? false : true;
372   
373          // Build sql strings for sorting
374          $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
375          $sql_sort_table = $sql_sort_join = '';
376   
377          switch ($sql_sort[0])
378          {
379              case 'u':
380                  $sql_sort_table    = USERS_TABLE . ' u, ';
381                  $sql_sort_join    = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster ';
382              break;
383   
384              case 't':
385                  $join_topic = true;
386              break;
387   
388              case 'f':
389                  $sql_sort_table    = FORUMS_TABLE . ' f, ';
390                  $sql_sort_join    = ' AND f.forum_id = p.forum_id ';
391              break;
392          }
393   
394          // Build some display specific sql strings
395          switch ($fields)
396          {
397              case 'titleonly':
398                  $sql_match = 'p.post_subject';
399                  $sql_match_where = ' AND p.post_id = t.topic_first_post_id';
400                  $join_topic = true;
401              break;
402   
403              case 'msgonly':
404                  $sql_match = 'p.post_text';
405                  $sql_match_where = '';
406              break;
407   
408              case 'firstpost':
409                  $sql_match = 'p.post_subject, p.post_text';
410                  $sql_match_where = ' AND p.post_id = t.topic_first_post_id';
411                  $join_topic = true;
412              break;
413   
414              default:
415                  $sql_match = 'p.post_subject, p.post_text';
416                  $sql_match_where = '';
417              break;
418          }
419   
420          if (!sizeof($m_approve_fid_ary))
421          {
422              $m_approve_fid_sql = ' AND p.post_approved = 1';
423          }
424          else if ($m_approve_fid_ary === array(-1))
425          {
426              $m_approve_fid_sql = '';
427          }
428          else
429          {
430              $m_approve_fid_sql = ' AND (p.post_approved = 1 OR ' . $db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')';
431          }
432   
433          $sql_select            = (!$result_count) ? 'SQL_CALC_FOUND_ROWS ' : '';
434          $sql_select            = ($type == 'posts') ? $sql_select . 'p.post_id' : 'DISTINCT ' . $sql_select . 't.topic_id';
435          $sql_from            = ($join_topic) ? TOPICS_TABLE . ' t, ' : '';
436          $field                = ($type == 'posts') ? 'post_id' : 'topic_id';
437          $sql_author            = (sizeof($author_ary) == 1) ? ' = ' . $author_ary[0] : 'IN (' . implode(', ', $author_ary) . ')';
438   
439          $sql_where_options = $sql_sort_join;
440          $sql_where_options .= ($topic_id) ? ' AND p.topic_id = ' . $topic_id : '';
441          $sql_where_options .= ($join_topic) ? ' AND t.topic_id = p.topic_id' : '';
442          $sql_where_options .= (sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
443          $sql_where_options .= $m_approve_fid_sql;
444          $sql_where_options .= (sizeof($author_ary)) ? ' AND p.poster_id ' . $sql_author : '';
445          $sql_where_options .= ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
446          $sql_where_options .= $sql_match_where;
447   
448          $sql = "SELECT $sql_select
449              FROM $sql_from$sql_sort_table" . POSTS_TABLE . " p
450              WHERE MATCH ($sql_match) AGAINST ('" . $db->sql_escape(htmlspecialchars_decode($this->search_query)) . "' IN BOOLEAN MODE)
451                  $sql_where_options
452              ORDER BY $sql_sort";
453          $result = $db->sql_query_limit($sql, $config['search_block_size'], $start);
454   
455          while ($row = $db->sql_fetchrow($result))
456          {
457              $id_ary[] = $row[$field];
458          }
459          $db->sql_freeresult($result);
460   
461          $id_ary = array_unique($id_ary);
462   
463          if (!sizeof($id_ary))
464          {
465              return false;
466          }
467   
468          // if the total result count is not cached yet, retrieve it from the db
469          if (!$result_count)
470          {
471              $sql = 'SELECT FOUND_ROWS() as result_count';
472              $result = $db->sql_query($sql);
473              $result_count = (int) $db->sql_fetchfield('result_count');
474              $db->sql_freeresult($result);
475   
476              if (!$result_count)
477              {
478                  return false;
479              }
480          }
481   
482          // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page
483          $this->save_ids($search_key, implode(' ', $this->split_words), $author_ary, $result_count, $id_ary, $start, $sort_dir);
484          $id_ary = array_slice($id_ary, 0, (int) $per_page);
485   
486          return $result_count;
487      }
488   
489      /**
490      * Performs a search on an author's posts without caring about message contents. Depends on display specific params
491      *
492      * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered
493      * @param int $start indicates the first index of the page
494      * @param int $per_page number of ids each page is supposed to contain
495      * @return total number of results
496      */
497      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, &$id_ary, $start, $per_page)
498      {
499          global $config, $db;
500   
501          // No author? No posts.
502          if (!sizeof($author_ary))
503          {
504              return 0;
505          }
506   
507          // generate a search_key from all the options to identify the results
508          $search_key = md5(implode('#', array(
509              '',
510              $type,
511              ($firstpost_only) ? 'firstpost' : '',
512              '',
513              '',
514              $sort_days,
515              $sort_key,
516              $topic_id,
517              implode(',', $ex_fid_ary),
518              implode(',', $m_approve_fid_ary),
519              implode(',', $author_ary)
520          )));
521   
522          // try reading the results from cache
523          $result_count = 0;
524          if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE)
525          {
526              return $result_count;
527          }
528   
529          $id_ary = array();
530   
531          // Create some display specific sql strings
532          $sql_author        = $db->sql_in_set('p.poster_id', $author_ary);
533          $sql_fora        = (sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
534          $sql_topic_id    = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : '';
535          $sql_time        = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
536          $sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : '';
537   
538          // Build sql strings for sorting
539          $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
540          $sql_sort_table = $sql_sort_join = '';
541          switch ($sql_sort[0])
542          {
543              case 'u':
544                  $sql_sort_table    = USERS_TABLE . ' u, ';
545                  $sql_sort_join    = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster ';
546              break;
547   
548              case 't':
549                  $sql_sort_table    = ($type == 'posts') ? TOPICS_TABLE . ' t, ' : '';
550                  $sql_sort_join    = ($type == 'posts') ? ' AND t.topic_id = p.topic_id ' : '';
551              break;
552   
553              case 'f':
554                  $sql_sort_table    = FORUMS_TABLE . ' f, ';
555                  $sql_sort_join    = ' AND f.forum_id = p.forum_id ';
556              break;
557          }
558   
559          if (!sizeof($m_approve_fid_ary))
560          {
561              $m_approve_fid_sql = ' AND p.post_approved = 1';
562          }
563          else if ($m_approve_fid_ary == array(-1))
564          {
565              $m_approve_fid_sql = '';
566          }
567          else
568          {
569              $m_approve_fid_sql = ' AND (p.post_approved = 1 OR ' . $db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')';
570          }
571   
572          // If the cache was completely empty count the results
573          $calc_results = ($result_count) ? '' : 'SQL_CALC_FOUND_ROWS ';
574   
575          // Build the query for really selecting the post_ids
576          if ($type == 'posts')
577          {
578              $sql = "SELECT {$calc_results}p.post_id
579                  FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . "
580                  WHERE $sql_author
581                      $sql_topic_id
582                      $sql_firstpost
583                      $m_approve_fid_sql
584                      $sql_fora
585                      $sql_sort_join
586                      $sql_time
587                  ORDER BY $sql_sort";
588              $field = 'post_id';
589          }
590          else
591          {
592              $sql = "SELECT {$calc_results}t.topic_id
593                  FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
594                  WHERE $sql_author
595                      $sql_topic_id
596                      $sql_firstpost
597                      $m_approve_fid_sql
598                      $sql_fora
599                      AND t.topic_id = p.topic_id
600                      $sql_sort_join
601                      $sql_time
602                  GROUP BY t.topic_id
603                  ORDER BY $sql_sort";
604              $field = 'topic_id';
605          }
606   
607          // Only read one block of posts from the db and then cache it
608          $result = $db->sql_query_limit($sql, $config['search_block_size'], $start);
609   
610          while ($row = $db->sql_fetchrow($result))
611          {
612              $id_ary[] = $row[$field];
613          }
614          $db->sql_freeresult($result);
615   
616          // retrieve the total result count if needed
617          if (!$result_count)
618          {
619              $sql = 'SELECT FOUND_ROWS() as result_count';
620              $result = $db->sql_query($sql);
621              $result_count = (int) $db->sql_fetchfield('result_count');
622              $db->sql_freeresult($result);
623   
624              if (!$result_count)
625              {
626                  return false;
627              }
628          }
629   
630          if (sizeof($id_ary))
631          {
632              $this->save_ids($search_key, '', $author_ary, $result_count, $id_ary, $start, $sort_dir);
633              $id_ary = array_slice($id_ary, 0, $per_page);
634   
635              return $result_count;
636          }
637          return false;
638      }
639   
640      /**
641      * Destroys cached search results, that contained one of the new words in a post so the results won't be outdated.
642      *
643      * @param string $mode contains the post mode: edit, post, reply, quote ...
644      */
645      function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id)
646      {
647          global $db;
648   
649          // Split old and new post/subject to obtain array of words
650          $split_text = $this->split_message($message);
651          $split_title = ($subject) ? $this->split_message($subject) : array();
652   
653          $words = array_unique(array_merge($split_text, $split_title));
654   
655          unset($split_text);
656          unset($split_title);
657   
658          // destroy cached search results containing any of the words removed or added
659          $this->destroy_cache($words, array($poster_id));
660   
661          unset($words);
662      }
663   
664      /**
665      * Destroy cached results, that might be outdated after deleting a post
666      */
667      function index_remove($post_ids, $author_ids, $forum_ids)
668      {
669          $this->destroy_cache(array(), $author_ids);
670      }
671   
672      /**
673      * Destroy old cache entries
674      */
675      function tidy()
676      {
677          global $db, $config;
678   
679          // destroy too old cached search results
680          $this->destroy_cache(array());
681   
682          set_config('search_last_gc', time(), true);
683      }
684   
685      /**
686      * Create fulltext index
687      */
688      function create_index($acp_module, $u_action)
689      {
690          global $db;
691   
692          // Make sure we can actually use MySQL with fulltext indexes
693          if ($error = $this->init())
694          {
695              return $error;
696          }
697   
698          if (empty($this->stats))
699          {
700              $this->get_stats();
701          }
702   
703          $alter = array();
704   
705          if (!isset($this->stats['post_subject']))
706          {
707              if ($db->sql_layer == 'mysqli' || version_compare($db->mysql_version, '4.1.3', '>='))
708              {
709                  //$alter[] = 'MODIFY post_subject varchar(100) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL';
710              }
711              else
712              {
713                  $alter[] = 'MODIFY post_subject text NOT NULL';
714              }
715              $alter[] = 'ADD FULLTEXT (post_subject)';
716          }
717   
718          if (!isset($this->stats['post_text']))
719          {
720              if ($db->sql_layer == 'mysqli' || version_compare($db->mysql_version, '4.1.3', '>='))
721              {
722                  $alter[] = 'MODIFY post_text mediumtext COLLATE utf8_unicode_ci NOT NULL';
723              }
724              else
725              {
726                  $alter[] = 'MODIFY post_text mediumtext NOT NULL';
727              }
728              $alter[] = 'ADD FULLTEXT (post_text)';
729          }
730   
731          if (!isset($this->stats['post_content']))
732          {
733              $alter[] = 'ADD FULLTEXT post_content (post_subject, post_text)';
734          }
735   
736          if (sizeof($alter))
737          {
738              $db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter));
739          }
740   
741          $db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);
742   
743          return false;
744      }
745   
746      /**
747      * Drop fulltext index
748      */
749      function delete_index($acp_module, $u_action)
750      {
751          global $db;
752   
753          // Make sure we can actually use MySQL with fulltext indexes
754          if ($error = $this->init())
755          {
756              return $error;
757          }
758   
759          if (empty($this->stats))
760          {
761              $this->get_stats();
762          }
763   
764          $alter = array();
765   
766          if (isset($this->stats['post_subject']))
767          {
768              $alter[] = 'DROP INDEX post_subject';
769          }
770   
771          if (isset($this->stats['post_text']))
772          {
773              $alter[] = 'DROP INDEX post_text';
774          }
775   
776          if (isset($this->stats['post_content']))
777          {
778              $alter[] = 'DROP INDEX post_content';
779          }
780   
781          if (sizeof($alter))
782          {
783              $db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter));
784          }
785   
786          $db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);
787   
788          return false;
789      }
790   
791      /**
792      * Returns true if both FULLTEXT indexes exist
793      */
794      function index_created()
795      {
796          if (empty($this->stats))
797          {
798              $this->get_stats();
799          }
800   
801          return (isset($this->stats['post_text']) && isset($this->stats['post_subject']) && isset($this->stats['post_content'])) ? true : false;
802      }
803   
804      /**
805      * Returns an associative array containing information about the indexes
806      */
807      function index_stats()
808      {
809          global $user;
810   
811          if (empty($this->stats))
812          {
813              $this->get_stats();
814          }
815   
816          return array(
817              $user->lang['FULLTEXT_MYSQL_TOTAL_POSTS']            => ($this->index_created()) ? $this->stats['total_posts'] : 0,
818          );
819      }
820   
821      function get_stats()
822      {
823          global $db;
824   
825          if (strpos($db->sql_layer, 'mysql') === false)
826          {
827              $this->stats = array();
828              return;
829          }
830   
831          $sql = 'SHOW INDEX
832              FROM ' . POSTS_TABLE;
833          $result = $db->sql_query($sql);
834   
835          while ($row = $db->sql_fetchrow($result))
836          {
837              // deal with older MySQL versions which didn't use Index_type
838              $index_type = (isset($row['Index_type'])) ? $row['Index_type'] : $row['Comment'];
839   
840              if ($index_type == 'FULLTEXT')
841              {
842                  if ($row['Key_name'] == 'post_text')
843                  {
844                      $this->stats['post_text'] = $row;
845                  }
846                  else if ($row['Key_name'] == 'post_subject')
847                  {
848                      $this->stats['post_subject'] = $row;
849                  }
850                  else if ($row['Key_name'] == 'post_content')
851                  {
852                      $this->stats['post_content'] = $row;
853                  }
854              }
855          }
856          $db->sql_freeresult($result);
857   
858          $sql = 'SELECT COUNT(post_id) as total_posts
859              FROM ' . POSTS_TABLE;
860          $result = $db->sql_query($sql);
861          $this->stats['total_posts'] = (int) $db->sql_fetchfield('total_posts');
862          $db->sql_freeresult($result);
863      }
864   
865      /**
866      * Display a note, that UTF-8 support is not available with certain versions of PHP
867      */
868      function acp()
869      {
870          global $user, $config;
871   
872          $tpl = '
873          <dl>
874              <dt><label>' . $user->lang['FULLTEXT_MYSQL_PCRE'] . '</label><br /><span>' . $user->lang['FULLTEXT_MYSQL_PCRE_EXPLAIN'] . '</span></dt>
875              <dd>' . (($this->pcre_properties) ? $user->lang['YES'] : $user->lang['NO']) . ' (PHP ' . PHP_VERSION . ')</dd>
876          </dl>
877          <dl>
878              <dt><label>' . $user->lang['FULLTEXT_MYSQL_MBSTRING'] . '</label><br /><span>' . $user->lang['FULLTEXT_MYSQL_MBSTRING_EXPLAIN'] . '</span></dt>
879              <dd>' . (($this->mbstring_regex) ? $user->lang['YES'] : $user->lang['NO']). '</dd>
880          </dl>
881          ';
882   
883          // These are fields required in the config table
884          return array(
885              'tpl'        => $tpl,
886              'config'    => array()
887          );
888      }
889  }
890   
891  ?>