Mercurial > hg > vamp-website
comparison forum/Sources/ManageSearch.php @ 76:e3e11437ecea website
Add forum code
author | Chris Cannam |
---|---|
date | Sun, 07 Jul 2013 11:25:48 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
75:72f59aa7e503 | 76:e3e11437ecea |
---|---|
1 <?php | |
2 | |
3 /** | |
4 * Simple Machines Forum (SMF) | |
5 * | |
6 * @package SMF | |
7 * @author Simple Machines http://www.simplemachines.org | |
8 * @copyright 2011 Simple Machines | |
9 * @license http://www.simplemachines.org/about/smf/license.php BSD | |
10 * | |
11 * @version 2.0 | |
12 */ | |
13 | |
14 if (!defined('SMF')) | |
15 die('Hacking attempt...'); | |
16 | |
17 /* The admin screen to change the search settings. | |
18 | |
19 void ManageSearch() | |
20 - main entry point for the admin search settings screen. | |
21 - called by ?action=admin;area=managesearch. | |
22 - requires the admin_forum permission. | |
23 - loads the ManageSearch template. | |
24 - loads the Search language file. | |
25 - calls a function based on the given sub-action. | |
26 - defaults to sub-action 'settings'. | |
27 | |
28 void EditSearchSettings() | |
29 - edit some general settings related to the search function. | |
30 - called by ?action=admin;area=managesearch;sa=settings. | |
31 - requires the admin_forum permission. | |
32 - uses the 'modify_settings' sub template of the ManageSearch template. | |
33 | |
34 void EditWeights() | |
35 - edit the relative weight of the search factors. | |
36 - called by ?action=admin;area=managesearch;sa=weights. | |
37 - requires the admin_forum permission. | |
38 - uses the 'modify_weights' sub template of the ManageSearch template. | |
39 | |
40 void EditSearchMethod() | |
41 - edit the search method and search index used. | |
42 - called by ?action=admin;area=managesearch;sa=method. | |
43 - requires the admin_forum permission. | |
44 - uses the 'select_search_method' sub template of the ManageSearch | |
45 template. | |
46 - allows to create and delete a fulltext index on the messages table. | |
47 - allows to delete a custom index (that CreateMessageIndex() created). | |
48 - calculates the size of the current search indexes in use. | |
49 | |
50 void CreateMessageIndex() | |
51 - create a custom search index for the messages table. | |
52 - called by ?action=admin;area=managesearch;sa=createmsgindex. | |
53 - linked from the EditSearchMethod screen. | |
54 - requires the admin_forum permission. | |
55 - uses the 'create_index', 'create_index_progress', and | |
56 'create_index_done' sub templates of the ManageSearch template. | |
57 - depending on the size of the message table, the process is divided | |
58 in steps. | |
59 | |
60 array loadSearchAPIs() | |
61 - get the installed APIs. | |
62 | |
63 */ | |
64 | |
65 function ManageSearch() | |
66 { | |
67 global $context, $txt, $scripturl; | |
68 | |
69 isAllowedTo('admin_forum'); | |
70 | |
71 loadLanguage('Search'); | |
72 loadTemplate('ManageSearch'); | |
73 | |
74 db_extend('search'); | |
75 | |
76 $subActions = array( | |
77 'settings' => 'EditSearchSettings', | |
78 'weights' => 'EditWeights', | |
79 'method' => 'EditSearchMethod', | |
80 'createfulltext' => 'EditSearchMethod', | |
81 'removecustom' => 'EditSearchMethod', | |
82 'removefulltext' => 'EditSearchMethod', | |
83 'createmsgindex' => 'CreateMessageIndex', | |
84 ); | |
85 | |
86 // Default the sub-action to 'edit search settings'. | |
87 $_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'weights'; | |
88 | |
89 $context['sub_action'] = $_REQUEST['sa']; | |
90 | |
91 // Create the tabs for the template. | |
92 $context[$context['admin_menu_name']]['tab_data'] = array( | |
93 'title' => $txt['manage_search'], | |
94 'help' => 'search', | |
95 'description' => $txt['search_settings_desc'], | |
96 'tabs' => array( | |
97 'weights' => array( | |
98 'description' => $txt['search_weights_desc'], | |
99 ), | |
100 'method' => array( | |
101 'description' => $txt['search_method_desc'], | |
102 ), | |
103 'settings' => array( | |
104 'description' => $txt['search_settings_desc'], | |
105 ), | |
106 ), | |
107 ); | |
108 | |
109 // Call the right function for this sub-acton. | |
110 $subActions[$_REQUEST['sa']](); | |
111 } | |
112 | |
113 function EditSearchSettings($return_config = false) | |
114 { | |
115 global $txt, $context, $scripturl, $sourcedir, $modSettings; | |
116 | |
117 // What are we editing anyway? | |
118 $config_vars = array( | |
119 // Permission... | |
120 array('permissions', 'search_posts'), | |
121 // Some simple settings. | |
122 array('check', 'simpleSearch'), | |
123 array('int', 'search_results_per_page'), | |
124 array('int', 'search_max_results', 'subtext' => $txt['search_max_results_disable']), | |
125 '', | |
126 // Some limitations. | |
127 array('int', 'search_floodcontrol_time', 'subtext' => $txt['search_floodcontrol_time_desc']), | |
128 ); | |
129 | |
130 // Perhaps the search method wants to add some settings? | |
131 $modSettings['search_index'] = empty($modSettings['search_index']) ? 'standard' : $modSettings['search_index']; | |
132 if (file_exists($sourcedir . '/SearchAPI-' . ucwords($modSettings['search_index']) . '.php')) | |
133 { | |
134 loadClassFile('SearchAPI-' . ucwords($modSettings['search_index']) . '.php'); | |
135 | |
136 $method_call = array($modSettings['search_index'] . '_search', 'searchSettings'); | |
137 if (is_callable($method_call)) | |
138 call_user_func_array($method_call, array(&$config_vars)); | |
139 } | |
140 | |
141 if ($return_config) | |
142 return $config_vars; | |
143 | |
144 $context['page_title'] = $txt['search_settings_title']; | |
145 $context['sub_template'] = 'show_settings'; | |
146 | |
147 // We'll need this for the settings. | |
148 require_once($sourcedir . '/ManageServer.php'); | |
149 | |
150 // A form was submitted. | |
151 if (isset($_REQUEST['save'])) | |
152 { | |
153 checkSession(); | |
154 | |
155 saveDBSettings($config_vars); | |
156 redirectexit('action=admin;area=managesearch;sa=settings;' . $context['session_var'] . '=' . $context['session_id']); | |
157 } | |
158 | |
159 // Prep the template! | |
160 $context['post_url'] = $scripturl . '?action=admin;area=managesearch;save;sa=settings'; | |
161 $context['settings_title'] = $txt['search_settings_title']; | |
162 | |
163 prepareDBSettingContext($config_vars); | |
164 } | |
165 | |
166 function EditWeights() | |
167 { | |
168 global $txt, $context, $modSettings; | |
169 | |
170 $context['page_title'] = $txt['search_weights_title']; | |
171 $context['sub_template'] = 'modify_weights'; | |
172 | |
173 $factors = array( | |
174 'search_weight_frequency', | |
175 'search_weight_age', | |
176 'search_weight_length', | |
177 'search_weight_subject', | |
178 'search_weight_first_message', | |
179 'search_weight_sticky', | |
180 ); | |
181 | |
182 // A form was submitted. | |
183 if (isset($_POST['save'])) | |
184 { | |
185 checkSession(); | |
186 | |
187 $changes = array(); | |
188 foreach ($factors as $factor) | |
189 $changes[$factor] = (int) $_POST[$factor]; | |
190 updateSettings($changes); | |
191 } | |
192 | |
193 $context['relative_weights'] = array('total' => 0); | |
194 foreach ($factors as $factor) | |
195 $context['relative_weights']['total'] += isset($modSettings[$factor]) ? $modSettings[$factor] : 0; | |
196 | |
197 foreach ($factors as $factor) | |
198 $context['relative_weights'][$factor] = round(100 * (isset($modSettings[$factor]) ? $modSettings[$factor] : 0) / $context['relative_weights']['total'], 1); | |
199 } | |
200 | |
201 function EditSearchMethod() | |
202 { | |
203 global $txt, $context, $modSettings, $smcFunc, $db_type, $db_prefix; | |
204 | |
205 $context[$context['admin_menu_name']]['current_subsection'] = 'method'; | |
206 $context['page_title'] = $txt['search_method_title']; | |
207 $context['sub_template'] = 'select_search_method'; | |
208 $context['supports_fulltext'] = $smcFunc['db_search_support']('fulltext'); | |
209 | |
210 // Load any apis. | |
211 $context['search_apis'] = loadSearchAPIs(); | |
212 | |
213 // Detect whether a fulltext index is set. | |
214 if ($context['supports_fulltext']) | |
215 { | |
216 $request = $smcFunc['db_query']('', ' | |
217 SHOW INDEX | |
218 FROM {db_prefix}messages', | |
219 array( | |
220 ) | |
221 ); | |
222 $context['fulltext_index'] = ''; | |
223 if ($request !== false || $smcFunc['db_num_rows']($request) != 0) | |
224 { | |
225 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
226 if ($row['Column_name'] == 'body' && (isset($row['Index_type']) && $row['Index_type'] == 'FULLTEXT' || isset($row['Comment']) && $row['Comment'] == 'FULLTEXT')) | |
227 $context['fulltext_index'][] = $row['Key_name']; | |
228 $smcFunc['db_free_result']($request); | |
229 | |
230 if (is_array($context['fulltext_index'])) | |
231 $context['fulltext_index'] = array_unique($context['fulltext_index']); | |
232 } | |
233 | |
234 $request = $smcFunc['db_query']('', ' | |
235 SHOW COLUMNS | |
236 FROM {db_prefix}messages', | |
237 array( | |
238 ) | |
239 ); | |
240 if ($request !== false) | |
241 { | |
242 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
243 if ($row['Field'] == 'body' && $row['Type'] == 'mediumtext') | |
244 $context['cannot_create_fulltext'] = true; | |
245 $smcFunc['db_free_result']($request); | |
246 } | |
247 | |
248 if (preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) !== 0) | |
249 $request = $smcFunc['db_query']('', ' | |
250 SHOW TABLE STATUS | |
251 FROM {string:database_name} | |
252 LIKE {string:table_name}', | |
253 array( | |
254 'database_name' => '`' . strtr($match[1], array('`' => '')) . '`', | |
255 'table_name' => str_replace('_', '\_', $match[2]) . 'messages', | |
256 ) | |
257 ); | |
258 else | |
259 $request = $smcFunc['db_query']('', ' | |
260 SHOW TABLE STATUS | |
261 LIKE {string:table_name}', | |
262 array( | |
263 'table_name' => str_replace('_', '\_', $db_prefix) . 'messages', | |
264 ) | |
265 ); | |
266 | |
267 if ($request !== false) | |
268 { | |
269 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
270 if ((isset($row['Type']) && strtolower($row['Type']) != 'myisam') || (isset($row['Engine']) && strtolower($row['Engine']) != 'myisam')) | |
271 $context['cannot_create_fulltext'] = true; | |
272 $smcFunc['db_free_result']($request); | |
273 } | |
274 } | |
275 | |
276 if (!empty($_REQUEST['sa']) && $_REQUEST['sa'] == 'createfulltext') | |
277 { | |
278 checkSession('get'); | |
279 | |
280 // Make sure it's gone before creating it. | |
281 $smcFunc['db_query']('', ' | |
282 ALTER TABLE {db_prefix}messages | |
283 DROP INDEX body', | |
284 array( | |
285 'db_error_skip' => true, | |
286 ) | |
287 ); | |
288 | |
289 $smcFunc['db_query']('', ' | |
290 ALTER TABLE {db_prefix}messages | |
291 ADD FULLTEXT body (body)', | |
292 array( | |
293 ) | |
294 ); | |
295 | |
296 $context['fulltext_index'] = 'body'; | |
297 } | |
298 elseif (!empty($_REQUEST['sa']) && $_REQUEST['sa'] == 'removefulltext' && !empty($context['fulltext_index'])) | |
299 { | |
300 checkSession('get'); | |
301 | |
302 $smcFunc['db_query']('', ' | |
303 ALTER TABLE {db_prefix}messages | |
304 DROP INDEX ' . implode(', | |
305 DROP INDEX ', $context['fulltext_index']), | |
306 array( | |
307 'db_error_skip' => true, | |
308 ) | |
309 ); | |
310 | |
311 $context['fulltext_index'] = ''; | |
312 | |
313 // Go back to the default search method. | |
314 if (!empty($modSettings['search_index']) && $modSettings['search_index'] == 'fulltext') | |
315 updateSettings(array( | |
316 'search_index' => '', | |
317 )); | |
318 } | |
319 elseif (!empty($_REQUEST['sa']) && $_REQUEST['sa'] == 'removecustom') | |
320 { | |
321 checkSession('get'); | |
322 | |
323 db_extend(); | |
324 $tables = $smcFunc['db_list_tables'](false, $db_prefix . 'log_search_words'); | |
325 if (!empty($tables)) | |
326 { | |
327 $smcFunc['db_search_query']('drop_words_table', ' | |
328 DROP TABLE {db_prefix}log_search_words', | |
329 array( | |
330 ) | |
331 ); | |
332 } | |
333 | |
334 updateSettings(array( | |
335 'search_custom_index_config' => '', | |
336 'search_custom_index_resume' => '', | |
337 )); | |
338 | |
339 // Go back to the default search method. | |
340 if (!empty($modSettings['search_index']) && $modSettings['search_index'] == 'custom') | |
341 updateSettings(array( | |
342 'search_index' => '', | |
343 )); | |
344 } | |
345 elseif (isset($_POST['save'])) | |
346 { | |
347 checkSession(); | |
348 updateSettings(array( | |
349 'search_index' => empty($_POST['search_index']) || (!in_array($_POST['search_index'], array('fulltext', 'custom')) && !isset($context['search_apis'][$_POST['search_index']])) ? '' : $_POST['search_index'], | |
350 'search_force_index' => isset($_POST['search_force_index']) ? '1' : '0', | |
351 'search_match_words' => isset($_POST['search_match_words']) ? '1' : '0', | |
352 )); | |
353 } | |
354 | |
355 $context['table_info'] = array( | |
356 'data_length' => 0, | |
357 'index_length' => 0, | |
358 'fulltext_length' => 0, | |
359 'custom_index_length' => 0, | |
360 ); | |
361 | |
362 // Get some info about the messages table, to show its size and index size. | |
363 if ($db_type == 'mysql') | |
364 { | |
365 if (preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) !== 0) | |
366 $request = $smcFunc['db_query']('', ' | |
367 SHOW TABLE STATUS | |
368 FROM {string:database_name} | |
369 LIKE {string:table_name}', | |
370 array( | |
371 'database_name' => '`' . strtr($match[1], array('`' => '')) . '`', | |
372 'table_name' => str_replace('_', '\_', $match[2]) . 'messages', | |
373 ) | |
374 ); | |
375 else | |
376 $request = $smcFunc['db_query']('', ' | |
377 SHOW TABLE STATUS | |
378 LIKE {string:table_name}', | |
379 array( | |
380 'table_name' => str_replace('_', '\_', $db_prefix) . 'messages', | |
381 ) | |
382 ); | |
383 if ($request !== false && $smcFunc['db_num_rows']($request) == 1) | |
384 { | |
385 // Only do this if the user has permission to execute this query. | |
386 $row = $smcFunc['db_fetch_assoc']($request); | |
387 $context['table_info']['data_length'] = $row['Data_length']; | |
388 $context['table_info']['index_length'] = $row['Index_length']; | |
389 $context['table_info']['fulltext_length'] = $row['Index_length']; | |
390 $smcFunc['db_free_result']($request); | |
391 } | |
392 | |
393 // Now check the custom index table, if it exists at all. | |
394 if (preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) !== 0) | |
395 $request = $smcFunc['db_query']('', ' | |
396 SHOW TABLE STATUS | |
397 FROM {string:database_name} | |
398 LIKE {string:table_name}', | |
399 array( | |
400 'database_name' => '`' . strtr($match[1], array('`' => '')) . '`', | |
401 'table_name' => str_replace('_', '\_', $match[2]) . 'log_search_words', | |
402 ) | |
403 ); | |
404 else | |
405 $request = $smcFunc['db_query']('', ' | |
406 SHOW TABLE STATUS | |
407 LIKE {string:table_name}', | |
408 array( | |
409 'table_name' => str_replace('_', '\_', $db_prefix) . 'log_search_words', | |
410 ) | |
411 ); | |
412 if ($request !== false && $smcFunc['db_num_rows']($request) == 1) | |
413 { | |
414 // Only do this if the user has permission to execute this query. | |
415 $row = $smcFunc['db_fetch_assoc']($request); | |
416 $context['table_info']['index_length'] += $row['Data_length'] + $row['Index_length']; | |
417 $context['table_info']['custom_index_length'] = $row['Data_length'] + $row['Index_length']; | |
418 $smcFunc['db_free_result']($request); | |
419 } | |
420 } | |
421 elseif ($db_type == 'postgresql') | |
422 { | |
423 // In order to report the sizes correctly we need to perform vacuum (optimize) on the tables we will be using. | |
424 db_extend(); | |
425 $temp_tables = $smcFunc['db_list_tables'](); | |
426 foreach ($temp_tables as $table) | |
427 if ($table == $db_prefix. 'messages' || $table == $db_prefix. 'log_search_words') | |
428 $smcFunc['db_optimize_table']($table); | |
429 | |
430 // PostGreSql has some hidden sizes. | |
431 $request = $smcFunc['db_query']('', ' | |
432 SELECT relname, relpages * 8 *1024 AS "KB" FROM pg_class | |
433 WHERE relname = {string:messages} OR relname = {string:log_search_words} | |
434 ORDER BY relpages DESC', | |
435 array( | |
436 'messages' => $db_prefix. 'messages', | |
437 'log_search_words' => $db_prefix. 'log_search_words', | |
438 ) | |
439 ); | |
440 | |
441 if ($request !== false && $smcFunc['db_num_rows']($request) > 0) | |
442 { | |
443 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
444 { | |
445 if ($row['relname'] == $db_prefix . 'messages') | |
446 { | |
447 $context['table_info']['data_length'] = (int) $row['KB']; | |
448 $context['table_info']['index_length'] = (int) $row['KB']; | |
449 // Doesn't support fulltext | |
450 $context['table_info']['fulltext_length'] = $txt['not_applicable']; | |
451 } | |
452 elseif ($row['relname'] == $db_prefix. 'log_search_words') | |
453 { | |
454 $context['table_info']['index_length'] = (int) $row['KB']; | |
455 $context['table_info']['custom_index_length'] = (int) $row['KB']; | |
456 } | |
457 } | |
458 $smcFunc['db_free_result']($request); | |
459 } | |
460 else | |
461 // Didn't work for some reason... | |
462 $context['table_info'] = array( | |
463 'data_length' => $txt['not_applicable'], | |
464 'index_length' => $txt['not_applicable'], | |
465 'fulltext_length' => $txt['not_applicable'], | |
466 'custom_index_length' => $txt['not_applicable'], | |
467 ); | |
468 } | |
469 else | |
470 $context['table_info'] = array( | |
471 'data_length' => $txt['not_applicable'], | |
472 'index_length' => $txt['not_applicable'], | |
473 'fulltext_length' => $txt['not_applicable'], | |
474 'custom_index_length' => $txt['not_applicable'], | |
475 ); | |
476 | |
477 // Format the data and index length in kilobytes. | |
478 foreach ($context['table_info'] as $type => $size) | |
479 { | |
480 // If it's not numeric then just break. This database engine doesn't support size. | |
481 if (!is_numeric($size)) | |
482 break; | |
483 | |
484 $context['table_info'][$type] = comma_format($context['table_info'][$type] / 1024) . ' ' . $txt['search_method_kilobytes']; | |
485 } | |
486 | |
487 $context['custom_index'] = !empty($modSettings['search_custom_index_config']); | |
488 $context['partial_custom_index'] = !empty($modSettings['search_custom_index_resume']) && empty($modSettings['search_custom_index_config']); | |
489 $context['double_index'] = !empty($context['fulltext_index']) && $context['custom_index']; | |
490 } | |
491 | |
492 function CreateMessageIndex() | |
493 { | |
494 global $modSettings, $context, $smcFunc, $db_prefix, $txt; | |
495 | |
496 // Scotty, we need more time... | |
497 @set_time_limit(600); | |
498 if (function_exists('apache_reset_timeout')) | |
499 @apache_reset_timeout(); | |
500 | |
501 $context[$context['admin_menu_name']]['current_subsection'] = 'method'; | |
502 $context['page_title'] = $txt['search_index_custom']; | |
503 | |
504 $messages_per_batch = 50; | |
505 | |
506 $index_properties = array( | |
507 2 => array( | |
508 'column_definition' => 'small', | |
509 'step_size' => 1000000, | |
510 ), | |
511 4 => array( | |
512 'column_definition' => 'medium', | |
513 'step_size' => 1000000, | |
514 'max_size' => 16777215, | |
515 ), | |
516 5 => array( | |
517 'column_definition' => 'large', | |
518 'step_size' => 100000000, | |
519 'max_size' => 2000000000, | |
520 ), | |
521 ); | |
522 | |
523 if (isset($_REQUEST['resume']) && !empty($modSettings['search_custom_index_resume'])) | |
524 { | |
525 $context['index_settings'] = unserialize($modSettings['search_custom_index_resume']); | |
526 $context['start'] = (int) $context['index_settings']['resume_at']; | |
527 unset($context['index_settings']['resume_at']); | |
528 $context['step'] = 1; | |
529 } | |
530 else | |
531 { | |
532 $context['index_settings'] = array( | |
533 'bytes_per_word' => isset($_REQUEST['bytes_per_word']) && isset($index_properties[$_REQUEST['bytes_per_word']]) ? (int) $_REQUEST['bytes_per_word'] : 2, | |
534 ); | |
535 $context['start'] = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0; | |
536 $context['step'] = isset($_REQUEST['step']) ? (int) $_REQUEST['step'] : 0; | |
537 } | |
538 | |
539 if ($context['step'] !== 0) | |
540 checkSession('request'); | |
541 | |
542 // Step 0: let the user determine how they like their index. | |
543 if ($context['step'] === 0) | |
544 { | |
545 $context['sub_template'] = 'create_index'; | |
546 } | |
547 | |
548 // Step 1: insert all the words. | |
549 if ($context['step'] === 1) | |
550 { | |
551 $context['sub_template'] = 'create_index_progress'; | |
552 | |
553 if ($context['start'] === 0) | |
554 { | |
555 db_extend(); | |
556 $tables = $smcFunc['db_list_tables'](false, $db_prefix . 'log_search_words'); | |
557 if (!empty($tables)) | |
558 { | |
559 $smcFunc['db_search_query']('drop_words_table', ' | |
560 DROP TABLE {db_prefix}log_search_words', | |
561 array( | |
562 ) | |
563 ); | |
564 } | |
565 | |
566 $smcFunc['db_create_word_search']($index_properties[$context['index_settings']['bytes_per_word']]['column_definition']); | |
567 | |
568 // Temporarily switch back to not using a search index. | |
569 if (!empty($modSettings['search_index']) && $modSettings['search_index'] == 'custom') | |
570 updateSettings(array('search_index' => '')); | |
571 | |
572 // Don't let simultanious processes be updating the search index. | |
573 if (!empty($modSettings['search_custom_index_config'])) | |
574 updateSettings(array('search_custom_index_config' => '')); | |
575 } | |
576 | |
577 $num_messages = array( | |
578 'done' => 0, | |
579 'todo' => 0, | |
580 ); | |
581 | |
582 $request = $smcFunc['db_query']('', ' | |
583 SELECT id_msg >= {int:starting_id} AS todo, COUNT(*) AS num_messages | |
584 FROM {db_prefix}messages | |
585 GROUP BY todo', | |
586 array( | |
587 'starting_id' => $context['start'], | |
588 ) | |
589 ); | |
590 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
591 $num_messages[empty($row['todo']) ? 'done' : 'todo'] = $row['num_messages']; | |
592 | |
593 if (empty($num_messages['todo'])) | |
594 { | |
595 $context['step'] = 2; | |
596 $context['percentage'] = 80; | |
597 $context['start'] = 0; | |
598 } | |
599 else | |
600 { | |
601 // Number of seconds before the next step. | |
602 $stop = time() + 3; | |
603 while (time() < $stop) | |
604 { | |
605 $inserts = array(); | |
606 $request = $smcFunc['db_query']('', ' | |
607 SELECT id_msg, body | |
608 FROM {db_prefix}messages | |
609 WHERE id_msg BETWEEN {int:starting_id} AND {int:ending_id} | |
610 LIMIT {int:limit}', | |
611 array( | |
612 'starting_id' => $context['start'], | |
613 'ending_id' => $context['start'] + $messages_per_batch - 1, | |
614 'limit' => $messages_per_batch, | |
615 ) | |
616 ); | |
617 $forced_break = false; | |
618 $number_processed = 0; | |
619 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
620 { | |
621 // In theory it's possible for one of these to take friggin ages so add more timeout protection. | |
622 if ($stop < time()) | |
623 { | |
624 $forced_break = true; | |
625 break; | |
626 } | |
627 | |
628 $number_processed++; | |
629 foreach (text2words($row['body'], $context['index_settings']['bytes_per_word'], true) as $id_word) | |
630 { | |
631 $inserts[] = array($id_word, $row['id_msg']); | |
632 } | |
633 } | |
634 $num_messages['done'] += $number_processed; | |
635 $num_messages['todo'] -= $number_processed; | |
636 $smcFunc['db_free_result']($request); | |
637 | |
638 $context['start'] += $forced_break ? $number_processed : $messages_per_batch; | |
639 | |
640 if (!empty($inserts)) | |
641 $smcFunc['db_insert']('ignore', | |
642 '{db_prefix}log_search_words', | |
643 array('id_word' => 'int', 'id_msg' => 'int'), | |
644 $inserts, | |
645 array('id_word', 'id_msg') | |
646 ); | |
647 if ($num_messages['todo'] === 0) | |
648 { | |
649 $context['step'] = 2; | |
650 $context['start'] = 0; | |
651 break; | |
652 } | |
653 else | |
654 updateSettings(array('search_custom_index_resume' => serialize(array_merge($context['index_settings'], array('resume_at' => $context['start']))))); | |
655 } | |
656 | |
657 // Since there are still two steps to go, 90% is the maximum here. | |
658 $context['percentage'] = round($num_messages['done'] / ($num_messages['done'] + $num_messages['todo']), 3) * 80; | |
659 } | |
660 } | |
661 | |
662 // Step 2: removing the words that occur too often and are of no use. | |
663 elseif ($context['step'] === 2) | |
664 { | |
665 if ($context['index_settings']['bytes_per_word'] < 4) | |
666 $context['step'] = 3; | |
667 else | |
668 { | |
669 $stop_words = $context['start'] === 0 || empty($modSettings['search_stopwords']) ? array() : explode(',', $modSettings['search_stopwords']); | |
670 $stop = time() + 3; | |
671 $context['sub_template'] = 'create_index_progress'; | |
672 $max_messages = ceil(60 * $modSettings['totalMessages'] / 100); | |
673 | |
674 while (time() < $stop) | |
675 { | |
676 $request = $smcFunc['db_query']('', ' | |
677 SELECT id_word, COUNT(id_word) AS num_words | |
678 FROM {db_prefix}log_search_words | |
679 WHERE id_word BETWEEN {int:starting_id} AND {int:ending_id} | |
680 GROUP BY id_word | |
681 HAVING COUNT(id_word) > {int:minimum_messages}', | |
682 array( | |
683 'starting_id' => $context['start'], | |
684 'ending_id' => $context['start'] + $index_properties[$context['index_settings']['bytes_per_word']]['step_size'] - 1, | |
685 'minimum_messages' => $max_messages, | |
686 ) | |
687 ); | |
688 while ($row = $smcFunc['db_fetch_assoc']($request)) | |
689 $stop_words[] = $row['id_word']; | |
690 $smcFunc['db_free_result']($request); | |
691 | |
692 updateSettings(array('search_stopwords' => implode(',', $stop_words))); | |
693 | |
694 if (!empty($stop_words)) | |
695 $smcFunc['db_query']('', ' | |
696 DELETE FROM {db_prefix}log_search_words | |
697 WHERE id_word in ({array_int:stop_words})', | |
698 array( | |
699 'stop_words' => $stop_words, | |
700 ) | |
701 ); | |
702 | |
703 $context['start'] += $index_properties[$context['index_settings']['bytes_per_word']]['step_size']; | |
704 if ($context['start'] > $index_properties[$context['index_settings']['bytes_per_word']]['max_size']) | |
705 { | |
706 $context['step'] = 3; | |
707 break; | |
708 } | |
709 } | |
710 $context['percentage'] = 80 + round($context['start'] / $index_properties[$context['index_settings']['bytes_per_word']]['max_size'], 3) * 20; | |
711 } | |
712 } | |
713 | |
714 // Step 3: remove words not distinctive enough. | |
715 if ($context['step'] === 3) | |
716 { | |
717 $context['sub_template'] = 'create_index_done'; | |
718 | |
719 updateSettings(array('search_index' => 'custom', 'search_custom_index_config' => serialize($context['index_settings']))); | |
720 $smcFunc['db_query']('', ' | |
721 DELETE FROM {db_prefix}settings | |
722 WHERE variable = {string:search_custom_index_resume}', | |
723 array( | |
724 'search_custom_index_resume' => 'search_custom_index_resume', | |
725 ) | |
726 ); | |
727 } | |
728 } | |
729 | |
730 // Get the installed APIs. | |
731 function loadSearchAPIs() | |
732 { | |
733 global $sourcedir, $txt; | |
734 | |
735 $apis = array(); | |
736 if ($dh = opendir($sourcedir)) | |
737 { | |
738 while (($file = readdir($dh)) !== false) | |
739 { | |
740 if (is_file($sourcedir . '/' . $file) && preg_match('~SearchAPI-([A-Za-z\d_]+)\.php~', $file, $matches)) | |
741 { | |
742 // Check this is definitely a valid API! | |
743 $fp = fopen($sourcedir . '/' . $file, 'rb'); | |
744 $header = fread($fp, 4096); | |
745 fclose($fp); | |
746 | |
747 if (strpos($header, '* SearchAPI-' . $matches[1] . '.php') !== false) | |
748 { | |
749 loadClassFile($file); | |
750 | |
751 $index_name = strtolower($matches[1]); | |
752 $search_class_name = $index_name . '_search'; | |
753 $searchAPI = new $search_class_name(); | |
754 | |
755 // No Support? NEXT! | |
756 if (!$searchAPI->is_supported) | |
757 continue; | |
758 | |
759 $apis[$index_name] = array( | |
760 'filename' => $file, | |
761 'setting_index' => $index_name, | |
762 'has_template' => in_array($index_name, array('custom', 'fulltext', 'standard')), | |
763 'label' => $index_name && isset($txt['search_index_' . $index_name]) ? $txt['search_index_' . $index_name] : '', | |
764 'desc' => $index_name && isset($txt['search_index_' . $index_name . '_desc']) ? $txt['search_index_' . $index_name . '_desc'] : '', | |
765 ); | |
766 } | |
767 } | |
768 } | |
769 } | |
770 closedir($dh); | |
771 | |
772 return $apis; | |
773 } | |
774 | |
775 ?> |