Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 832
n/a
0 / 0
CRAP
n/a
0 / 0
1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14/**
15* @ignore
16*/
17define('IN_PHPBB', true);
18$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './';
19$phpEx = substr(strrchr(__FILE__, '.'), 1);
20include($phpbb_root_path . 'common.' . $phpEx);
21
22// Start session management
23$user->session_begin();
24$auth->acl($user->data);
25$user->setup('search');
26
27// Define initial vars
28$mode            = $request->variable('mode', '');
29$search_id        = $request->variable('search_id', '');
30$start            = max($request->variable('start', 0), 0);
31$post_id        = $request->variable('p', 0);
32$topic_id        = $request->variable('t', 0);
33$view            = $request->variable('view', '');
34
35$submit            = $request->variable('submit', false);
36$keywords        = $request->variable('keywords', '', true);
37$add_keywords    = $request->variable('add_keywords', '', true);
38$author            = $request->variable('author', '', true);
39$author_id        = $request->variable('author_id', 0);
40$show_results    = ($topic_id) ? 'posts' : $request->variable('sr', 'posts');
41$show_results    = ($show_results == 'posts') ? 'posts' : 'topics';
42$search_terms    = $request->variable('terms', 'all');
43$search_fields    = $request->variable('sf', 'all');
44$search_child    = $request->variable('sc', true);
45
46$sort_days        = $request->variable('st', 0);
47$sort_key        = $request->variable('sk', 't');
48$sort_dir        = $request->variable('sd', 'd');
49
50$return_chars    = $request->variable('ch', $topic_id ? 0 : (int) $config['default_search_return_chars']);
51$search_forum    = $request->variable('fid', array(0));
52
53// We put login boxes for the case if search_id is newposts, egosearch or unreadposts
54// because a guest should be able to log in even if guests search is not permitted
55
56switch ($search_id)
57{
58    // Egosearch is an author search
59    case 'egosearch':
60        $author_id = $user->data['user_id'];
61        if ($user->data['user_id'] == ANONYMOUS)
62        {
63            login_box('', $user->lang['LOGIN_EXPLAIN_EGOSEARCH']);
64        }
65    break;
66
67    // Search for unread posts needs to be allowed and user to be logged in if topics tracking for guests is disabled
68    case 'unreadposts':
69        if (!$config['load_unreads_search'])
70        {
71            $template->assign_var('S_NO_SEARCH', true);
72            trigger_error('NO_SEARCH_UNREADS');
73        }
74        else if (!$config['load_anon_lastread'] && !$user->data['is_registered'])
75        {
76            login_box('', $user->lang['LOGIN_EXPLAIN_UNREADSEARCH']);
77        }
78    break;
79
80    // The "new posts" search uses user_lastvisit which is user based, so it should require user to log in.
81    case 'newposts':
82        if ($user->data['user_id'] == ANONYMOUS)
83        {
84            login_box('', $user->lang['LOGIN_EXPLAIN_NEWPOSTS']);
85        }
86    break;
87
88    default:
89        // There's nothing to do here for now ;)
90    break;
91}
92
93$search_auth_check_override = false;
94/**
95* This event allows you to override search auth checks
96*
97* @event core.search_auth_check_override
98* @var    bool    search_auth_check_override    Whether or not the search auth check overridden
99* @since 3.3.14-RC1
100*/
101$vars = [
102    'search_auth_check_override',
103];
104extract($phpbb_dispatcher->trigger_event('core.search_auth_check_override', compact($vars)));
105
106// Is user able to search? Has search been disabled?
107if (!$search_auth_check_override && (!$auth->acl_get('u_search') || !$auth->acl_getf_global('f_search') || !$config['load_search']))
108{
109    $template->assign_var('S_NO_SEARCH', true);
110    trigger_error('NO_SEARCH');
111}
112
113// Check search load limit
114if ($user->load && $config['limit_search_load'] && ($user->load > doubleval($config['limit_search_load'])))
115{
116    $template->assign_var('S_NO_SEARCH', true);
117    trigger_error('NO_SEARCH_LOAD');
118}
119
120// It is applicable if the configuration setting is non-zero, and the user cannot
121// ignore the flood setting, and the search is a keyword search.
122$interval = ($user->data['user_id'] == ANONYMOUS) ? $config['search_anonymous_interval'] : $config['search_interval'];
123if ($interval && !in_array($search_id, array('unreadposts', 'unanswered', 'active_topics', 'egosearch')) && !$auth->acl_get('u_ignoreflood'))
124{
125    if ($user->data['user_last_search'] > time() - $interval)
126    {
127        $template->assign_var('S_NO_SEARCH', true);
128        trigger_error($user->lang('NO_SEARCH_TIME', (int) ($user->data['user_last_search'] + $interval - time())));
129    }
130}
131
132// Define some vars
133$limit_days        = array(0 => $user->lang['ALL_RESULTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
134$sort_by_text    = array('a' => $user->lang['SORT_AUTHOR'], 't' => $user->lang['SORT_TIME'], 'f' => $user->lang['SORT_FORUM'], 'i' => $user->lang['SORT_TOPIC_TITLE'], 's' => $user->lang['SORT_POST_SUBJECT']);
135
136$s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
137gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
138
139/* @var $phpbb_content_visibility \phpbb\content_visibility */
140$phpbb_content_visibility = $phpbb_container->get('content.visibility');
141
142/* @var $pagination \phpbb\pagination */
143$pagination = $phpbb_container->get('pagination');
144
145$template->assign_block_vars('navlinks', array(
146    'BREADCRUMB_NAME'    => $user->lang('SEARCH'),
147    'U_BREADCRUMB'        => append_sid("{$phpbb_root_path}search.$phpEx"),
148));
149
150/**
151* This event allows you to alter the above parameters, such as keywords and submit
152*
153* @event core.search_modify_submit_parameters
154* @var    string    keywords    The search keywords
155* @var    string    author        Specifies the author match, when ANONYMOUS is also a search-match
156* @var    int        author_id    ID of the author to search by
157* @var    string    search_id    Predefined search type name
158* @var    bool    submit        Whether or not the form has been submitted
159* @since 3.1.10-RC1
160*/
161$vars = array(
162    'keywords',
163    'author',
164    'author_id',
165    'search_id',
166    'submit',
167);
168extract($phpbb_dispatcher->trigger_event('core.search_modify_submit_parameters', compact($vars)));
169
170if ($keywords || $author || $author_id || $search_id || $submit)
171{
172    // clear arrays
173    $id_ary = array();
174
175    // If we are looking for authors get their ids
176    $author_id_ary = array();
177    $sql_author_match = '';
178    if ($author_id)
179    {
180        $author_id_ary[] = $author_id;
181    }
182    else if ($author)
183    {
184        if ((strpos($author, '*') !== false) && (utf8_strlen(str_replace(array('*', '%'), '', $author)) < $config['min_search_author_chars']))
185        {
186            trigger_error($user->lang('TOO_FEW_AUTHOR_CHARS', (int) $config['min_search_author_chars']));
187        }
188
189        $sql_where = (strpos($author, '*') !== false) ? ' username_clean ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " username_clean = '" . $db->sql_escape(utf8_clean_string($author)) . "'";
190
191        $sql = 'SELECT user_id
192            FROM ' . USERS_TABLE . "
193            WHERE $sql_where
194                AND user_type <> " . USER_IGNORE;
195        $result = $db->sql_query_limit($sql, 100);
196
197        while ($row = $db->sql_fetchrow($result))
198        {
199            $author_id_ary[] = (int) $row['user_id'];
200        }
201        $db->sql_freeresult($result);
202
203        $sql_where = (strpos($author, '*') !== false) ? ' post_username ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " post_username = '" . $db->sql_escape(utf8_clean_string($author)) . "'";
204
205        $sql = 'SELECT 1 as guest_post
206            FROM ' . POSTS_TABLE . "
207            WHERE $sql_where
208                AND poster_id = " . ANONYMOUS;
209        $result = $db->sql_query_limit($sql, 1);
210        $found_guest_post = $db->sql_fetchfield('guest_post');
211        $db->sql_freeresult($result);
212
213        if ($found_guest_post)
214        {
215            $author_id_ary[] = ANONYMOUS;
216            $sql_author_match = (strpos($author, '*') !== false) ? ' ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " = '" . $db->sql_escape(utf8_clean_string($author)) . "'";
217        }
218
219        if (!count($author_id_ary))
220        {
221            trigger_error('NO_SEARCH_RESULTS');
222        }
223    }
224
225    // if we search in an existing search result just add the additional keywords. But we need to use "all search terms"-mode
226    // so we can keep the old keywords in their old mode, but add the new ones as required words
227    if ($add_keywords)
228    {
229        if ($search_terms == 'all')
230        {
231            $keywords .= ' ' . $add_keywords;
232        }
233        else
234        {
235            $search_terms = 'all';
236            $keywords = implode(' |', explode(' ', preg_replace('#\s+#u', ' ', $keywords))) . ' ' .$add_keywords;
237        }
238    }
239
240    // Which forums should not be searched? Author searches are also carried out in unindexed forums
241    if (empty($keywords) && count($author_id_ary))
242    {
243        $ex_fid_ary = array_keys($auth->acl_getf('!f_read', true));
244    }
245    else
246    {
247        $ex_fid_ary = array_unique(array_merge(array_keys($auth->acl_getf('!f_read', true)), array_keys($auth->acl_getf('!f_search', true))));
248    }
249
250    // Consider if there are any forums where can read forum = no, can read topics = yes
251    // In these cases, the user should see the topic title in the search results but not the link to the topic (or any posts) because they don't have the permissions
252    if ($request->variable('sr', '') == 'topics' && $search_fields == 'titleonly')
253    {
254        // The user could get here from a quick search through the viewforum page, or by doing a main search displayed by topics and searching only the topic titles.
255        // Allow the 'can read topics = yes' forums back in to the search by removing from $ex_fid_ary any of the 'can read topics' forums
256        $ex_fid_ary = array_diff($ex_fid_ary, array_keys($auth->acl_getf('f_list_topics', true)));
257    }
258
259    $not_in_fid = (count($ex_fid_ary)) ? 'WHERE ' . $db->sql_in_set('f.forum_id', $ex_fid_ary, true) . " OR (f.forum_password <> '' AND fa.user_id <> " . (int) $user->data['user_id'] . ')' : "";
260
261    $sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.right_id, f.forum_password, f.forum_flags, fa.user_id
262        FROM ' . FORUMS_TABLE . ' f
263        LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa ON (fa.forum_id = f.forum_id
264            AND fa.session_id = '" . $db->sql_escape($user->session_id) . "')
265        $not_in_fid
266        ORDER BY f.left_id";
267    $result = $db->sql_query($sql);
268
269    $right_id = 0;
270    $reset_search_forum = true;
271    while ($row = $db->sql_fetchrow($result))
272    {
273        if ($row['forum_password'] && $row['user_id'] != $user->data['user_id'])
274        {
275            $ex_fid_ary[] = (int) $row['forum_id'];
276            continue;
277        }
278
279        // Exclude forums from active topics
280        if (!($row['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) && ($search_id == 'active_topics'))
281        {
282            $ex_fid_ary[] = (int) $row['forum_id'];
283            continue;
284        }
285
286        if (count($search_forum))
287        {
288            if ($search_child)
289            {
290                if (in_array($row['forum_id'], $search_forum) && $row['right_id'] > $right_id)
291                {
292                    $right_id = (int) $row['right_id'];
293                }
294                else if ($row['right_id'] < $right_id)
295                {
296                    continue;
297                }
298            }
299
300            if (!in_array($row['forum_id'], $search_forum))
301            {
302                $ex_fid_ary[] = (int) $row['forum_id'];
303                $reset_search_forum = false;
304            }
305        }
306    }
307    $db->sql_freeresult($result);
308
309    // find out in which forums the user is allowed to view posts
310    $m_approve_posts_fid_sql = $phpbb_content_visibility->get_global_visibility_sql('post', $ex_fid_ary, 'p.');
311    $m_approve_topics_fid_sql = $phpbb_content_visibility->get_global_visibility_sql('topic', $ex_fid_ary, 't.');
312
313    if ($reset_search_forum)
314    {
315        $search_forum = array();
316    }
317
318    // Select which method we'll use to obtain the post_id or topic_id information
319    try
320    {
321        $search_backend_factory = $phpbb_container->get('search.backend_factory');
322        $search = $search_backend_factory->get_active();
323    }
324    catch (\phpbb\search\exception\no_search_backend_found_exception $e)
325    {
326        trigger_error('NO_SUCH_SEARCH_MODULE');
327    }
328
329    // let the search module split up the keywords
330    if ($keywords)
331    {
332        $correct_query = $search->split_keywords($keywords, $search_terms);
333        $common_words = $search->get_common_words();
334        if (!$correct_query || (!$search->get_search_query() && !count($author_id_ary) && !$search_id))
335        {
336            $ignored = (count($common_words)) ? sprintf($user->lang['IGNORED_TERMS_EXPLAIN'], implode(' ', $common_words)) . '<br />' : '';
337            $word_length = $search->get_word_length();
338            if ($word_length)
339            {
340                trigger_error($ignored . $user->lang('NO_KEYWORDS', $user->lang('CHARACTERS', (int) $word_length['min']), $user->lang('CHARACTERS', (int) $word_length['max'])));
341            }
342            else
343            {
344                trigger_error($ignored);
345            }
346        }
347    }
348
349    if (!$keywords && count($author_id_ary))
350    {
351        // if it is an author search we want to show topics by default
352        $show_results = ($topic_id) ? 'posts' : $request->variable('sr', ($search_id == 'egosearch') ? 'topics' : 'posts');
353        $show_results = ($show_results == 'posts') ? 'posts' : 'topics';
354    }
355
356    // define some variables needed for retrieving post_id/topic_id information
357    $sort_by_sql = [
358        'a' => 'u.username_clean',
359        't' => (($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time'),
360        'f' => 'f.forum_id',
361        'i' => 't.topic_title',
362        's' => (($show_results == 'posts') ? 'p.post_subject' : 't.topic_title')
363    ];
364
365    /**
366    * Event to modify the SQL parameters before pre-made searches
367    *
368    * @event core.search_modify_param_before
369    * @var    string    keywords        String of the specified keywords
370    * @var    array    sort_by_sql        Array of SQL sorting instructions
371    * @var    array    ex_fid_ary        Array of excluded forum ids
372    * @var    array    author_id_ary    Array of exclusive author ids
373    * @var    string    search_id        The id of the search request
374    * @var    array    id_ary            Array of post or topic ids for search result
375    * @var    string    show_results    'posts' or 'topics' type of ids
376    * @since 3.1.3-RC1
377    * @changed 3.1.10-RC1 Added id_ary, show_results
378    */
379    $vars = array(
380        'keywords',
381        'sort_by_sql',
382        'ex_fid_ary',
383        'author_id_ary',
384        'search_id',
385        'id_ary',
386        'show_results',
387    );
388    extract($phpbb_dispatcher->trigger_event('core.search_modify_param_before', compact($vars)));
389
390    // pre-made searches
391    $sql = $field = $l_search_title = '';
392    if ($search_id)
393    {
394        switch ($search_id)
395        {
396            // Oh holy Bob, bring us some activity...
397            case 'active_topics':
398                $l_search_title = $user->lang['SEARCH_ACTIVE_TOPICS'];
399                $show_results = 'topics';
400                $sort_key = 't';
401                $sort_dir = 'd';
402                $sort_days = $request->variable('st', 7);
403                $sort_by_sql['t'] = 't.topic_last_post_time';
404
405                gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
406                $s_sort_key = $s_sort_dir = '';
407
408                $last_post_time_sql = ($sort_days) ? ' AND t.topic_last_post_time > ' . (time() - ($sort_days * 24 * 3600)) : '';
409
410                $sql = 'SELECT t.topic_last_post_time, t.topic_id
411                    FROM ' . TOPICS_TABLE . " t
412                    WHERE t.topic_moved_id = 0
413                        $last_post_time_sql
414                        AND " . $m_approve_topics_fid_sql . '
415                        ' . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '') . '
416                    ORDER BY t.topic_last_post_time DESC';
417                $field = 'topic_id';
418            break;
419
420            case 'unanswered':
421                $l_search_title = $user->lang['SEARCH_UNANSWERED'];
422                $show_results = $request->variable('sr', 'topics');
423                $show_results = ($show_results == 'posts') ? 'posts' : 'topics';
424                $sort_by_sql['t'] = ($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time';
425                $sort_by_sql['s'] = ($show_results == 'posts') ? 'p.post_subject' : 't.topic_title';
426                $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
427
428                $sort_join = ($sort_key == 'f') ? FORUMS_TABLE . ' f, ' : '';
429                $sql_sort = ($sort_key == 'f') ? ' AND f.forum_id = t.forum_id ' . $sql_sort : $sql_sort;
430
431                if ($sort_days)
432                {
433                    $last_post_time = 'AND ' . ($show_results == 'posts' ? 'p.post_time' : 't.topic_last_post_time') . ' > ' . (time() - ($sort_days * 24 * 3600));
434                }
435                else
436                {
437                    $last_post_time = '';
438                }
439
440                if ($sort_key == 'a')
441                {
442                    $sort_join = USERS_TABLE . ' u, ';
443                    $sql_sort = ' AND u.user_id = ' . ($show_results == 'posts' ? 'p.poster_id ' : 't.topic_last_poster_id ') . $sql_sort;
444                }
445                if ($show_results == 'posts')
446                {
447                    $sql = "SELECT p.post_id
448                        FROM $sort_join" . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t
449                        WHERE t.topic_posts_approved = 1
450                            AND p.topic_id = t.topic_id
451                            $last_post_time
452                            AND $m_approve_posts_fid_sql
453                            " . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . "
454                            $sql_sort";
455                    $field = 'post_id';
456                }
457                else
458                {
459                    $sql = 'SELECT DISTINCT ' . $sort_by_sql[$sort_key] . ", t.topic_id
460                        FROM $sort_join" . TOPICS_TABLE . " t
461                        WHERE t.topic_posts_approved = 1
462                            AND t.topic_moved_id = 0
463                            $last_post_time
464                            AND $m_approve_topics_fid_sql
465                            " . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '') . "
466                        $sql_sort";
467                    $field = 'topic_id';
468                }
469            break;
470
471            case 'unreadposts':
472                $l_search_title = $user->lang['SEARCH_UNREAD'];
473                // force sorting
474                $show_results = 'topics';
475                $sort_key = 't';
476                $sort_by_sql['t'] = 't.topic_last_post_time';
477                $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
478
479                $sql_where = 'AND t.topic_moved_id = 0
480                    AND ' . $m_approve_topics_fid_sql . '
481                    ' . ((count($ex_fid_ary)) ? 'AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '');
482
483                gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
484                $s_sort_key = $s_sort_dir = $u_sort_param = $s_limit_days = '';
485
486                $template->assign_var('U_MARK_ALL_READ', ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}index.$phpEx", 'hash=' . generate_link_hash('global') . '&amp;mark=forums&amp;mark_time=' . time()) : '');
487            break;
488
489            case 'newposts':
490                $l_search_title = $user->lang['SEARCH_NEW'];
491                // force sorting
492                $show_results = ($request->variable('sr', 'topics') == 'posts') ? 'posts' : 'topics';
493                $sort_key = 't';
494                $sort_dir = 'd';
495                $sort_by_sql['t'] = ($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time';
496                $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
497
498                gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
499                $s_sort_key = $s_sort_dir = $u_sort_param = $s_limit_days = '';
500
501                if ($show_results == 'posts')
502                {
503                    $sql = 'SELECT p.post_id
504                        FROM ' . POSTS_TABLE . ' p
505                        WHERE p.post_time > ' . $user->data['user_lastvisit'] . '
506                            AND ' . $m_approve_posts_fid_sql . '
507                            ' . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . "
508                        $sql_sort";
509                    $field = 'post_id';
510                }
511                else
512                {
513                    $sql = 'SELECT t.topic_id
514                        FROM ' . TOPICS_TABLE . ' t
515                        WHERE t.topic_last_post_time > ' . $user->data['user_lastvisit'] . '
516                            AND t.topic_moved_id = 0
517                            AND ' . $m_approve_topics_fid_sql . '
518                            ' . ((count($ex_fid_ary)) ? 'AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '') . "
519                        $sql_sort";
520/*
521        [Fix] queued replies missing from "view new posts" (Bug #42705 - Patch by Paul)
522        - Creates temporary table, query is far from optimized
523
524                    $sql = 'SELECT t.topic_id
525                        FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p
526                        WHERE p.post_time > ' . $user->data['user_lastvisit'] . '
527                            AND t.topic_id = p.topic_id
528                            AND t.topic_moved_id = 0
529                            AND ' . $m_approve_topics_fid_sql . "
530                        GROUP BY t.topic_id
531                        $sql_sort";
532*/
533                    $field = 'topic_id';
534                }
535            break;
536
537            case 'egosearch':
538                $l_search_title = $user->lang['SEARCH_SELF'];
539            break;
540        }
541
542        $template->assign_block_vars('navlinks', array(
543            'BREADCRUMB_NAME'    => $l_search_title,
544            'U_BREADCRUMB'        => append_sid("{$phpbb_root_path}search.$phpEx", "search_id=$search_id"),
545        ));
546    }
547
548    /**
549    * Event to modify data after pre-made searches
550    *
551    * @event core.search_modify_param_after
552    * @var    string    l_search_title    The title of the search page
553    * @var    string    search_id        Predefined search type name
554    * @var    string    show_results    Display topics or posts
555    * @var    string    sql                SQL query corresponding to the pre-made search id
556    * @since 3.1.7-RC1
557    */
558    $vars = array(
559        'l_search_title',
560        'search_id',
561        'show_results',
562        'sql',
563    );
564    extract($phpbb_dispatcher->trigger_event('core.search_modify_param_after', compact($vars)));
565
566    // show_results should not change after this
567    $per_page = ($show_results == 'posts') ? (int) $config['posts_per_page'] : (int) $config['topics_per_page'];
568    $total_match_count = 0;
569
570    // Set limit for the $total_match_count to reduce server load
571    $total_matches_limit = 1000;
572    $found_more_search_matches = false;
573
574    if ($search_id)
575    {
576        if ($sql)
577        {
578            // Only return up to $total_matches_limit+1 ids (the last one will be removed later)
579            $result = $db->sql_query_limit($sql, $total_matches_limit + 1);
580
581            while ($row = $db->sql_fetchrow($result))
582            {
583                $id_ary[] = (int) $row[$field];
584            }
585            $db->sql_freeresult($result);
586        }
587        else if ($search_id == 'unreadposts')
588        {
589            // Only return up to $total_matches_limit+1 ids (the last one will be removed later)
590            $id_ary = array_keys(get_unread_topics($user->data['user_id'], $sql_where, $sql_sort, $total_matches_limit + 1));
591        }
592        else
593        {
594            $search_id = '';
595        }
596
597        $total_match_count = count($id_ary);
598        if ($total_match_count)
599        {
600            // Limit the number to $total_matches_limit for pre-made searches
601            if ($total_match_count > $total_matches_limit)
602            {
603                $found_more_search_matches = true;
604                $total_match_count = $total_matches_limit;
605            }
606
607            // Make sure $start is set to the last page if it exceeds the amount
608            $start = $pagination->validate_start($start, $per_page, $total_match_count);
609
610            $id_ary = array_slice($id_ary, $start, $per_page);
611        }
612        else
613        {
614            // Set $start to 0 if no matches were found
615            $start = 0;
616        }
617    }
618
619    // make sure that some arrays are always in the same order
620    sort($ex_fid_ary);
621    sort($author_id_ary);
622
623    if ($search->get_search_query())
624    {
625        $total_match_count = $search->keyword_search($show_results, $search_fields, $search_terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_posts_fid_sql, $topic_id, $author_id_ary, $sql_author_match, $id_ary, $start, $per_page);
626    }
627    else if (count($author_id_ary))
628    {
629        $firstpost_only = ($search_fields === 'firstpost' || $search_fields == 'titleonly') ? true : false;
630        $total_match_count = $search->author_search($show_results, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_posts_fid_sql, $topic_id, $author_id_ary, $sql_author_match, $id_ary, $start, $per_page);
631    }
632
633    /**
634    * Event to search otherwise than by keywords or author
635    *
636    * @event core.search_backend_search_after
637    * @var    string        show_results                'posts' or 'topics' type of ids
638    * @var    string        search_fields                The data fields to search in
639    * @var    string        search_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)
640    * @var    array        sort_by_sql                    Array of SQL sorting instructions
641    * @var    string        sort_key                    The sort key
642    * @var    string        sort_dir                    The sort direction
643    * @var    int            sort_days                    Limit the age of results
644    * @var    array        ex_fid_ary                    Array of excluded forum ids
645    * @var    string        m_approve_posts_fid_sql        Specifies which types of posts the user can view in which forums
646    * @var    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
647    * @var    array        author_id_ary                Array of exclusive author ids
648    * @var    string        sql_author_match            Specifies the author match, when ANONYMOUS is also a search-match
649    * @var    array        id_ary                        Array of post or topic ids for search result
650    * @var    int            start                        The starting id of the results
651    * @var    int            per_page                    Number of ids each page is supposed to contain
652    * @var    int            total_match_count            The total number of search matches
653    * @since 3.1.10-RC1
654    */
655    $vars = array(
656        'show_results',
657        'search_fields',
658        'search_terms',
659        'sort_by_sql',
660        'sort_key',
661        'sort_dir',
662        'sort_days',
663        'ex_fid_ary',
664        'm_approve_posts_fid_sql',
665        'topic_id',
666        'author_id_ary',
667        'sql_author_match',
668        'id_ary',
669        'start',
670        'per_page',
671        'total_match_count',
672    );
673    extract($phpbb_dispatcher->trigger_event('core.search_backend_search_after', compact($vars)));
674
675    $sql_where = '';
676
677    if (count($id_ary))
678    {
679        $sql_where .= $db->sql_in_set(($show_results == 'posts') ? 'p.post_id' : 't.topic_id', $id_ary);
680        $sql_where .= (count($ex_fid_ary)) ? ' AND (' . $db->sql_in_set('f.forum_id', $ex_fid_ary, true) . ' OR f.forum_id IS NULL)' : '';
681        $sql_where .= ' AND ' . (($show_results == 'posts') ? $m_approve_posts_fid_sql : $m_approve_topics_fid_sql);
682    }
683
684    if ($show_results == 'posts')
685    {
686        include($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
687    }
688    else
689    {
690        include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
691    }
692
693    $user->add_lang('viewtopic');
694
695    // Grab icons
696    $icons = $cache->obtain_icons();
697
698    // define some vars for urls
699    // A single wildcard will make the search results look ugly
700    $hilit = phpbb_clean_search_string(str_replace(array('+', '-', '|', '(', ')', '&quot;'), ' ', $keywords));
701    $hilit = str_replace(' ', '|', $hilit);
702
703    $u_hilit = urlencode(html_entity_decode(str_replace('|', ' ', $hilit), ENT_COMPAT));
704    $u_show_results = 'sr=' . $show_results;
705    $u_search_forum = implode('&amp;fid%5B%5D=', $search_forum);
706
707    $u_search = append_sid("{$phpbb_root_path}search.$phpEx", (($u_sort_param) ? $u_sort_param . '&amp;' : '') . $u_show_results);
708    $u_search .= ($search_id) ? '&amp;search_id=' . $search_id : '';
709    $u_search .= ($u_hilit) ? '&amp;keywords=' . urlencode(html_entity_decode($keywords, ENT_COMPAT)) : '';
710    $u_search .= ($search_terms != 'all') ? '&amp;terms=' . $search_terms : '';
711    $u_search .= ($topic_id) ? '&amp;t=' . $topic_id : '';
712    $u_search .= ($author) ? '&amp;author=' . urlencode(html_entity_decode($author, ENT_COMPAT)) : '';
713    $u_search .= ($author_id) ? '&amp;author_id=' . $author_id : '';
714    $u_search .= ($u_search_forum) ? '&amp;fid%5B%5D=' . $u_search_forum : '';
715    $u_search .= (!$search_child) ? '&amp;sc=0' : '';
716    $u_search .= ($search_fields != 'all') ? '&amp;sf=' . $search_fields : '';
717    $u_search .= $return_chars !== (int) $config['default_search_return_chars'] ? '&amp;ch=' . $return_chars : '';
718
719    /**
720    * Event to add or modify search URL parameters
721    *
722    * @event core.search_modify_url_parameters
723    * @var    string    u_search        Search URL parameters string
724    * @var    string    search_id        Predefined search type name
725    * @var    string    show_results    String indicating the show results mode
726    * @var    string    sql_where        The SQL WHERE string used by search to get topic data
727    * @var    int        total_match_count    The total number of search matches
728    * @var    array    ex_fid_ary        Array of excluded forum ids
729    * @since 3.1.7-RC1
730    * @changed 3.1.10-RC1 Added show_results, sql_where, total_match_count
731    * @changed 3.1.11-RC1 Added ex_fid_ary
732    */
733    $vars = array(
734        'u_search',
735        'search_id',
736        'show_results',
737        'sql_where',
738        'total_match_count',
739        'ex_fid_ary',
740    );
741    extract($phpbb_dispatcher->trigger_event('core.search_modify_url_parameters', compact($vars)));
742
743    if ($sql_where)
744    {
745        $zebra = [];
746
747        if ($show_results == 'posts')
748        {
749            // @todo Joining this query to the one below?
750            $sql = 'SELECT zebra_id, friend, foe
751                FROM ' . ZEBRA_TABLE . '
752                WHERE user_id = ' . $user->data['user_id'];
753            $result = $db->sql_query($sql);
754
755            while ($row = $db->sql_fetchrow($result))
756            {
757                $zebra[($row['friend']) ? 'friend' : 'foe'][] = $row['zebra_id'];
758            }
759            $db->sql_freeresult($result);
760
761            $sql_array = array(
762                'SELECT'    => 'p.*, f.forum_id, f.forum_name, t.*, u.username, u.username_clean, u.user_sig, u.user_sig_bbcode_uid, u.user_colour',
763                'FROM'        => array(
764                    POSTS_TABLE        => 'p',
765                ),
766                'LEFT_JOIN' => array(
767                    array(
768                        'FROM'    => array(TOPICS_TABLE => 't'),
769                        'ON'    => 'p.topic_id = t.topic_id',
770                    ),
771                    array(
772                        'FROM'    => array(FORUMS_TABLE => 'f'),
773                        'ON'    => 'p.forum_id = f.forum_id',
774                    ),
775                    array(
776                        'FROM'    => array(USERS_TABLE => 'u'),
777                        'ON'    => 'p.poster_id = u.user_id',
778                    ),
779                ),
780                'WHERE'    => $sql_where,
781                'ORDER_BY' => $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'),
782            );
783
784            /**
785            * Event to modify the SQL query before the posts data is retrieved
786            *
787            * @event core.search_get_posts_data
788            * @var    array    sql_array        The SQL array
789            * @var    array    zebra            Array of zebra data for the current user
790            * @var    int        total_match_count    The total number of search matches
791            * @var    string    keywords        String of the specified keywords
792            * @var    array    sort_by_sql        Array of SQL sorting instructions
793            * @var    string    s_sort_dir        The sort direction
794            * @var    string    s_sort_key        The sort key
795            * @var    string    s_limit_days    Limit the age of results
796            * @var    array    ex_fid_ary        Array of excluded forum ids
797            * @var    array    author_id_ary    Array of exclusive author ids
798            * @var    string    search_fields    The data fields to search in
799            * @var    int        search_id        The id of the search request
800            * @var    int        start            The starting id of the results
801            * @since 3.1.0-b3
802            */
803            $vars = array(
804                'sql_array',
805                'zebra',
806                'total_match_count',
807                'keywords',
808                'sort_by_sql',
809                's_sort_dir',
810                's_sort_key',
811                's_limit_days',
812                'ex_fid_ary',
813                'author_id_ary',
814                'search_fields',
815                'search_id',
816                'start',
817            );
818            extract($phpbb_dispatcher->trigger_event('core.search_get_posts_data', compact($vars)));
819
820            $sql = $db->sql_build_query('SELECT', $sql_array);
821        }
822        else
823        {
824            $sql_from = TOPICS_TABLE . ' t
825                LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = t.forum_id)
826                ' . (($sort_key == 'a') ? ' LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = t.topic_poster) ' : '');
827            $sql_select = 't.*, f.forum_id, f.forum_name';
828
829            if ($user->data['is_registered'])
830            {
831                if ($config['load_db_track'] && $author_id !== $user->data['user_id'])
832                {
833                    $sql_from .= ' LEFT JOIN ' . TOPICS_POSTED_TABLE . ' tp ON (tp.user_id = ' . $user->data['user_id'] . '
834                        AND t.topic_id = tp.topic_id)';
835                    $sql_select .= ', tp.topic_posted';
836                }
837
838                if ($config['load_db_lastread'])
839                {
840                    $sql_from .= ' LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt ON (tt.user_id = ' . $user->data['user_id'] . '
841                            AND t.topic_id = tt.topic_id)
842                        LEFT JOIN ' . FORUMS_TRACK_TABLE . ' ft ON (ft.user_id = ' . $user->data['user_id'] . '
843                            AND ft.forum_id = f.forum_id)';
844                    $sql_select .= ', tt.mark_time, ft.mark_time as f_mark_time';
845                }
846            }
847
848            if ($config['load_anon_lastread'] || ($user->data['is_registered'] && !$config['load_db_lastread']))
849            {
850                $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE);
851                $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array();
852            }
853
854            $sql_order_by = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC');
855
856            /**
857            * Event to modify the SQL query before the topic data is retrieved
858            *
859            * @event core.search_get_topic_data
860            * @var    string    sql_select        The SQL SELECT string used by search to get topic data
861            * @var    string    sql_from        The SQL FROM string used by search to get topic data
862            * @var    string    sql_where        The SQL WHERE string used by search to get topic data
863            * @var    int        total_match_count    The total number of search matches
864            * @var    array    sort_by_sql        Array of SQL sorting instructions
865            * @var    string    sort_dir        The sorting direction
866            * @var    string    sort_key        The sorting key
867            * @var    string    sql_order_by    The SQL ORDER BY string used by search to get topic data
868            * @since 3.1.0-a1
869            * @changed 3.1.0-RC5 Added total_match_count
870            * @changed 3.1.7-RC1 Added sort_by_sql, sort_dir, sort_key, sql_order_by
871            */
872            $vars = array(
873                'sql_select',
874                'sql_from',
875                'sql_where',
876                'total_match_count',
877                'sort_by_sql',
878                'sort_dir',
879                'sort_key',
880                'sql_order_by',
881            );
882            extract($phpbb_dispatcher->trigger_event('core.search_get_topic_data', compact($vars)));
883
884            $sql = "SELECT $sql_select
885                FROM $sql_from
886                WHERE $sql_where
887                ORDER BY $sql_order_by";
888        }
889        $result = $db->sql_query($sql);
890        $result_topic_id = 0;
891
892        $rowset = $attachments = $topic_tracking_info = array();
893
894        if ($show_results == 'topics')
895        {
896            $forums = $rowset = $shadow_topic_list = array();
897            while ($row = $db->sql_fetchrow($result))
898            {
899                $row['forum_id'] = (int) $row['forum_id'];
900                $row['topic_id'] = (int) $row['topic_id'];
901
902                if ($row['topic_status'] == ITEM_MOVED)
903                {
904                    $shadow_topic_list[$row['topic_moved_id']] = $row['topic_id'];
905                }
906
907                $rowset[$row['topic_id']] = $row;
908
909                if (!isset($forums[$row['forum_id']]) && $user->data['is_registered'] && $config['load_db_lastread'])
910                {
911                    $forums[$row['forum_id']]['mark_time'] = $row['f_mark_time'];
912                }
913                $forums[$row['forum_id']]['topic_list'][] = $row['topic_id'];
914                $forums[$row['forum_id']]['rowset'][$row['topic_id']] = &$rowset[$row['topic_id']];
915            }
916            $db->sql_freeresult($result);
917
918            // If we have some shadow topics, update the rowset to reflect their topic information
919            if (count($shadow_topic_list))
920            {
921                $sql = 'SELECT *
922                    FROM ' . TOPICS_TABLE . '
923                    WHERE ' . $db->sql_in_set('topic_id', array_keys($shadow_topic_list));
924                $result = $db->sql_query($sql);
925
926                while ($row = $db->sql_fetchrow($result))
927                {
928                    $orig_topic_id = $shadow_topic_list[$row['topic_id']];
929
930                    // We want to retain some values
931                    $row = array_merge($row, array(
932                        'topic_moved_id'    => $rowset[$orig_topic_id]['topic_moved_id'],
933                        'topic_status'        => $rowset[$orig_topic_id]['topic_status'],
934                        'forum_name'        => $rowset[$orig_topic_id]['forum_name'])
935                    );
936
937                    $rowset[$orig_topic_id] = $row;
938                }
939                $db->sql_freeresult($result);
940            }
941            unset($shadow_topic_list);
942
943            foreach ($forums as $forum_id => $forum)
944            {
945                if ($user->data['is_registered'] && $config['load_db_lastread'])
946                {
947                    $topic_tracking_info[$forum_id] = get_topic_tracking($forum_id, $forum['topic_list'], $forum['rowset'], array($forum_id => $forum['mark_time']));
948                }
949                else if ($config['load_anon_lastread'] || $user->data['is_registered'])
950                {
951                    $topic_tracking_info[$forum_id] = get_complete_topic_tracking($forum_id, $forum['topic_list']);
952
953                    if (!$user->data['is_registered'])
954                    {
955                        $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0;
956                    }
957                }
958            }
959            unset($forums);
960        }
961        else
962        {
963            $text_only_message = '';
964            $attach_list = array();
965
966            while ($row = $db->sql_fetchrow($result))
967            {
968                /**
969                * Modify the row of a post result before the post_text is trimmed
970                *
971                * @event core.search_modify_post_row
972                * @var    string    hilit                    String to highlight
973                * @var    array    row                        Array with the post data
974                * @var    string    u_hilit                    Highlight string to be injected into URL
975                * @var    string    view                    Search results view mode
976                * @var    array    zebra                    Array with zebra data for the current user
977                * @since 3.2.2-RC1
978                */
979                $vars = array(
980                    'hilit',
981                    'row',
982                    'u_hilit',
983                    'view',
984                    'zebra',
985                );
986                extract($phpbb_dispatcher->trigger_event('core.search_modify_post_row', compact($vars)));
987
988                // We pre-process some variables here for later usage
989                $row['post_text'] = censor_text($row['post_text']);
990
991                $text_only_message = $row['post_text'];
992                // make list items visible as such
993                if ($row['bbcode_uid'])
994                {
995                    $text_only_message = str_replace('[*:' . $row['bbcode_uid'] . ']', '&sdot;&nbsp;', $text_only_message);
996                    // no BBCode in text only message
997                    strip_bbcode($text_only_message, $row['bbcode_uid']);
998                }
999
1000                if ($return_chars === 0 || utf8_strlen($text_only_message) < ($return_chars + 3))
1001                {
1002                    $row['display_text_only'] = false;
1003
1004                    // Does this post have an attachment? If so, add it to the list
1005                    if ($row['post_attachment'] && $config['allow_attachments'])
1006                    {
1007                        $attach_list[$row['forum_id']][] = $row['post_id'];
1008                    }
1009                }
1010                else
1011                {
1012                    $row['post_text'] = $text_only_message;
1013                    $row['display_text_only'] = true;
1014                }
1015
1016                $rowset[] = $row;
1017            }
1018            $db->sql_freeresult($result);
1019
1020            unset($text_only_message);
1021
1022            // Pull attachment data
1023            if (count($attach_list))
1024            {
1025                $use_attach_list = $attach_list;
1026                $attach_list = array();
1027
1028                foreach ($use_attach_list as $forum_id => $_list)
1029                {
1030                    if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id))
1031                    {
1032                        $attach_list = array_merge($attach_list, $_list);
1033                    }
1034                }
1035            }
1036
1037            if (count($attach_list))
1038            {
1039                $sql = 'SELECT *
1040                    FROM ' . ATTACHMENTS_TABLE . '
1041                    WHERE ' . $db->sql_in_set('post_msg_id', $attach_list) . '
1042                        AND in_message = 0
1043                    ORDER BY filetime DESC, post_msg_id ASC';
1044                $result = $db->sql_query($sql);
1045
1046                while ($row = $db->sql_fetchrow($result))
1047                {
1048                    $attachments[$row['post_msg_id']][] = $row;
1049                }
1050                $db->sql_freeresult($result);
1051            }
1052        }
1053
1054        if ($hilit)
1055        {
1056            // Remove bad highlights
1057            $hilit_array = array_filter(explode('|', $hilit), 'strlen');
1058            foreach ($hilit_array as $key => $value)
1059            {
1060                $hilit_array[$key] = phpbb_clean_search_string($value);
1061                $hilit_array[$key] = str_replace('\*', '\w*?', preg_quote($hilit_array[$key], '#'));
1062                $hilit_array[$key] = preg_replace('#(^|\s)\\\\w\*\?(\s|$)#', '$1\w+?$2', $hilit_array[$key]);
1063            }
1064            $hilit = implode('|', $hilit_array);
1065        }
1066
1067        /**
1068        * Modify the rowset data
1069        *
1070        * @event core.search_modify_rowset
1071        * @var    array    attachments                Array with posts attachments data
1072        * @var    string    hilit                    String to highlight
1073        * @var    array    rowset                    Array with the search results data
1074        * @var    string    show_results            String indicating the show results mode
1075        * @var    array    topic_tracking_info        Array with the topics tracking data
1076        * @var    string    u_hilit                    Highlight string to be injected into URL
1077        * @var    string    view                    Search results view mode
1078        * @var    array    zebra                    Array with zebra data for the current user
1079        * @since 3.1.0-b4
1080        * @changed 3.1.0-b5 Added var show_results
1081        */
1082        $vars = array(
1083            'attachments',
1084            'hilit',
1085            'rowset',
1086            'show_results',
1087            'topic_tracking_info',
1088            'u_hilit',
1089            'view',
1090            'zebra',
1091        );
1092        extract($phpbb_dispatcher->trigger_event('core.search_modify_rowset', compact($vars)));
1093
1094        foreach ($rowset as $row)
1095        {
1096            $forum_id = $row['forum_id'];
1097            $result_topic_id = $row['topic_id'];
1098            $topic_title = censor_text($row['topic_title']);
1099            $replies = $phpbb_content_visibility->get_count('topic_posts', $row, $forum_id) - 1;
1100
1101            $view_topic_url_params = "t=$result_topic_id" . (($u_hilit) ? "&amp;hilit=$u_hilit" : '');
1102            $view_topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params);
1103
1104            $folder_img = $folder_alt = $u_mcp_queue = '';
1105            $topic_type = $posts_unapproved = 0;
1106            $unread_topic = $topic_unapproved = $topic_deleted = false;
1107
1108            if ($show_results == 'topics')
1109            {
1110                if ($config['load_db_track'] && $author_id === $user->data['user_id'])
1111                {
1112                    $row['topic_posted'] = 1;
1113                }
1114
1115                topic_status($row, $replies, (isset($topic_tracking_info[$forum_id][$row['topic_id']]) && $row['topic_last_post_time'] > $topic_tracking_info[$forum_id][$row['topic_id']]) ? true : false, $folder_img, $folder_alt, $topic_type);
1116
1117                $unread_topic = (isset($topic_tracking_info[$forum_id][$row['topic_id']]) && $row['topic_last_post_time'] > $topic_tracking_info[$forum_id][$row['topic_id']]) ? true : false;
1118
1119                $topic_unapproved = (($row['topic_visibility'] == ITEM_UNAPPROVED || $row['topic_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $forum_id)) ? true : false;
1120                $posts_unapproved = ($row['topic_visibility'] == ITEM_APPROVED && $row['topic_posts_unapproved'] && $auth->acl_get('m_approve', $forum_id)) ? true : false;
1121                $topic_deleted = $row['topic_visibility'] == ITEM_DELETED;
1122                $u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&amp;mode=' . (($topic_unapproved) ? 'approve_details' : 'unapproved_posts') . "&amp;t=$result_topic_id") : '';
1123                $u_mcp_queue = (!$u_mcp_queue && $topic_deleted) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&amp;mode=deleted_topics&amp;t=$result_topic_id") : $u_mcp_queue;
1124
1125                $row['topic_title'] = preg_replace('#(?!<.*)(?<!\w)(' . $hilit . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#isu', '<span class="posthilit">$1</span>', $row['topic_title']);
1126
1127                $tpl_ary = array(
1128                    'TOPIC_AUTHOR'                => get_username_string('username', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
1129                    'TOPIC_AUTHOR_COLOUR'        => get_username_string('colour', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
1130                    'TOPIC_AUTHOR_FULL'            => get_username_string('full', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
1131                    'FIRST_POST_TIME'            => $user->format_date($row['topic_time']),
1132                    'FIRST_POST_TIME_RFC3339'    => gmdate(DATE_RFC3339, $row['topic_time']),
1133                    'LAST_POST_SUBJECT'            => $row['topic_last_post_subject'],
1134                    'LAST_POST_TIME'            => $user->format_date($row['topic_last_post_time']),
1135                    'LAST_POST_TIME_RFC3339'    => gmdate(DATE_RFC3339, $row['topic_last_post_time']),
1136                    'LAST_VIEW_TIME'            => $user->format_date($row['topic_last_view_time']),
1137                    'LAST_VIEW_TIME_RFC3339'    => gmdate(DATE_RFC3339, $row['topic_last_view_time']),
1138                    'LAST_POST_AUTHOR'            => get_username_string('username', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
1139                    'LAST_POST_AUTHOR_COLOUR'    => get_username_string('colour', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
1140                    'LAST_POST_AUTHOR_FULL'        => get_username_string('full', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
1141
1142                    'TOPIC_TYPE'        => $topic_type,
1143
1144                    'TOPIC_IMG_STYLE'        => $folder_img,
1145                    'TOPIC_FOLDER_IMG'        => $user->img($folder_img, $folder_alt),
1146                    'TOPIC_FOLDER_IMG_ALT'    => $user->lang[$folder_alt],
1147                    'S_POST_ANNOUNCE'        => $row['topic_type'] == POST_ANNOUNCE,
1148                    'S_POST_GLOBAL'            => $row['topic_type'] == POST_GLOBAL,
1149                    'S_POST_STICKY'            => $row['topic_type'] == POST_STICKY,
1150                    'S_TOPIC_LOCKED'        => $row['topic_status'] == ITEM_LOCKED,
1151                    'S_TOPIC_MOVED'            => $row['topic_status'] == ITEM_MOVED,
1152
1153                    'TOPIC_ICON_IMG'        => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['img'] : '',
1154                    'TOPIC_ICON_IMG_WIDTH'    => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['width'] : '',
1155                    'TOPIC_ICON_IMG_HEIGHT'    => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['height'] : '',
1156                    'ATTACH_ICON_IMG'        => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id) && $row['topic_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '',
1157                    'UNAPPROVED_IMG'        => ($topic_unapproved || $posts_unapproved) ? $user->img('icon_topic_unapproved', ($topic_unapproved) ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '',
1158
1159                    'S_TOPIC_TYPE'            => $row['topic_type'],
1160                    'S_USER_POSTED'            => !empty($row['topic_posted']),
1161                    'S_UNREAD_TOPIC'        => $unread_topic,
1162
1163                    'S_TOPIC_REPORTED'        => !empty($row['topic_reported']) && $auth->acl_get('m_report', $forum_id),
1164                    'S_TOPIC_UNAPPROVED'    => $topic_unapproved,
1165                    'S_POSTS_UNAPPROVED'    => $posts_unapproved,
1166                    'S_TOPIC_DELETED'        => $topic_deleted,
1167                    'S_HAS_POLL'            => (bool) $row['poll_start'],
1168
1169                    'U_LAST_POST'            => $auth->acl_get('f_read', $forum_id) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['topic_last_post_id']) . '#p' . $row['topic_last_post_id'] : false,
1170                    'U_LAST_POST_AUTHOR'    => get_username_string('profile', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
1171                    'U_TOPIC_AUTHOR'        => get_username_string('profile', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
1172                    'U_NEWEST_POST'            => $auth->acl_get('f_read', $forum_id) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&amp;view=unread') . '#unread' : false,
1173                    'U_MCP_REPORT'            => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&amp;mode=reports&amp;t=' . $result_topic_id),
1174                    'U_MCP_QUEUE'            => $u_mcp_queue,
1175                );
1176            }
1177            else
1178            {
1179                if ((isset($zebra['foe']) && in_array($row['poster_id'], $zebra['foe'])) && (!$view || $view != 'show' || $post_id != $row['post_id']))
1180                {
1181                    $template->assign_block_vars('searchresults', array(
1182                        'S_IGNORE_POST' => true,
1183
1184                        'L_IGNORE_POST' => sprintf($user->lang['POST_BY_FOE'], $row['username'], "<a href=\"$u_search&amp;start=$start&amp;p=" . $row['post_id'] . '&amp;view=show#p' . $row['post_id'] . '">', '</a>'))
1185                    );
1186
1187                    continue;
1188                }
1189
1190                // Replace naughty words such as farty pants
1191                $row['post_subject'] = censor_text($row['post_subject']);
1192
1193                if ($row['display_text_only'])
1194                {
1195                    // now find context for the searched words
1196                    $row['post_text'] = get_context($row['post_text'], array_filter(explode('|', $hilit), 'strlen'), $return_chars);
1197                    $row['post_text'] = bbcode_nl2br($row['post_text']);
1198                }
1199                else
1200                {
1201                    $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
1202                    $row['post_text'] = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false);
1203
1204                    if (!empty($attachments[$row['post_id']]))
1205                    {
1206                        parse_attachments($forum_id, $row['post_text'], $attachments[$row['post_id']], $update_count);
1207
1208                        // we only display inline attachments
1209                        unset($attachments[$row['post_id']]);
1210                    }
1211                }
1212
1213                if ($hilit)
1214                {
1215                    // post highlighting
1216                    $row['post_text'] = preg_replace('#(?!<.*)(?<!\w)(' . $hilit . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#isu', '<span class="posthilit">$1</span>', $row['post_text']);
1217                    $row['post_subject'] = preg_replace('#(?!<.*)(?<!\w)(' . $hilit . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#isu', '<span class="posthilit">$1</span>', $row['post_subject']);
1218                }
1219
1220                $tpl_ary = array(
1221                    'POST_AUTHOR_FULL'        => get_username_string('full', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
1222                    'POST_AUTHOR_COLOUR'    => get_username_string('colour', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
1223                    'POST_AUTHOR'            => get_username_string('username', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
1224                    'U_POST_AUTHOR'            => get_username_string('profile', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
1225
1226                    'POST_SUBJECT'        => $row['post_subject'],
1227                    'POST_DATE'            => (!empty($row['post_time'])) ? $user->format_date($row['post_time']) : '',
1228                    'MESSAGE'            => $row['post_text']
1229                );
1230            }
1231
1232            $tpl_ary = array_merge($tpl_ary, array(
1233                'FORUM_ID'            => $forum_id,
1234                'TOPIC_ID'            => $result_topic_id,
1235                'POST_ID'            => ($show_results == 'posts') ? $row['post_id'] : false,
1236
1237                'FORUM_TITLE'        => $row['forum_name'],
1238                'TOPIC_TITLE'        => $topic_title,
1239                'TOPIC_REPLIES'        => $replies,
1240                'TOPIC_VIEWS'        => $row['topic_views'],
1241
1242                'U_VIEW_TOPIC'        => $auth->acl_get('f_read', $forum_id) ? $view_topic_url : false,
1243                'U_VIEW_FORUM'        => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id),
1244                'U_VIEW_POST'        => (!empty($row['post_id'])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id'] . (($u_hilit) ? '&amp;hilit=' . $u_hilit : '')) . '#p' . $row['post_id'] : '',
1245            ));
1246
1247            /**
1248            * Modify the topic data before it is assigned to the template
1249            *
1250            * @event core.search_modify_tpl_ary
1251            * @var    array    row                Array with topic data
1252            * @var    array    tpl_ary            Template block array with topic data
1253            * @var    string    show_results    Display topics or posts
1254            * @var    string    topic_title        Cleaned topic title
1255            * @var    int        replies            The number of topic replies
1256            * @var    string    view_topic_url    The URL to the topic
1257            * @var    string    folder_img        The folder image of the topic
1258            * @var    string    folder_alt        The alt attribute of the topic folder img
1259            * @var    int        topic_type        The topic type
1260            * @var    bool    unread_topic    Whether the topic has unread posts
1261            * @var    bool    topic_unapproved    Whether the topic is unapproved
1262            * @var    int        posts_unapproved    The number of unapproved posts
1263            * @var    bool    topic_deleted    Whether the topic has been deleted
1264            * @var    string    u_mcp_queue        The URL to the corresponding MCP queue page
1265            * @var    array    zebra            The zebra data of the current user
1266            * @var    array    attachments        All the attachments of the search results
1267            * @since 3.1.0-a1
1268            * @changed 3.1.0-b3 Added vars show_results, topic_title, replies,
1269            *        view_topic_url, folder_img, folder_alt, topic_type, unread_topic,
1270            *        topic_unapproved, posts_unapproved, topic_deleted, u_mcp_queue,
1271            *        zebra, attachments
1272            */
1273            $vars = array(
1274                'row',
1275                'tpl_ary',
1276                'show_results',
1277                'topic_title',
1278                'replies',
1279                'view_topic_url',
1280                'folder_img',
1281                'folder_alt',
1282                'topic_type',
1283                'unread_topic',
1284                'topic_unapproved',
1285                'posts_unapproved',
1286                'topic_deleted',
1287                'u_mcp_queue',
1288                'zebra',
1289                'attachments',
1290            );
1291            extract($phpbb_dispatcher->trigger_event('core.search_modify_tpl_ary', compact($vars)));
1292
1293            $template->assign_block_vars('searchresults', $tpl_ary);
1294
1295            if ($show_results == 'topics')
1296            {
1297                $pagination->generate_template_pagination($view_topic_url, 'searchresults.pagination', 'start', $replies + 1, $config['posts_per_page'], 1, true, true);
1298            }
1299        }
1300
1301        if ($topic_id && ($topic_id == $result_topic_id))
1302        {
1303            $template->assign_vars(array(
1304                'SEARCH_TOPIC'        => $topic_title,
1305                'L_RETURN_TO_TOPIC'    => $user->lang('RETURN_TO', $topic_title),
1306                'U_SEARCH_TOPIC'    => $view_topic_url
1307            ));
1308        }
1309    }
1310    unset($rowset);
1311
1312    // Output header
1313    if ($found_more_search_matches)
1314    {
1315        $l_search_matches = $user->lang('FOUND_MORE_SEARCH_MATCHES', (int) $total_match_count);
1316    }
1317    else
1318    {
1319        $l_search_matches = $user->lang('FOUND_SEARCH_MATCHES', (int) $total_match_count);
1320    }
1321
1322    // Check if search backend supports phrase search or not
1323    $phrase_search_disabled = '';
1324    if (strpos(html_entity_decode($keywords), '"') !== false)
1325    {
1326        $phrase_search_disabled = $search->supports_phrase_search() ? false : true;
1327    }
1328
1329    $pagination->generate_template_pagination($u_search, 'pagination', 'start', $total_match_count, $per_page, $start);
1330
1331    $template->assign_vars(array(
1332        'SEARCH_TITLE'        => $l_search_title,
1333        'SEARCH_MATCHES'    => $l_search_matches,
1334        'SEARCH_WORDS'        => $keywords,
1335        'SEARCHED_QUERY'    => $search->get_search_query(),
1336        'IGNORED_WORDS'        => (!empty($common_words)) ? implode(' ', $common_words) : '',
1337
1338        'PHRASE_SEARCH_DISABLED'        => $phrase_search_disabled,
1339
1340        'TOTAL_MATCHES'        => $total_match_count,
1341        'SEARCH_IN_RESULTS'    => ($search_id) ? false : true,
1342
1343        'S_SELECT_SORT_DIR'        => $s_sort_dir,
1344        'S_SELECT_SORT_KEY'        => $s_sort_key,
1345        'S_SELECT_SORT_DAYS'    => $s_limit_days,
1346        'S_SEARCH_ACTION'        => $u_search,
1347        'S_SHOW_TOPICS'            => ($show_results == 'posts') ? false : true,
1348
1349        'GOTO_PAGE_IMG'        => $user->img('icon_post_target', 'GOTO_PAGE'),
1350        'NEWEST_POST_IMG'    => $user->img('icon_topic_newest', 'VIEW_NEWEST_POST'),
1351        'REPORTED_IMG'        => $user->img('icon_topic_reported', 'TOPIC_REPORTED'),
1352        'UNAPPROVED_IMG'    => $user->img('icon_topic_unapproved', 'TOPIC_UNAPPROVED'),
1353        'DELETED_IMG'        => $user->img('icon_topic_deleted', 'TOPIC_DELETED'),
1354        'POLL_IMG'            => $user->img('icon_topic_poll', 'TOPIC_POLL'),
1355        'LAST_POST_IMG'        => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'),
1356
1357        'U_SEARCH_WORDS'    => $u_search,
1358    ));
1359
1360    /**
1361    * Modify the title and/or load data for the search results page
1362    *
1363    * @event core.search_results_modify_search_title
1364    * @var    int        author_id            ID of the author to search by
1365    * @var    string    l_search_title        The title of the search page
1366    * @var    string    search_id            Predefined search type name
1367    * @var    string    show_results        Search results output mode - topics or posts
1368    * @var    int        start                The starting id of the results
1369    * @var    int        total_match_count    The count of search results
1370    * @var    string    keywords            The search keywords
1371    * @since 3.1.0-RC4
1372    * @changed 3.1.6-RC1 Added total_match_count and keywords
1373    */
1374    $vars = array(
1375        'author_id',
1376        'l_search_title',
1377        'search_id',
1378        'show_results',
1379        'start',
1380        'total_match_count',
1381        'keywords',
1382    );
1383    extract($phpbb_dispatcher->trigger_event('core.search_results_modify_search_title', compact($vars)));
1384
1385    page_header(($l_search_title) ? $l_search_title : $user->lang['SEARCH']);
1386
1387    $template->set_filenames(array(
1388        'body' => 'search_results.html')
1389    );
1390    make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"));
1391
1392    page_footer();
1393}
1394
1395// Search forum
1396$rowset = array();
1397$s_forums = '';
1398$sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.left_id, f.right_id, f.forum_password, f.enable_indexing, fa.user_id
1399    FROM ' . FORUMS_TABLE . ' f
1400    LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa ON (fa.forum_id = f.forum_id
1401        AND fa.session_id = '" . $db->sql_escape($user->session_id) . "')
1402    ORDER BY f.left_id ASC";
1403$result = $db->sql_query($sql);
1404
1405while ($row = $db->sql_fetchrow($result))
1406{
1407    $rowset[(int) $row['forum_id']] = $row;
1408}
1409$db->sql_freeresult($result);
1410
1411$right = $cat_right = $padding_inc = 0;
1412$padding = $forum_list = $holding = '';
1413$pad_store = array('0' => '');
1414
1415/**
1416* Modify the forum select list for advanced search page
1417*
1418* @event core.search_modify_forum_select_list
1419* @var    array    rowset    Array with the forums list data
1420* @since 3.1.10-RC1
1421*/
1422$vars = array('rowset');
1423extract($phpbb_dispatcher->trigger_event('core.search_modify_forum_select_list', compact($vars)));
1424
1425foreach ($rowset as $row)
1426{
1427    if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id']))
1428    {
1429        // Non-postable forum with no subforums, don't display
1430        continue;
1431    }
1432
1433    if ($row['forum_type'] == FORUM_POST && ($row['left_id'] + 1 == $row['right_id']) && !$row['enable_indexing'])
1434    {
1435        // Postable forum with no subforums and indexing disabled, don't display
1436        continue;
1437    }
1438
1439    if ($row['forum_type'] == FORUM_LINK || ($row['forum_password'] && !$row['user_id']))
1440    {
1441        // if this forum is a link or password protected (user has not entered the password yet) then skip to the next branch
1442        continue;
1443    }
1444
1445    if ($row['left_id'] < $right)
1446    {
1447        $padding .= '&nbsp; &nbsp;';
1448        $pad_store[$row['parent_id']] = $padding;
1449    }
1450    else if ($row['left_id'] > $right + 1)
1451    {
1452        if (isset($pad_store[$row['parent_id']]))
1453        {
1454            $padding = $pad_store[$row['parent_id']];
1455        }
1456        else
1457        {
1458            continue;
1459        }
1460    }
1461
1462    $right = $row['right_id'];
1463
1464    if ($auth->acl_gets('!f_search', '!f_list', $row['forum_id']))
1465    {
1466        // if the user does not have permissions to search or see this forum skip only this forum/category
1467        continue;
1468    }
1469
1470    $selected = (in_array($row['forum_id'], $search_forum)) ? ' selected="selected"' : '';
1471
1472    if ($row['left_id'] > $cat_right)
1473    {
1474        // make sure we don't forget anything
1475        $s_forums .= $holding;
1476        $holding = '';
1477    }
1478
1479    if ($row['right_id'] - $row['left_id'] > 1)
1480    {
1481        $cat_right = max($cat_right, $row['right_id']);
1482
1483        $holding .= '<option value="' . $row['forum_id'] . '"' . $selected . '>' . $padding . $row['forum_name'] . '</option>';
1484    }
1485    else
1486    {
1487        $s_forums .= $holding . '<option value="' . $row['forum_id'] . '"' . $selected . '>' . $padding . $row['forum_name'] . '</option>';
1488        $holding = '';
1489    }
1490}
1491
1492if ($holding)
1493{
1494    $s_forums .= $holding;
1495}
1496
1497unset($pad_store);
1498unset($rowset);
1499
1500if (!$s_forums)
1501{
1502    trigger_error('NO_SEARCH');
1503}
1504
1505/**
1506 * Build options for a select list for the number of characters returned.
1507 *
1508 * If the admin defined amount is not within the predefined range,
1509 * and the admin did not set it to unlimited (0), we add that option aswell.
1510 *
1511 * @deprecated 3.3.1-RC1    Templates should use an numeric input, in favor of a select.
1512 */
1513$s_characters = '<option value="0">' . $language->lang('ALL_AVAILABLE') . '</option>';
1514$i_characters = array_merge([25, 50], range(100, 1000, 100));
1515
1516if ($config['default_search_return_chars'] && !in_array((int) $config['default_search_return_chars'], $i_characters))
1517{
1518    $i_characters[] = (int) $config['default_search_return_chars'];
1519    sort($i_characters);
1520}
1521
1522foreach ($i_characters as $i)
1523{
1524    $selected = $i === (int) $config['default_search_return_chars'] ? ' selected="selected"' : '';
1525    $s_characters .= sprintf('<option value="%1$s"%2$s>%1$s</option>', $i, $selected);
1526}
1527
1528$s_hidden_fields = array('t' => $topic_id);
1529
1530if ($_SID)
1531{
1532    $s_hidden_fields['sid'] = $_SID;
1533}
1534
1535if (!empty($_EXTRA_URL))
1536{
1537    foreach ($_EXTRA_URL as $url_param)
1538    {
1539        $url_param = explode('=', $url_param, 2);
1540        $s_hidden_fields[$url_param[0]] = $url_param[1];
1541    }
1542}
1543
1544$template->assign_vars(array(
1545    'DEFAULT_RETURN_CHARS'    => (int) $config['default_search_return_chars'],
1546    'S_SEARCH_ACTION'        => append_sid("{$phpbb_root_path}search.$phpEx", false, true, 0), // We force no ?sid= appending by using 0
1547    'S_HIDDEN_FIELDS'        => build_hidden_fields($s_hidden_fields),
1548    'S_CHARACTER_OPTIONS'    => $s_characters,
1549    'S_FORUM_OPTIONS'        => $s_forums,
1550    'S_SELECT_SORT_DIR'        => $s_sort_dir,
1551    'S_SELECT_SORT_KEY'        => $s_sort_key,
1552    'S_SELECT_SORT_DAYS'    => $s_limit_days,
1553    'S_IN_SEARCH'            => true,
1554));
1555
1556// only show recent searches to search administrators
1557if ($auth->acl_get('a_search'))
1558{
1559    // Handle large objects differently for Oracle and MSSQL
1560    switch ($db->get_sql_layer())
1561    {
1562        case 'oracle':
1563            $sql = 'SELECT search_time, search_keywords
1564                FROM ' . SEARCH_RESULTS_TABLE . '
1565                WHERE dbms_lob.getlength(search_keywords) > 0
1566                ORDER BY search_time DESC';
1567        break;
1568
1569        case 'mssql_odbc':
1570        case 'mssqlnative':
1571            $sql = 'SELECT search_time, search_keywords
1572                FROM ' . SEARCH_RESULTS_TABLE . '
1573                WHERE DATALENGTH(search_keywords) > 0
1574                ORDER BY search_time DESC';
1575        break;
1576
1577        default:
1578            $sql = 'SELECT search_time, search_keywords
1579                FROM ' . SEARCH_RESULTS_TABLE . '
1580                WHERE search_keywords <> \'\'
1581                ORDER BY search_time DESC';
1582        break;
1583    }
1584    $result = $db->sql_query_limit($sql, 5);
1585
1586    while ($row = $db->sql_fetchrow($result))
1587    {
1588        $keywords = $row['search_keywords'];
1589
1590        $template->assign_block_vars('recentsearch', array(
1591            'KEYWORDS'    => $keywords,
1592            'TIME'        => $user->format_date($row['search_time']),
1593
1594            'U_KEYWORDS'    => append_sid("{$phpbb_root_path}search.$phpEx", 'keywords=' . urlencode(html_entity_decode($keywords, ENT_COMPAT)))
1595        ));
1596    }
1597    $db->sql_freeresult($result);
1598}
1599
1600// Output the basic page
1601page_header($user->lang['SEARCH']);
1602
1603$template->set_filenames(array(
1604    'body' => 'search_body.html')
1605);
1606make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"));
1607
1608page_footer();