source: forum/includes/acp/acp_search.php@ 400

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