source: trunk/forum/includes/acp/acp_search.php

Last change on this file was 702, checked in by george, 15 years ago
  • Upraveno: Aktualizace fóra.
File size: 16.5 KB
Line 
1<?php
2/**
3*
4* @package acp
5* @version $Id$
6* @copyright (c) 2005 phpBB Group
7* @license http://opensource.org/licenses/gpl-license.php GNU Public License
8*
9*/
10
11/**
12* @ignore
13*/
14if (!defined('IN_PHPBB'))
15{
16 exit;
17}
18
19/**
20* @package acp
21*/
22class acp_search
23{
24 var $u_action;
25 var $state;
26 var $search;
27 var $max_post_id;
28 var $batch_size = 100;
29
30 function main($id, $mode)
31 {
32 global $user;
33
34 $user->add_lang('acp/search');
35
36 // For some this may be of help...
37 @ini_set('memory_limit', '128M');
38
39 switch ($mode)
40 {
41 case 'settings':
42 $this->settings($id, $mode);
43 break;
44
45 case 'index':
46 $this->index($id, $mode);
47 break;
48 }
49 }
50
51 function settings($id, $mode)
52 {
53 global $db, $user, $auth, $template, $cache;
54 global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
55
56 $submit = (isset($_POST['submit'])) ? true : false;
57
58 $search_types = $this->get_search_types();
59
60 $settings = array(
61 'search_interval' => 'float',
62 'search_anonymous_interval' => 'float',
63 'load_search' => 'bool',
64 'limit_search_load' => 'float',
65 'min_search_author_chars' => 'integer',
66 'max_num_search_keywords' => 'integer',
67 'search_store_results' => 'integer',
68 );
69
70 $search = null;
71 $error = false;
72 $search_options = '';
73 foreach ($search_types as $type)
74 {
75 if ($this->init_search($type, $search, $error))
76 {
77 continue;
78 }
79
80 $name = ucfirst(strtolower(str_replace('_', ' ', $type)));
81 $selected = ($config['search_type'] == $type) ? ' selected="selected"' : '';
82 $search_options .= '<option value="' . $type . '"' . $selected . '>' . $name . '</option>';
83
84 if (method_exists($search, 'acp'))
85 {
86 $vars = $search->acp();
87
88 if (!$submit)
89 {
90 $template->assign_block_vars('backend', array(
91 'NAME' => $name,
92 'SETTINGS' => $vars['tpl'])
93 );
94 }
95 else if (is_array($vars['config']))
96 {
97 $settings = array_merge($settings, $vars['config']);
98 }
99 }
100 }
101 unset($search);
102 unset($error);
103
104 $cfg_array = (isset($_REQUEST['config'])) ? request_var('config', array('' => ''), true) : array();
105 $updated = request_var('updated', false);
106
107 foreach ($settings as $config_name => $var_type)
108 {
109 if (!isset($cfg_array[$config_name]))
110 {
111 continue;
112 }
113
114 // e.g. integer:4:12 (min 4, max 12)
115 $var_type = explode(':', $var_type);
116
117 $config_value = $cfg_array[$config_name];
118 settype($config_value, $var_type[0]);
119
120 if (isset($var_type[1]))
121 {
122 $config_value = max($var_type[1], $config_value);
123 }
124
125 if (isset($var_type[2]))
126 {
127 $config_value = min($var_type[2], $config_value);
128 }
129
130 // only change config if anything was actually changed
131 if ($submit && ($config[$config_name] != $config_value))
132 {
133 set_config($config_name, $config_value);
134 $updated = true;
135 }
136 }
137
138 if ($submit)
139 {
140 $extra_message = '';
141 if ($updated)
142 {
143 add_log('admin', 'LOG_CONFIG_SEARCH');
144 }
145
146 if (isset($cfg_array['search_type']) && in_array($cfg_array['search_type'], $search_types, true) && ($cfg_array['search_type'] != $config['search_type']))
147 {
148 $search = null;
149 $error = false;
150
151 if (!$this->init_search($cfg_array['search_type'], $search, $error))
152 {
153 if (confirm_box(true))
154 {
155 if (!method_exists($search, 'init') || !($error = $search->init()))
156 {
157 set_config('search_type', $cfg_array['search_type']);
158
159 if (!$updated)
160 {
161 add_log('admin', 'LOG_CONFIG_SEARCH');
162 }
163 $extra_message = '<br />' . $user->lang['SWITCHED_SEARCH_BACKEND'] . '<br /><a href="' . append_sid("{$phpbb_admin_path}index.$phpEx", 'i=search&amp;mode=index') . '">&raquo; ' . $user->lang['GO_TO_SEARCH_INDEX'] . '</a>';
164 }
165 else
166 {
167 trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
168 }
169 }
170 else
171 {
172 confirm_box(false, $user->lang['CONFIRM_SEARCH_BACKEND'], build_hidden_fields(array(
173 'i' => $id,
174 'mode' => $mode,
175 'submit' => true,
176 'updated' => $updated,
177 'config' => array('search_type' => $cfg_array['search_type']),
178 )));
179 }
180 }
181 else
182 {
183 trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
184 }
185 }
186
187 $search = null;
188 $error = false;
189 if (!$this->init_search($config['search_type'], $search, $error))
190 {
191 if ($updated)
192 {
193 if (method_exists($search, 'config_updated'))
194 {
195 if ($search->config_updated())
196 {
197 trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
198 }
199 }
200 }
201 }
202 else
203 {
204 trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
205 }
206
207 trigger_error($user->lang['CONFIG_UPDATED'] . $extra_message . adm_back_link($this->u_action));
208 }
209 unset($cfg_array);
210
211 $this->tpl_name = 'acp_search';
212 $this->page_title = 'ACP_SEARCH_SETTINGS';
213
214 $template->assign_vars(array(
215 'LIMIT_SEARCH_LOAD' => (float) $config['limit_search_load'],
216 'MIN_SEARCH_AUTHOR_CHARS' => (int) $config['min_search_author_chars'],
217 'SEARCH_INTERVAL' => (float) $config['search_interval'],
218 'SEARCH_GUEST_INTERVAL' => (float) $config['search_anonymous_interval'],
219 'SEARCH_STORE_RESULTS' => (int) $config['search_store_results'],
220 'MAX_NUM_SEARCH_KEYWORDS' => (int) $config['max_num_search_keywords'],
221
222 'S_SEARCH_TYPES' => $search_options,
223 'S_YES_SEARCH' => (bool) $config['load_search'],
224 'S_SETTINGS' => true,
225
226 'U_ACTION' => $this->u_action)
227 );
228 }
229
230 function index($id, $mode)
231 {
232 global $db, $user, $auth, $template, $cache;
233 global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
234
235 if (isset($_REQUEST['action']) && is_array($_REQUEST['action']))
236 {
237 $action = request_var('action', array('' => false));
238 $action = key($action);
239 }
240 else
241 {
242 $action = request_var('action', '');
243 }
244 $this->state = explode(',', $config['search_indexing_state']);
245
246 if (isset($_POST['cancel']))
247 {
248 $action = '';
249 $this->state = array();
250 $this->save_state();
251 }
252
253 if ($action)
254 {
255 switch ($action)
256 {
257 case 'progress_bar':
258 $type = request_var('type', '');
259 $this->display_progress_bar($type);
260 break;
261
262 case 'delete':
263 $this->state[1] = 'delete';
264 break;
265
266 case 'create':
267 $this->state[1] = 'create';
268 break;
269
270 default:
271 trigger_error('NO_ACTION', E_USER_ERROR);
272 break;
273 }
274
275 if (empty($this->state[0]))
276 {
277 $this->state[0] = request_var('search_type', '');
278 }
279
280 $this->search = null;
281 $error = false;
282 if ($this->init_search($this->state[0], $this->search, $error))
283 {
284 trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
285 }
286 $name = ucfirst(strtolower(str_replace('_', ' ', $this->state[0])));
287
288 $action = &$this->state[1];
289
290 $this->max_post_id = $this->get_max_post_id();
291
292 $post_counter = (isset($this->state[2])) ? $this->state[2] : 0;
293 $this->state[2] = &$post_counter;
294 $this->save_state();
295
296 switch ($action)
297 {
298 case 'delete':
299 if (method_exists($this->search, 'delete_index'))
300 {
301 // pass a reference to myself so the $search object can make use of save_state() and attributes
302 if ($error = $this->search->delete_index($this, append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&mode=$mode&action=delete", false)))
303 {
304 $this->state = array('');
305 $this->save_state();
306 trigger_error($error . adm_back_link($this->u_action) . $this->close_popup_js(), E_USER_WARNING);
307 }
308 }
309 else
310 {
311 $starttime = explode(' ', microtime());
312 $starttime = $starttime[1] + $starttime[0];
313 $row_count = 0;
314 while (still_on_time() && $post_counter <= $this->max_post_id)
315 {
316 $sql = 'SELECT post_id, poster_id, forum_id
317 FROM ' . POSTS_TABLE . '
318 WHERE post_id >= ' . (int) ($post_counter + 1) . '
319 AND post_id <= ' . (int) ($post_counter + $this->batch_size);
320 $result = $db->sql_query($sql);
321
322 $ids = $posters = $forum_ids = array();
323 while ($row = $db->sql_fetchrow($result))
324 {
325 $ids[] = $row['post_id'];
326 $posters[] = $row['poster_id'];
327 $forum_ids[] = $row['forum_id'];
328 }
329 $db->sql_freeresult($result);
330 $row_count += sizeof($ids);
331
332 if (sizeof($ids))
333 {
334 $this->search->index_remove($ids, $posters, $forum_ids);
335 }
336
337 $post_counter += $this->batch_size;
338 }
339 // save the current state
340 $this->save_state();
341
342 if ($post_counter <= $this->max_post_id)
343 {
344 $mtime = explode(' ', microtime());
345 $totaltime = $mtime[0] + $mtime[1] - $starttime;
346 $rows_per_second = $row_count / $totaltime;
347 meta_refresh(1, append_sid($this->u_action . '&amp;action=delete&amp;skip_rows=' . $post_counter));
348 trigger_error(sprintf($user->lang['SEARCH_INDEX_DELETE_REDIRECT'], $post_counter, $row_count, $rows_per_second));
349 }
350 }
351
352 $this->search->tidy();
353
354 $this->state = array('');
355 $this->save_state();
356
357 add_log('admin', 'LOG_SEARCH_INDEX_REMOVED', $name);
358 trigger_error($user->lang['SEARCH_INDEX_REMOVED'] . adm_back_link($this->u_action) . $this->close_popup_js());
359 break;
360
361 case 'create':
362 if (method_exists($this->search, 'create_index'))
363 {
364 // pass a reference to acp_search so the $search object can make use of save_state() and attributes
365 if ($error = $this->search->create_index($this, append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&mode=$mode&action=create", false)))
366 {
367 $this->state = array('');
368 $this->save_state();
369 trigger_error($error . adm_back_link($this->u_action) . $this->close_popup_js(), E_USER_WARNING);
370 }
371 }
372 else
373 {
374 $sql = 'SELECT forum_id, enable_indexing
375 FROM ' . FORUMS_TABLE;
376 $result = $db->sql_query($sql, 3600);
377
378 while ($row = $db->sql_fetchrow($result))
379 {
380 $forums[$row['forum_id']] = (bool) $row['enable_indexing'];
381 }
382 $db->sql_freeresult($result);
383
384 $starttime = explode(' ', microtime());
385 $starttime = $starttime[1] + $starttime[0];
386 $row_count = 0;
387 while (still_on_time() && $post_counter <= $this->max_post_id)
388 {
389 $sql = 'SELECT post_id, post_subject, post_text, poster_id, forum_id
390 FROM ' . POSTS_TABLE . '
391 WHERE post_id >= ' . (int) ($post_counter + 1) . '
392 AND post_id <= ' . (int) ($post_counter + $this->batch_size);
393 $result = $db->sql_query($sql);
394
395 while ($row = $db->sql_fetchrow($result))
396 {
397 // Indexing enabled for this forum or global announcement?
398 // Global announcements get indexed by default.
399 if (!$row['forum_id'] || (isset($forums[$row['forum_id']]) && $forums[$row['forum_id']]))
400 {
401 $this->search->index('post', $row['post_id'], $row['post_text'], $row['post_subject'], $row['poster_id'], $row['forum_id']);
402 }
403 $row_count++;
404 }
405 $db->sql_freeresult($result);
406
407 $post_counter += $this->batch_size;
408 }
409 // save the current state
410 $this->save_state();
411
412 // pretend the number of posts was as big as the number of ids we indexed so far
413 // just an estimation as it includes deleted posts
414 $num_posts = $config['num_posts'];
415 $config['num_posts'] = min($config['num_posts'], $post_counter);
416 $this->search->tidy();
417 $config['num_posts'] = $num_posts;
418
419 if ($post_counter <= $this->max_post_id)
420 {
421 $mtime = explode(' ', microtime());
422 $totaltime = $mtime[0] + $mtime[1] - $starttime;
423 $rows_per_second = $row_count / $totaltime;
424 meta_refresh(1, append_sid($this->u_action . '&amp;action=create&amp;skip_rows=' . $post_counter));
425 trigger_error(sprintf($user->lang['SEARCH_INDEX_CREATE_REDIRECT'], $post_counter, $row_count, $rows_per_second));
426 }
427 }
428
429 $this->search->tidy();
430
431 $this->state = array('');
432 $this->save_state();
433
434 add_log('admin', 'LOG_SEARCH_INDEX_CREATED', $name);
435 trigger_error($user->lang['SEARCH_INDEX_CREATED'] . adm_back_link($this->u_action) . $this->close_popup_js());
436 break;
437 }
438 }
439
440 $search_types = $this->get_search_types();
441
442 $search = null;
443 $error = false;
444 $search_options = '';
445 foreach ($search_types as $type)
446 {
447 if ($this->init_search($type, $search, $error) || !method_exists($search, 'index_created'))
448 {
449 continue;
450 }
451
452 $name = ucfirst(strtolower(str_replace('_', ' ', $type)));
453
454 $data = array();
455 if (method_exists($search, 'index_stats'))
456 {
457 $data = $search->index_stats();
458 }
459
460 $statistics = array();
461 foreach ($data as $statistic => $value)
462 {
463 $n = sizeof($statistics);
464 if ($n && sizeof($statistics[$n - 1]) < 3)
465 {
466 $statistics[$n - 1] += array('statistic_2' => $statistic, 'value_2' => $value);
467 }
468 else
469 {
470 $statistics[] = array('statistic_1' => $statistic, 'value_1' => $value);
471 }
472 }
473
474 $template->assign_block_vars('backend', array(
475 'L_NAME' => $name,
476 'NAME' => $type,
477
478 'S_ACTIVE' => ($type == $config['search_type']) ? true : false,
479 'S_HIDDEN_FIELDS' => build_hidden_fields(array('search_type' => $type)),
480 'S_INDEXED' => (bool) $search->index_created(),
481 'S_STATS' => (bool) sizeof($statistics))
482 );
483
484 foreach ($statistics as $statistic)
485 {
486 $template->assign_block_vars('backend.data', array(
487 'STATISTIC_1' => $statistic['statistic_1'],
488 'VALUE_1' => $statistic['value_1'],
489 'STATISTIC_2' => (isset($statistic['statistic_2'])) ? $statistic['statistic_2'] : '',
490 'VALUE_2' => (isset($statistic['value_2'])) ? $statistic['value_2'] : '')
491 );
492 }
493 }
494 unset($search);
495 unset($error);
496 unset($statistics);
497 unset($data);
498
499 $this->tpl_name = 'acp_search';
500 $this->page_title = 'ACP_SEARCH_INDEX';
501
502 $template->assign_vars(array(
503 'S_INDEX' => true,
504 'U_ACTION' => $this->u_action,
505 'U_PROGRESS_BAR' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&amp;mode=$mode&amp;action=progress_bar"),
506 'UA_PROGRESS_BAR' => addslashes(append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&amp;mode=$mode&amp;action=progress_bar")),
507 ));
508
509 if (isset($this->state[1]))
510 {
511 $template->assign_vars(array(
512 'S_CONTINUE_INDEXING' => $this->state[1],
513 'U_CONTINUE_INDEXING' => $this->u_action . '&amp;action=' . $this->state[1],
514 'L_CONTINUE' => ($this->state[1] == 'create') ? $user->lang['CONTINUE_INDEXING'] : $user->lang['CONTINUE_DELETING_INDEX'],
515 'L_CONTINUE_EXPLAIN' => ($this->state[1] == 'create') ? $user->lang['CONTINUE_INDEXING_EXPLAIN'] : $user->lang['CONTINUE_DELETING_INDEX_EXPLAIN'])
516 );
517 }
518 }
519
520 function display_progress_bar($type)
521 {
522 global $template, $user;
523
524 $l_type = ($type == 'create') ? 'INDEXING_IN_PROGRESS' : 'DELETING_INDEX_IN_PROGRESS';
525
526 adm_page_header($user->lang[$l_type]);
527
528 $template->set_filenames(array(
529 'body' => 'progress_bar.html')
530 );
531
532 $template->assign_vars(array(
533 'L_PROGRESS' => $user->lang[$l_type],
534 'L_PROGRESS_EXPLAIN' => $user->lang[$l_type . '_EXPLAIN'])
535 );
536
537 adm_page_footer();
538 }
539
540 function close_popup_js()
541 {
542 return "<script type=\"text/javascript\">\n" .
543 "// <![CDATA[\n" .
544 " close_waitscreen = 1;\n" .
545 "// ]]>\n" .
546 "</script>\n";
547 }
548
549 function get_search_types()
550 {
551 global $phpbb_root_path, $phpEx;
552
553 $search_types = array();
554
555 $dp = @opendir($phpbb_root_path . 'includes/search');
556
557 if ($dp)
558 {
559 while (($file = readdir($dp)) !== false)
560 {
561 if ((preg_match('#\.' . $phpEx . '$#', $file)) && ($file != "search.$phpEx"))
562 {
563 $search_types[] = preg_replace('#^(.*?)\.' . $phpEx . '$#', '\1', $file);
564 }
565 }
566 closedir($dp);
567
568 sort($search_types);
569 }
570
571 return $search_types;
572 }
573
574 function get_max_post_id()
575 {
576 global $db;
577
578 $sql = 'SELECT MAX(post_id) as max_post_id
579 FROM '. POSTS_TABLE;
580 $result = $db->sql_query($sql);
581 $max_post_id = (int) $db->sql_fetchfield('max_post_id');
582 $db->sql_freeresult($result);
583
584 return $max_post_id;
585 }
586
587 function save_state($state = false)
588 {
589 if ($state)
590 {
591 $this->state = $state;
592 }
593
594 ksort($this->state);
595
596 set_config('search_indexing_state', implode(',', $this->state), true);
597 }
598
599 /**
600 * Initialises a search backend object
601 *
602 * @return false if no error occurred else an error message
603 */
604 function init_search($type, &$search, &$error)
605 {
606 global $phpbb_root_path, $phpEx, $user;
607
608 if (!preg_match('#^\w+$#', $type) || !file_exists("{$phpbb_root_path}includes/search/$type.$phpEx"))
609 {
610 $error = $user->lang['NO_SUCH_SEARCH_MODULE'];
611 return $error;
612 }
613
614 include_once("{$phpbb_root_path}includes/search/$type.$phpEx");
615
616 if (!class_exists($type))
617 {
618 $error = $user->lang['NO_SUCH_SEARCH_MODULE'];
619 return $error;
620 }
621
622 $error = false;
623 $search = new $type($error);
624
625 return $error;
626 }
627}
628
629?>
Note: See TracBrowser for help on using the repository browser.