PageRenderTime 63ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/phpBB/search.php

https://github.com/Jipem/phpbb
PHP | 1345 lines | 1092 code | 133 blank | 120 comment | 184 complexity | f53723204ad94709316f82283df40eef MD5 | raw file
Possible License(s): AGPL-1.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. * @ignore
  15. */
  16. define('IN_PHPBB', true);
  17. $phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './';
  18. $phpEx = substr(strrchr(__FILE__, '.'), 1);
  19. include($phpbb_root_path . 'common.' . $phpEx);
  20. // Start session management
  21. $user->session_begin();
  22. $auth->acl($user->data);
  23. $user->setup('search');
  24. // Define initial vars
  25. $mode = request_var('mode', '');
  26. $search_id = request_var('search_id', '');
  27. $start = max(request_var('start', 0), 0);
  28. $post_id = request_var('p', 0);
  29. $topic_id = request_var('t', 0);
  30. $view = request_var('view', '');
  31. $submit = request_var('submit', false);
  32. $keywords = utf8_normalize_nfc(request_var('keywords', '', true));
  33. $add_keywords = utf8_normalize_nfc(request_var('add_keywords', '', true));
  34. $author = request_var('author', '', true);
  35. $author_id = request_var('author_id', 0);
  36. $show_results = ($topic_id) ? 'posts' : request_var('sr', 'posts');
  37. $show_results = ($show_results == 'posts') ? 'posts' : 'topics';
  38. $search_terms = request_var('terms', 'all');
  39. $search_fields = request_var('sf', 'all');
  40. $search_child = request_var('sc', true);
  41. $sort_days = request_var('st', 0);
  42. $sort_key = request_var('sk', 't');
  43. $sort_dir = request_var('sd', 'd');
  44. $return_chars = request_var('ch', ($topic_id) ? -1 : 300);
  45. $search_forum = request_var('fid', array(0));
  46. // We put login boxes for the case if search_id is newposts, egosearch or unreadposts
  47. // because a guest should be able to log in even if guests search is not permitted
  48. switch ($search_id)
  49. {
  50. // Egosearch is an author search
  51. case 'egosearch':
  52. $author_id = $user->data['user_id'];
  53. if ($user->data['user_id'] == ANONYMOUS)
  54. {
  55. login_box('', $user->lang['LOGIN_EXPLAIN_EGOSEARCH']);
  56. }
  57. break;
  58. // Search for unread posts needs to be allowed and user to be logged in if topics tracking for guests is disabled
  59. case 'unreadposts':
  60. if (!$config['load_unreads_search'])
  61. {
  62. $template->assign_var('S_NO_SEARCH', true);
  63. trigger_error('NO_SEARCH_UNREADS');
  64. }
  65. else if (!$config['load_anon_lastread'] && !$user->data['is_registered'])
  66. {
  67. login_box('', $user->lang['LOGIN_EXPLAIN_UNREADSEARCH']);
  68. }
  69. break;
  70. // The "new posts" search uses user_lastvisit which is user based, so it should require user to log in.
  71. case 'newposts':
  72. if ($user->data['user_id'] == ANONYMOUS)
  73. {
  74. login_box('', $user->lang['LOGIN_EXPLAIN_NEWPOSTS']);
  75. }
  76. break;
  77. default:
  78. // There's nothing to do here for now ;)
  79. break;
  80. }
  81. // Is user able to search? Has search been disabled?
  82. if (!$auth->acl_get('u_search') || !$auth->acl_getf_global('f_search') || !$config['load_search'])
  83. {
  84. $template->assign_var('S_NO_SEARCH', true);
  85. trigger_error('NO_SEARCH');
  86. }
  87. // Check search load limit
  88. if ($user->load && $config['limit_search_load'] && ($user->load > doubleval($config['limit_search_load'])))
  89. {
  90. $template->assign_var('S_NO_SEARCH', true);
  91. trigger_error('NO_SEARCH_TIME');
  92. }
  93. // It is applicable if the configuration setting is non-zero, and the user cannot
  94. // ignore the flood setting, and the search is a keyword search.
  95. $interval = ($user->data['user_id'] == ANONYMOUS) ? $config['search_anonymous_interval'] : $config['search_interval'];
  96. if ($interval && !in_array($search_id, array('unreadposts', 'unanswered', 'active_topics', 'egosearch')) && !$auth->acl_get('u_ignoreflood'))
  97. {
  98. if ($user->data['user_last_search'] > time() - $interval)
  99. {
  100. $template->assign_var('S_NO_SEARCH', true);
  101. trigger_error($user->lang('NO_SEARCH_TIME', (int) ($user->data['user_last_search'] + $interval - time())));
  102. }
  103. }
  104. // Define some vars
  105. $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']);
  106. $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']);
  107. $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
  108. 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);
  109. $phpbb_content_visibility = $phpbb_container->get('content.visibility');
  110. $pagination = $phpbb_container->get('pagination');
  111. if ($keywords || $author || $author_id || $search_id || $submit)
  112. {
  113. // clear arrays
  114. $id_ary = array();
  115. // If we are looking for authors get their ids
  116. $author_id_ary = array();
  117. $sql_author_match = '';
  118. if ($author_id)
  119. {
  120. $author_id_ary[] = $author_id;
  121. }
  122. else if ($author)
  123. {
  124. if ((strpos($author, '*') !== false) && (utf8_strlen(str_replace(array('*', '%'), '', $author)) < $config['min_search_author_chars']))
  125. {
  126. trigger_error($user->lang('TOO_FEW_AUTHOR_CHARS', (int) $config['min_search_author_chars']));
  127. }
  128. $sql_where = (strpos($author, '*') !== false) ? ' username_clean ' . $db->sql_like_expression(str_replace('*', $db->any_char, utf8_clean_string($author))) : " username_clean = '" . $db->sql_escape(utf8_clean_string($author)) . "'";
  129. $sql = 'SELECT user_id
  130. FROM ' . USERS_TABLE . "
  131. WHERE $sql_where
  132. AND user_type <> " . USER_IGNORE;
  133. $result = $db->sql_query_limit($sql, 100);
  134. while ($row = $db->sql_fetchrow($result))
  135. {
  136. $author_id_ary[] = (int) $row['user_id'];
  137. }
  138. $db->sql_freeresult($result);
  139. $sql_where = (strpos($author, '*') !== false) ? ' post_username ' . $db->sql_like_expression(str_replace('*', $db->any_char, utf8_clean_string($author))) : " post_username = '" . $db->sql_escape(utf8_clean_string($author)) . "'";
  140. $sql = 'SELECT 1 as guest_post
  141. FROM ' . POSTS_TABLE . "
  142. WHERE $sql_where
  143. AND poster_id = " . ANONYMOUS;
  144. $result = $db->sql_query_limit($sql, 1);
  145. $found_guest_post = $db->sql_fetchfield('guest_post');
  146. $db->sql_freeresult($result);
  147. if ($found_guest_post)
  148. {
  149. $author_id_ary[] = ANONYMOUS;
  150. $sql_author_match = (strpos($author, '*') !== false) ? ' ' . $db->sql_like_expression(str_replace('*', $db->any_char, utf8_clean_string($author))) : " = '" . $db->sql_escape(utf8_clean_string($author)) . "'";
  151. }
  152. if (!sizeof($author_id_ary))
  153. {
  154. trigger_error('NO_SEARCH_RESULTS');
  155. }
  156. }
  157. // if we search in an existing search result just add the additional keywords. But we need to use "all search terms"-mode
  158. // so we can keep the old keywords in their old mode, but add the new ones as required words
  159. if ($add_keywords)
  160. {
  161. if ($search_terms == 'all')
  162. {
  163. $keywords .= ' ' . $add_keywords;
  164. }
  165. else
  166. {
  167. $search_terms = 'all';
  168. $keywords = implode(' |', explode(' ', preg_replace('#\s+#u', ' ', $keywords))) . ' ' .$add_keywords;
  169. }
  170. }
  171. // Which forums should not be searched? Author searches are also carried out in unindexed forums
  172. if (empty($keywords) && sizeof($author_id_ary))
  173. {
  174. $ex_fid_ary = array_keys($auth->acl_getf('!f_read', true));
  175. }
  176. else
  177. {
  178. $ex_fid_ary = array_unique(array_merge(array_keys($auth->acl_getf('!f_read', true)), array_keys($auth->acl_getf('!f_search', true))));
  179. }
  180. $not_in_fid = (sizeof($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'] . ')' : "";
  181. $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
  182. FROM ' . FORUMS_TABLE . ' f
  183. LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa ON (fa.forum_id = f.forum_id
  184. AND fa.session_id = '" . $db->sql_escape($user->session_id) . "')
  185. $not_in_fid
  186. ORDER BY f.left_id";
  187. $result = $db->sql_query($sql);
  188. $right_id = 0;
  189. $reset_search_forum = true;
  190. while ($row = $db->sql_fetchrow($result))
  191. {
  192. if ($row['forum_password'] && $row['user_id'] != $user->data['user_id'])
  193. {
  194. $ex_fid_ary[] = (int) $row['forum_id'];
  195. continue;
  196. }
  197. // Exclude forums from active topics
  198. if (!($row['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) && ($search_id == 'active_topics'))
  199. {
  200. $ex_fid_ary[] = (int) $row['forum_id'];
  201. continue;
  202. }
  203. if (sizeof($search_forum))
  204. {
  205. if ($search_child)
  206. {
  207. if (in_array($row['forum_id'], $search_forum) && $row['right_id'] > $right_id)
  208. {
  209. $right_id = (int) $row['right_id'];
  210. }
  211. else if ($row['right_id'] < $right_id)
  212. {
  213. continue;
  214. }
  215. }
  216. if (!in_array($row['forum_id'], $search_forum))
  217. {
  218. $ex_fid_ary[] = (int) $row['forum_id'];
  219. $reset_search_forum = false;
  220. }
  221. }
  222. }
  223. $db->sql_freeresult($result);
  224. // find out in which forums the user is allowed to view posts
  225. $m_approve_posts_fid_sql = $phpbb_content_visibility->get_global_visibility_sql('post', $ex_fid_ary, 'p.');
  226. $m_approve_topics_fid_sql = $phpbb_content_visibility->get_global_visibility_sql('topic', $ex_fid_ary, 't.');
  227. if ($reset_search_forum)
  228. {
  229. $search_forum = array();
  230. }
  231. // Select which method we'll use to obtain the post_id or topic_id information
  232. $search_type = $config['search_type'];
  233. if (!class_exists($search_type))
  234. {
  235. trigger_error('NO_SUCH_SEARCH_MODULE');
  236. }
  237. // We do some additional checks in the module to ensure it can actually be utilised
  238. $error = false;
  239. $search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user);
  240. if ($error)
  241. {
  242. trigger_error($error);
  243. }
  244. $common_words = $search->get_common_words();
  245. // let the search module split up the keywords
  246. if ($keywords)
  247. {
  248. $correct_query = $search->split_keywords($keywords, $search_terms);
  249. if (!$correct_query || (!$search->get_search_query() && !sizeof($author_id_ary) && !$search_id))
  250. {
  251. $ignored = (sizeof($common_words)) ? sprintf($user->lang['IGNORED_TERMS_EXPLAIN'], implode(' ', $common_words)) . '<br />' : '';
  252. $word_length = $search->get_word_length();
  253. if ($word_length)
  254. {
  255. trigger_error($ignored . $user->lang('NO_KEYWORDS', $user->lang('CHARACTERS', (int) $word_length['min']), $user->lang('CHARACTERS', (int) $word_length['max'])));
  256. }
  257. else
  258. {
  259. trigger_error($ignored);
  260. }
  261. }
  262. }
  263. if (!$keywords && sizeof($author_id_ary))
  264. {
  265. // if it is an author search we want to show topics by default
  266. $show_results = ($topic_id) ? 'posts' : request_var('sr', ($search_id == 'egosearch') ? 'topics' : 'posts');
  267. $show_results = ($show_results == 'posts') ? 'posts' : 'topics';
  268. }
  269. // define some variables needed for retrieving post_id/topic_id information
  270. $sort_by_sql = array('a' => 'u.username_clean', 't' => (($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time'), 'f' => 'f.forum_id', 'i' => 't.topic_title', 's' => (($show_results == 'posts') ? 'p.post_subject' : 't.topic_title'));
  271. // pre-made searches
  272. $sql = $field = $l_search_title = '';
  273. if ($search_id)
  274. {
  275. switch ($search_id)
  276. {
  277. // Oh holy Bob, bring us some activity...
  278. case 'active_topics':
  279. $l_search_title = $user->lang['SEARCH_ACTIVE_TOPICS'];
  280. $show_results = 'topics';
  281. $sort_key = 't';
  282. $sort_dir = 'd';
  283. $sort_days = request_var('st', 7);
  284. $sort_by_sql['t'] = 't.topic_last_post_time';
  285. 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);
  286. $s_sort_key = $s_sort_dir = '';
  287. $last_post_time_sql = ($sort_days) ? ' AND t.topic_last_post_time > ' . (time() - ($sort_days * 24 * 3600)) : '';
  288. $sql = 'SELECT t.topic_last_post_time, t.topic_id
  289. FROM ' . TOPICS_TABLE . " t
  290. WHERE t.topic_moved_id = 0
  291. $last_post_time_sql
  292. AND " . $m_approve_topics_fid_sql . '
  293. ' . ((sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '') . '
  294. ORDER BY t.topic_last_post_time DESC';
  295. $field = 'topic_id';
  296. break;
  297. case 'unanswered':
  298. $l_search_title = $user->lang['SEARCH_UNANSWERED'];
  299. $show_results = request_var('sr', 'topics');
  300. $show_results = ($show_results == 'posts') ? 'posts' : 'topics';
  301. $sort_by_sql['t'] = ($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time';
  302. $sort_by_sql['s'] = ($show_results == 'posts') ? 'p.post_subject' : 't.topic_title';
  303. $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
  304. $sort_join = ($sort_key == 'f') ? FORUMS_TABLE . ' f, ' : '';
  305. $sql_sort = ($sort_key == 'f') ? ' AND f.forum_id = p.forum_id ' . $sql_sort : $sql_sort;
  306. if ($sort_days)
  307. {
  308. $last_post_time = 'AND p.post_time > ' . (time() - ($sort_days * 24 * 3600));
  309. }
  310. else
  311. {
  312. $last_post_time = '';
  313. }
  314. if ($sort_key == 'a')
  315. {
  316. $sort_join = USERS_TABLE . ' u, ';
  317. $sql_sort = ' AND u.user_id = p.poster_id ' . $sql_sort;
  318. }
  319. if ($show_results == 'posts')
  320. {
  321. $sql = "SELECT p.post_id
  322. FROM $sort_join" . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t
  323. WHERE t.topic_posts_approved = 1
  324. AND p.topic_id = t.topic_id
  325. $last_post_time
  326. AND $m_approve_posts_fid_sql
  327. " . ((sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . "
  328. $sql_sort";
  329. $field = 'post_id';
  330. }
  331. else
  332. {
  333. $sql = 'SELECT DISTINCT ' . $sort_by_sql[$sort_key] . ", p.topic_id
  334. FROM $sort_join" . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t
  335. WHERE t.topic_posts_approved = 1
  336. AND t.topic_moved_id = 0
  337. AND p.topic_id = t.topic_id
  338. $last_post_time
  339. AND $m_approve_topics_fid_sql
  340. " . ((sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . "
  341. $sql_sort";
  342. $field = 'topic_id';
  343. }
  344. break;
  345. case 'unreadposts':
  346. $l_search_title = $user->lang['SEARCH_UNREAD'];
  347. // force sorting
  348. $show_results = 'topics';
  349. $sort_key = 't';
  350. $sort_by_sql['t'] = 't.topic_last_post_time';
  351. $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
  352. $sql_where = 'AND t.topic_moved_id = 0
  353. AND ' . $m_approve_topics_fid_sql . '
  354. ' . ((sizeof($ex_fid_ary)) ? 'AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '');
  355. 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);
  356. $s_sort_key = $s_sort_dir = $u_sort_param = $s_limit_days = '';
  357. break;
  358. case 'newposts':
  359. $l_search_title = $user->lang['SEARCH_NEW'];
  360. // force sorting
  361. $show_results = (request_var('sr', 'topics') == 'posts') ? 'posts' : 'topics';
  362. $sort_key = 't';
  363. $sort_dir = 'd';
  364. $sort_by_sql['t'] = ($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time';
  365. $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
  366. 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);
  367. $s_sort_key = $s_sort_dir = $u_sort_param = $s_limit_days = '';
  368. if ($show_results == 'posts')
  369. {
  370. $sql = 'SELECT p.post_id
  371. FROM ' . POSTS_TABLE . ' p
  372. WHERE p.post_time > ' . $user->data['user_lastvisit'] . '
  373. AND ' . $m_approve_posts_fid_sql . '
  374. ' . ((sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . "
  375. $sql_sort";
  376. $field = 'post_id';
  377. }
  378. else
  379. {
  380. $sql = 'SELECT t.topic_id
  381. FROM ' . TOPICS_TABLE . ' t
  382. WHERE t.topic_last_post_time > ' . $user->data['user_lastvisit'] . '
  383. AND t.topic_moved_id = 0
  384. AND ' . $m_approve_topics_fid_sql . '
  385. ' . ((sizeof($ex_fid_ary)) ? 'AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '') . "
  386. $sql_sort";
  387. /*
  388. [Fix] queued replies missing from "view new posts" (Bug #42705 - Patch by Paul)
  389. - Creates temporary table, query is far from optimized
  390. $sql = 'SELECT t.topic_id
  391. FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p
  392. WHERE p.post_time > ' . $user->data['user_lastvisit'] . '
  393. AND t.topic_id = p.topic_id
  394. AND t.topic_moved_id = 0
  395. AND ' . $m_approve_topics_fid_sql . "
  396. GROUP BY t.topic_id
  397. $sql_sort";
  398. */
  399. $field = 'topic_id';
  400. }
  401. break;
  402. case 'egosearch':
  403. $l_search_title = $user->lang['SEARCH_SELF'];
  404. break;
  405. }
  406. }
  407. // show_results should not change after this
  408. $per_page = ($show_results == 'posts') ? $config['posts_per_page'] : $config['topics_per_page'];
  409. $total_match_count = 0;
  410. // Set limit for the $total_match_count to reduce server load
  411. $total_matches_limit = 1000;
  412. $found_more_search_matches = false;
  413. if ($search_id)
  414. {
  415. if ($sql)
  416. {
  417. // Only return up to $total_matches_limit+1 ids (the last one will be removed later)
  418. $result = $db->sql_query_limit($sql, $total_matches_limit + 1);
  419. while ($row = $db->sql_fetchrow($result))
  420. {
  421. $id_ary[] = (int) $row[$field];
  422. }
  423. $db->sql_freeresult($result);
  424. }
  425. else if ($search_id == 'unreadposts')
  426. {
  427. // Only return up to $total_matches_limit+1 ids (the last one will be removed later)
  428. $id_ary = array_keys(get_unread_topics($user->data['user_id'], $sql_where, $sql_sort, $total_matches_limit + 1));
  429. }
  430. else
  431. {
  432. $search_id = '';
  433. }
  434. $total_match_count = sizeof($id_ary);
  435. if ($total_match_count)
  436. {
  437. // Limit the number to $total_matches_limit for pre-made searches
  438. if ($total_match_count > $total_matches_limit)
  439. {
  440. $found_more_search_matches = true;
  441. $total_match_count = $total_matches_limit;
  442. }
  443. // Make sure $start is set to the last page if it exceeds the amount
  444. $start = $pagination->validate_start($start, $per_page, $total_match_count);
  445. $id_ary = array_slice($id_ary, $start, $per_page);
  446. }
  447. else
  448. {
  449. // Set $start to 0 if no matches were found
  450. $start = 0;
  451. }
  452. }
  453. // make sure that some arrays are always in the same order
  454. sort($ex_fid_ary);
  455. sort($author_id_ary);
  456. if ($search->get_search_query())
  457. {
  458. $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);
  459. }
  460. else if (sizeof($author_id_ary))
  461. {
  462. $firstpost_only = ($search_fields === 'firstpost' || $search_fields == 'titleonly') ? true : false;
  463. $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);
  464. }
  465. $sql_where = '';
  466. if (sizeof($id_ary))
  467. {
  468. $sql_where .= $db->sql_in_set(($show_results == 'posts') ? 'p.post_id' : 't.topic_id', $id_ary);
  469. $sql_where .= (sizeof($ex_fid_ary)) ? ' AND (' . $db->sql_in_set('f.forum_id', $ex_fid_ary, true) . ' OR f.forum_id IS NULL)' : '';
  470. $sql_where .= ' AND ' . (($show_results == 'posts') ? $m_approve_posts_fid_sql : $m_approve_topics_fid_sql);
  471. }
  472. if ($show_results == 'posts')
  473. {
  474. include($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
  475. }
  476. else
  477. {
  478. include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
  479. }
  480. $user->add_lang('viewtopic');
  481. // Grab icons
  482. $icons = $cache->obtain_icons();
  483. // Output header
  484. if ($found_more_search_matches)
  485. {
  486. $l_search_matches = $user->lang('FOUND_MORE_SEARCH_MATCHES', (int) $total_match_count);
  487. }
  488. else
  489. {
  490. $l_search_matches = $user->lang('FOUND_SEARCH_MATCHES', (int) $total_match_count);
  491. }
  492. // define some vars for urls
  493. // A single wildcard will make the search results look ugly
  494. $hilit = phpbb_clean_search_string(str_replace(array('+', '-', '|', '(', ')', '&quot;'), ' ', $keywords));
  495. $hilit = str_replace(' ', '|', $hilit);
  496. $u_hilit = urlencode(htmlspecialchars_decode(str_replace('|', ' ', $hilit)));
  497. $u_show_results = '&amp;sr=' . $show_results;
  498. $u_search_forum = implode('&amp;fid%5B%5D=', $search_forum);
  499. $u_search = append_sid("{$phpbb_root_path}search.$phpEx", $u_sort_param . $u_show_results);
  500. $u_search .= ($search_id) ? '&amp;search_id=' . $search_id : '';
  501. $u_search .= ($u_hilit) ? '&amp;keywords=' . urlencode(htmlspecialchars_decode($keywords)) : '';
  502. $u_search .= ($search_terms != 'all') ? '&amp;terms=' . $search_terms : '';
  503. $u_search .= ($topic_id) ? '&amp;t=' . $topic_id : '';
  504. $u_search .= ($author) ? '&amp;author=' . urlencode(htmlspecialchars_decode($author)) : '';
  505. $u_search .= ($author_id) ? '&amp;author_id=' . $author_id : '';
  506. $u_search .= ($u_search_forum) ? '&amp;fid%5B%5D=' . $u_search_forum : '';
  507. $u_search .= (!$search_child) ? '&amp;sc=0' : '';
  508. $u_search .= ($search_fields != 'all') ? '&amp;sf=' . $search_fields : '';
  509. $u_search .= ($return_chars != 300) ? '&amp;ch=' . $return_chars : '';
  510. // Check if search backend supports phrase search or not
  511. $phrase_search_disabled = '';
  512. if (strpos(html_entity_decode($keywords), '"') !== false && method_exists($search, 'supports_phrase_search'))
  513. {
  514. $phrase_search_disabled = $search->supports_phrase_search() ? false : true;
  515. }
  516. $pagination->generate_template_pagination($u_search, 'pagination', 'start', $total_match_count, $per_page, $start);
  517. $template->assign_vars(array(
  518. 'SEARCH_TITLE' => $l_search_title,
  519. 'SEARCH_MATCHES' => $l_search_matches,
  520. 'SEARCH_WORDS' => $keywords,
  521. 'SEARCHED_QUERY' => $search->get_search_query(),
  522. 'IGNORED_WORDS' => (sizeof($common_words)) ? implode(' ', $common_words) : '',
  523. 'PHRASE_SEARCH_DISABLED' => $phrase_search_disabled,
  524. 'TOTAL_MATCHES' => $total_match_count,
  525. 'SEARCH_IN_RESULTS' => ($search_id) ? false : true,
  526. 'S_SELECT_SORT_DIR' => $s_sort_dir,
  527. 'S_SELECT_SORT_KEY' => $s_sort_key,
  528. 'S_SELECT_SORT_DAYS' => $s_limit_days,
  529. 'S_SEARCH_ACTION' => $u_search,
  530. 'S_SHOW_TOPICS' => ($show_results == 'posts') ? false : true,
  531. 'GOTO_PAGE_IMG' => $user->img('icon_post_target', 'GOTO_PAGE'),
  532. 'NEWEST_POST_IMG' => $user->img('icon_topic_newest', 'VIEW_NEWEST_POST'),
  533. 'REPORTED_IMG' => $user->img('icon_topic_reported', 'TOPIC_REPORTED'),
  534. 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'TOPIC_UNAPPROVED'),
  535. 'DELETED_IMG' => $user->img('icon_topic_deleted', 'TOPIC_DELETED'),
  536. 'POLL_IMG' => $user->img('icon_topic_poll', 'TOPIC_POLL'),
  537. 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'),
  538. 'U_SEARCH_WORDS' => $u_search,
  539. ));
  540. if ($sql_where)
  541. {
  542. if ($show_results == 'posts')
  543. {
  544. // @todo Joining this query to the one below?
  545. $sql = 'SELECT zebra_id, friend, foe
  546. FROM ' . ZEBRA_TABLE . '
  547. WHERE user_id = ' . $user->data['user_id'];
  548. $result = $db->sql_query($sql);
  549. $zebra = array();
  550. while ($row = $db->sql_fetchrow($result))
  551. {
  552. $zebra[($row['friend']) ? 'friend' : 'foe'][] = $row['zebra_id'];
  553. }
  554. $db->sql_freeresult($result);
  555. $sql_array = array(
  556. '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',
  557. 'FROM' => array(
  558. POSTS_TABLE => 'p',
  559. ),
  560. 'LEFT_JOIN' => array(
  561. array(
  562. 'FROM' => array(TOPICS_TABLE => 't'),
  563. 'ON' => 'p.topic_id = t.topic_id',
  564. ),
  565. array(
  566. 'FROM' => array(FORUMS_TABLE => 'f'),
  567. 'ON' => 'p.forum_id = f.forum_id',
  568. ),
  569. array(
  570. 'FROM' => array(USERS_TABLE => 'u'),
  571. 'ON' => 'p.poster_id = u.user_id',
  572. ),
  573. ),
  574. 'WHERE' => $sql_where,
  575. 'ORDER_BY' => $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'),
  576. );
  577. /**
  578. * Event to modify the SQL query before the posts data is retrieved
  579. *
  580. * @event core.search_get_posts_data
  581. * @var array sql_array The SQL array
  582. * @var array zebra Array of zebra data for the current user
  583. * @var int total_match_count The total number of search matches
  584. * @var string keywords String of the specified keywords
  585. * @var array sort_by_sql Array of SQL sorting instructions
  586. * @var string s_sort_dir The sort direction
  587. * @var string s_sort_key The sort key
  588. * @var string s_limit_days Limit the age of results
  589. * @var array ex_fid_ary Array of excluded forum ids
  590. * @var array author_id_ary Array of exclusive author ids
  591. * @var string search_fields The data fields to search in
  592. * @var int search_id The id of the search request
  593. * @var int start The starting id of the results
  594. * @since 3.1.0-b3
  595. */
  596. $vars = array(
  597. 'sql_array',
  598. 'zebra',
  599. 'total_match_count',
  600. 'keywords',
  601. 'sort_by_sql',
  602. 's_sort_dir',
  603. 's_sort_key',
  604. 's_limit_days',
  605. 'ex_fid_ary',
  606. 'author_id_ary',
  607. 'search_fields',
  608. 'search_id',
  609. 'start',
  610. );
  611. extract($phpbb_dispatcher->trigger_event('core.search_get_posts_data', compact($vars)));
  612. $sql = $db->sql_build_query('SELECT', $sql_array);
  613. }
  614. else
  615. {
  616. $sql_from = TOPICS_TABLE . ' t
  617. LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = t.forum_id)
  618. ' . (($sort_key == 'a') ? ' LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = t.topic_poster) ' : '');
  619. $sql_select = 't.*, f.forum_id, f.forum_name';
  620. if ($user->data['is_registered'])
  621. {
  622. if ($config['load_db_track'] && $author_id !== $user->data['user_id'])
  623. {
  624. $sql_from .= ' LEFT JOIN ' . TOPICS_POSTED_TABLE . ' tp ON (tp.user_id = ' . $user->data['user_id'] . '
  625. AND t.topic_id = tp.topic_id)';
  626. $sql_select .= ', tp.topic_posted';
  627. }
  628. if ($config['load_db_lastread'])
  629. {
  630. $sql_from .= ' LEFT JOIN ' . TOPICS_TRACK_TABLE . ' tt ON (tt.user_id = ' . $user->data['user_id'] . '
  631. AND t.topic_id = tt.topic_id)
  632. LEFT JOIN ' . FORUMS_TRACK_TABLE . ' ft ON (ft.user_id = ' . $user->data['user_id'] . '
  633. AND ft.forum_id = f.forum_id)';
  634. $sql_select .= ', tt.mark_time, ft.mark_time as f_mark_time';
  635. }
  636. }
  637. if ($config['load_anon_lastread'] || ($user->data['is_registered'] && !$config['load_db_lastread']))
  638. {
  639. $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE);
  640. $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array();
  641. }
  642. /**
  643. * Event to modify the SQL query before the topic data is retrieved
  644. *
  645. * @event core.search_get_topic_data
  646. * @var string sql_select The SQL SELECT string used by search to get topic data
  647. * @var string sql_from The SQL FROM string used by search to get topic data
  648. * @var string sql_where The SQL WHERE string used by search to get topic data
  649. * @since 3.1.0-a1
  650. */
  651. $vars = array('sql_select', 'sql_from', 'sql_where');
  652. extract($phpbb_dispatcher->trigger_event('core.search_get_topic_data', compact($vars)));
  653. $sql = "SELECT $sql_select
  654. FROM $sql_from
  655. WHERE $sql_where";
  656. $sql .= ' ORDER BY ' . $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC');
  657. }
  658. $result = $db->sql_query($sql);
  659. $result_topic_id = 0;
  660. $rowset = array();
  661. if ($show_results == 'topics')
  662. {
  663. $forums = $rowset = $shadow_topic_list = array();
  664. while ($row = $db->sql_fetchrow($result))
  665. {
  666. $row['forum_id'] = (int) $row['forum_id'];
  667. $row['topic_id'] = (int) $row['topic_id'];
  668. if ($row['topic_status'] == ITEM_MOVED)
  669. {
  670. $shadow_topic_list[$row['topic_moved_id']] = $row['topic_id'];
  671. }
  672. $rowset[$row['topic_id']] = $row;
  673. if (!isset($forums[$row['forum_id']]) && $user->data['is_registered'] && $config['load_db_lastread'])
  674. {
  675. $forums[$row['forum_id']]['mark_time'] = $row['f_mark_time'];
  676. }
  677. $forums[$row['forum_id']]['topic_list'][] = $row['topic_id'];
  678. $forums[$row['forum_id']]['rowset'][$row['topic_id']] = &$rowset[$row['topic_id']];
  679. }
  680. $db->sql_freeresult($result);
  681. // If we have some shadow topics, update the rowset to reflect their topic information
  682. if (sizeof($shadow_topic_list))
  683. {
  684. $sql = 'SELECT *
  685. FROM ' . TOPICS_TABLE . '
  686. WHERE ' . $db->sql_in_set('topic_id', array_keys($shadow_topic_list));
  687. $result = $db->sql_query($sql);
  688. while ($row = $db->sql_fetchrow($result))
  689. {
  690. $orig_topic_id = $shadow_topic_list[$row['topic_id']];
  691. // We want to retain some values
  692. $row = array_merge($row, array(
  693. 'topic_moved_id' => $rowset[$orig_topic_id]['topic_moved_id'],
  694. 'topic_status' => $rowset[$orig_topic_id]['topic_status'],
  695. 'forum_name' => $rowset[$orig_topic_id]['forum_name'])
  696. );
  697. $rowset[$orig_topic_id] = $row;
  698. }
  699. $db->sql_freeresult($result);
  700. }
  701. unset($shadow_topic_list);
  702. foreach ($forums as $forum_id => $forum)
  703. {
  704. if ($user->data['is_registered'] && $config['load_db_lastread'])
  705. {
  706. $topic_tracking_info[$forum_id] = get_topic_tracking($forum_id, $forum['topic_list'], $forum['rowset'], array($forum_id => $forum['mark_time']));
  707. }
  708. else if ($config['load_anon_lastread'] || $user->data['is_registered'])
  709. {
  710. $topic_tracking_info[$forum_id] = get_complete_topic_tracking($forum_id, $forum['topic_list']);
  711. if (!$user->data['is_registered'])
  712. {
  713. $user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0;
  714. }
  715. }
  716. }
  717. unset($forums);
  718. }
  719. else
  720. {
  721. $bbcode_bitfield = $text_only_message = '';
  722. $attach_list = array();
  723. while ($row = $db->sql_fetchrow($result))
  724. {
  725. // We pre-process some variables here for later usage
  726. $row['post_text'] = censor_text($row['post_text']);
  727. $text_only_message = $row['post_text'];
  728. // make list items visible as such
  729. if ($row['bbcode_uid'])
  730. {
  731. $text_only_message = str_replace('[*:' . $row['bbcode_uid'] . ']', '&sdot;&nbsp;', $text_only_message);
  732. // no BBCode in text only message
  733. strip_bbcode($text_only_message, $row['bbcode_uid']);
  734. }
  735. if ($return_chars == -1 || utf8_strlen($text_only_message) < ($return_chars + 3))
  736. {
  737. $row['display_text_only'] = false;
  738. $bbcode_bitfield = $bbcode_bitfield | base64_decode($row['bbcode_bitfield']);
  739. // Does this post have an attachment? If so, add it to the list
  740. if ($row['post_attachment'] && $config['allow_attachments'])
  741. {
  742. $attach_list[$row['forum_id']][] = $row['post_id'];
  743. }
  744. }
  745. else
  746. {
  747. $row['post_text'] = $text_only_message;
  748. $row['display_text_only'] = true;
  749. }
  750. $rowset[] = $row;
  751. }
  752. $db->sql_freeresult($result);
  753. unset($text_only_message);
  754. // Instantiate BBCode if needed
  755. if ($bbcode_bitfield !== '')
  756. {
  757. include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx);
  758. $bbcode = new bbcode(base64_encode($bbcode_bitfield));
  759. }
  760. // Pull attachment data
  761. if (sizeof($attach_list))
  762. {
  763. $use_attach_list = $attach_list;
  764. $attach_list = array();
  765. foreach ($use_attach_list as $forum_id => $_list)
  766. {
  767. if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id))
  768. {
  769. $attach_list = array_merge($attach_list, $_list);
  770. }
  771. }
  772. }
  773. if (sizeof($attach_list))
  774. {
  775. $sql = 'SELECT *
  776. FROM ' . ATTACHMENTS_TABLE . '
  777. WHERE ' . $db->sql_in_set('post_msg_id', $attach_list) . '
  778. AND in_message = 0
  779. ORDER BY filetime DESC, post_msg_id ASC';
  780. $result = $db->sql_query($sql);
  781. while ($row = $db->sql_fetchrow($result))
  782. {
  783. $attachments[$row['post_msg_id']][] = $row;
  784. }
  785. $db->sql_freeresult($result);
  786. }
  787. }
  788. if ($hilit)
  789. {
  790. // Remove bad highlights
  791. $hilit_array = array_filter(explode('|', $hilit), 'strlen');
  792. foreach ($hilit_array as $key => $value)
  793. {
  794. $hilit_array[$key] = phpbb_clean_search_string($value);
  795. $hilit_array[$key] = str_replace('\*', '\w*?', preg_quote($hilit_array[$key], '#'));
  796. $hilit_array[$key] = preg_replace('#(^|\s)\\\\w\*\?(\s|$)#', '$1\w+?$2', $hilit_array[$key]);
  797. }
  798. $hilit = implode('|', $hilit_array);
  799. }
  800. /**
  801. * Modify the rowset data
  802. *
  803. * @event core.search_modify_rowset
  804. * @var array attachments Array with posts attachments data
  805. * @var string hilit String to highlight
  806. * @var array rowset Array with the search results data
  807. * @var array topic_tracking_info Array with the topics tracking data
  808. * @var string u_hilit Highlight string to be injected into URL
  809. * @var string view Search results view mode
  810. * @var array zebra Array with zebra data for the current user
  811. * @since 3.1.0-b4
  812. */
  813. $vars = array(
  814. 'attachments',
  815. 'hilit',
  816. 'rowset',
  817. 'topic_tracking_info',
  818. 'u_hilit',
  819. 'view',
  820. 'zebra',
  821. );
  822. extract($phpbb_dispatcher->trigger_event('core.search_modify_rowset', compact($vars)));
  823. foreach ($rowset as $row)
  824. {
  825. $forum_id = $row['forum_id'];
  826. $result_topic_id = $row['topic_id'];
  827. $topic_title = censor_text($row['topic_title']);
  828. $replies = $phpbb_content_visibility->get_count('topic_posts', $row, $forum_id) - 1;
  829. $view_topic_url_params = "f=$forum_id&amp;t=$result_topic_id" . (($u_hilit) ? "&amp;hilit=$u_hilit" : '');
  830. $view_topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params);
  831. if ($show_results == 'topics')
  832. {
  833. if ($config['load_db_track'] && $author_id === $user->data['user_id'])
  834. {
  835. $row['topic_posted'] = 1;
  836. }
  837. $folder_img = $folder_alt = $topic_type = '';
  838. 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);
  839. $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;
  840. $topic_unapproved = (($row['topic_visibility'] == ITEM_UNAPPROVED || $row['topic_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $forum_id)) ? true : false;
  841. $posts_unapproved = ($row['topic_visibility'] == ITEM_APPROVED && $row['topic_posts_unapproved'] && $auth->acl_get('m_approve', $forum_id)) ? true : false;
  842. $topic_deleted = $row['topic_visibility'] == ITEM_DELETED;
  843. $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", true, $user->session_id) : '';
  844. $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", true, $user->session_id) : '';
  845. $row['topic_title'] = preg_replace('#(?!<.*)(?<!\w)(' . $hilit . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#is', '<span class="posthilit">$1</span>', $row['topic_title']);
  846. $tpl_ary = array(
  847. 'TOPIC_AUTHOR' => get_username_string('username', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
  848. 'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
  849. 'TOPIC_AUTHOR_FULL' => get_username_string('full', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
  850. 'FIRST_POST_TIME' => $user->format_date($row['topic_time']),
  851. 'LAST_POST_SUBJECT' => $row['topic_last_post_subject'],
  852. 'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']),
  853. 'LAST_VIEW_TIME' => $user->format_date($row['topic_last_view_time']),
  854. 'LAST_POST_AUTHOR' => get_username_string('username', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
  855. 'LAST_POST_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
  856. 'LAST_POST_AUTHOR_FULL' => get_username_string('full', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
  857. 'TOPIC_TYPE' => $topic_type,
  858. 'TOPIC_IMG_STYLE' => $folder_img,
  859. 'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt),
  860. 'TOPIC_FOLDER_IMG_ALT' => $user->lang[$folder_alt],
  861. 'TOPIC_ICON_IMG' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['img'] : '',
  862. 'TOPIC_ICON_IMG_WIDTH' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['width'] : '',
  863. 'TOPIC_ICON_IMG_HEIGHT' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['height'] : '',
  864. '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']) : '',
  865. 'UNAPPROVED_IMG' => ($topic_unapproved || $posts_unapproved) ? $user->img('icon_topic_unapproved', ($topic_unapproved) ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '',
  866. 'S_TOPIC_TYPE' => $row['topic_type'],
  867. 'S_USER_POSTED' => (!empty($row['topic_posted'])) ? true : false,
  868. 'S_UNREAD_TOPIC' => $unread_topic,
  869. 'S_TOPIC_REPORTED' => (!empty($row['topic_reported']) && $auth->acl_get('m_report', $forum_id)) ? true : false,
  870. 'S_TOPIC_UNAPPROVED' => $topic_unapproved,
  871. 'S_POSTS_UNAPPROVED' => $posts_unapproved,
  872. 'S_TOPIC_DELETED' => $topic_deleted,
  873. 'S_HAS_POLL' => ($row['poll_start']) ? true : false,
  874. 'U_LAST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&amp;p=' . $row['topic_last_post_id']) . '#p' . $row['topic_last_post_id'],
  875. 'U_LAST_POST_AUTHOR' => get_username_string('profile', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
  876. 'U_TOPIC_AUTHOR' => get_username_string('profile', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
  877. 'U_NEWEST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&amp;view=unread') . '#unread',
  878. 'U_MCP_REPORT' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&amp;mode=reports&amp;t=' . $result_topic_id, true, $user->session_id),
  879. 'U_MCP_QUEUE' => $u_mcp_queue,
  880. );
  881. }
  882. else
  883. {
  884. if ((isset($zebra['foe']) && in_array($row['poster_id'], $zebra['foe'])) && (!$view || $view != 'show' || $post_id != $row['post_id']))
  885. {
  886. $template->assign_block_vars('searchresults', array(
  887. 'S_IGNORE_POST' => true,
  888. '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>'))
  889. );
  890. continue;
  891. }
  892. // Replace naughty words such as farty pants
  893. $row['post_subject'] = censor_text($row['post_subject']);
  894. if ($row['display_text_only'])
  895. {
  896. // now find context for the searched words
  897. $row['post_text'] = get_context($row['post_text'], array_filter(explode('|', $hilit), 'strlen'), $return_chars);
  898. $row['post_text'] = bbcode_nl2br($row['post_text']);
  899. }
  900. else
  901. {
  902. $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
  903. $row['post_text'] = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false);
  904. if (!empty($attachments[$row['post_id']]))
  905. {
  906. parse_attachments($forum_id, $row['post_text'], $attachments[$row['post_id']], $update_count);
  907. // we only display inline attachments
  908. unset($attachments[$row['post_id']]);
  909. }
  910. }
  911. if ($hilit)
  912. {
  913. // post highlighting
  914. $row['post_text'] = preg_replace('#(?!<.*)(?<!\w)(' . $hilit . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#is', '<span class="posthilit">$1</span>', $row['post_text']);
  915. $row['post_subject'] = preg_replace('#(?!<.*)(?<!\w)(' . $hilit . ')(?!\w|[^<>]*(?:</s(?:cript|tyle))?>)#is', '<span class="posthilit">$1</span>', $row['post_subject']);
  916. }
  917. $tpl_ary = array(
  918. 'POST_AUTHOR_FULL' => get_username_string('full', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
  919. 'POST_AUTHOR_COLOUR' => get_username_string('colour', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
  920. 'POST_AUTHOR' => get_username_string('username', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
  921. 'U_POST_AUTHOR' => get_username_string('profile', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
  922. 'POST_SUBJECT' => $row['post_subject'],
  923. 'POST_DATE' => (!empty($row['post_time'])) ? $user->format_date($row['post_time']) : '',
  924. 'MESSAGE' => $row['post_text']
  925. );
  926. }
  927. $tpl_ary = array_merge($tpl_ary, array(
  928. 'FORUM_ID' => $forum_id,
  929. 'TOPIC_ID' => $result_topic_id,
  930. 'POST_ID' => ($show_results == 'posts') ? $row['post_id'] : false,
  931. 'FORUM_TITLE' => $row['forum_name'],
  932. 'TOPIC_TITLE' => $topic_title,
  933. 'TOPIC_REPLIES' => $replies,
  934. 'TOPIC_VIEWS' => $row['topic_views'],
  935. 'U_VIEW_TOPIC' => $view_topic_url,
  936. 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id),
  937. 'U_VIEW_POST' => (!empty($row['post_id'])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=" . $row['topic_id'] . '&amp;p=' . $row['post_id'] . (($u_hilit) ? '&amp;hilit=' . $u_hilit : '')) . '#p' . $row['post_id'] : '',
  938. ));
  939. /**
  940. * Modify the topic data before it is assigned to the template
  941. *
  942. * @event core.search_modify_tpl_ary
  943. * @var array row Array with topic data
  944. * @var array tpl_ary Template block array with topic data
  945. * @var string show_results Display topics or posts
  946. * @var string topic_title Cleaned topic title
  947. * @var int replies The number of topic replies
  948. * @var string view_topic_url The URL to the topic
  949. * @var string folder_img The folder image of the topic
  950. * @var string folder_alt The alt attribute of the topic folder img
  951. * @var int topic_type The topic type
  952. * @var bool unread_topic Whether the topic has unread posts
  953. * @var bool topic_unapproved Whether the topic is unapproved
  954. * @var int posts_unapproved The number of unapproved posts
  955. * @var bool topic_deleted Whether the topic has been deleted
  956. * @var string u_mcp_queue The URL to the corresponding MCP queue page
  957. * @var array zebra The zebra data of the current user
  958. * @var array attachments All the attachments of the search results
  959. * @since 3.1.0-a1
  960. * @changed 3.1.0-b3 Added vars show_results, topic_title, replies,
  961. * view_topic_url, folder_img, folder_alt, topic_type, unread_topic,
  962. * topic_unapproved, posts_unapproved, topic_deleted, u_mcp_queue,
  963. * zebra, attachments
  964. */
  965. $vars = array(
  966. 'row',
  967. 'tpl_ary',
  968. 'show_results',
  969. 'topic_title',
  970. 'replies',
  971. 'view_topic_url',
  972. 'folder_img',
  973. 'folder_alt',
  974. 'topic_type',
  975. 'unread_topic',
  976. 'topic_unapproved',
  977. 'posts_unapproved',
  978. 'topic_deleted',
  979. 'u_mcp_queue',
  980. 'zebra',
  981. 'attachments',
  982. );
  983. extract($phpbb_dispatcher->trigger_event('core.search_modify_tpl_ary', compact($vars)));
  984. $template->assign_block_vars('searchresults', $tpl_ary);
  985. if ($show_results == 'topics')
  986. {
  987. $pagination->generate_template_pagination($view_topic_url, 'searchresults.pagination', 'start', $replies + 1, $config['posts_per_page'], 1, true, true);
  988. }
  989. }
  990. if ($topic_id && ($topic_id == $result_topic_id))
  991. {
  992. $template->assign_vars(array(
  993. 'SEARCH_TOPIC' => $topic_title,
  994. 'L_RETURN_TO_TOPIC' => $user->lang('RETURN_TO', $topic_title),
  995. 'U_SEARCH_TOPIC' => $view_topic_url
  996. ));
  997. }
  998. }
  999. unset($rowset);
  1000. page_header(($l_search_title) ? $l_search_title : $user->lang['SEARCH']);
  1001. $template->set_filenames(array(
  1002. 'body' => 'search_results.html')
  1003. );
  1004. make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"));
  1005. page_footer();
  1006. }
  1007. // Search forum
  1008. $s_forums = '';
  1009. $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
  1010. FROM ' . FORUMS_TABLE . ' f
  1011. LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa ON (fa.forum_id = f.forum_id
  1012. AND fa.session_id = '" . $db->sql_escape($user->session_id) . "')
  1013. ORDER BY f.left_id ASC";
  1014. $result = $db->sql_query($sql);
  1015. $right = $cat_right = $padding_inc = 0;
  1016. $padding = $forum_list = $holding = '';
  1017. $pad_store = array('0' => '');
  1018. while ($row = $db->sql_fetchrow($result))
  1019. {
  1020. if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id']))
  1021. {
  1022. // Non-postable forum with no subforums, don't display
  1023. continue;
  1024. }
  1025. if ($row['forum_type'] == FORUM_POST && ($row['left_id'] + 1 == $row['right_id']) && !$row['enable_indexing'])
  1026. {
  1027. // Postable forum with no subforums and indexing disabled, don't display
  1028. continue;
  1029. }
  1030. if ($row['forum_type'] == FORUM_LINK || ($row['forum_password'] && !$row['user_id']))
  1031. {
  1032. // if this forum is a link or password protected (user has not entered the password yet) then skip to the next branch
  1033. continue;
  1034. }
  1035. if ($row['left_id'] < $right)
  1036. {
  1037. $padding .= '&nbsp; &nbsp;';
  1038. $pad_store[$row['parent_id']] = $padding;
  1039. }
  1040. else if ($row['left_id'] > $right + 1)
  1041. {
  1042. if (isset($pad_store[$row['parent_id']]))
  1043. {
  1044. $padding = $pad_store[$row['parent_id']];
  1045. }
  1046. else
  1047. {
  1048. continue;
  1049. }
  1050. }
  1051. $right = $row['right_id'];
  1052. if ($auth->acl_gets('!f_search', '!f_list', $row['forum_id']))
  1053. {
  1054. // if the user does not have permissions to search or see this forum skip only this forum/category
  1055. continue;
  1056. }
  1057. $selected = (in_array($row['forum_id'], $search_forum)) ? ' selected="selected"' : '';
  1058. if ($row['left_id'] > $cat_right)
  1059. {
  1060. // make sure we don't forget anything
  1061. $s_forums .= $holding;
  1062. $holding = '';
  1063. }
  1064. if ($row['right_id'] - $row['left_id'] > 1)
  1065. {
  1066. $cat_right = max($cat_right, $row['right_id']);
  1067. $holding .= '<option value="' . $row['forum_id'] . '"' . $selected . '>' . $padding . $row['forum_name'] . '</option>';
  1068. }
  1069. else
  1070. {
  1071. $s_forums .= $holding . '<option value="' . $row['forum_id'] . '"' . $selected . '>' . $padding . $row['forum_name'] . '</option>';
  1072. $holding = '';
  1073. }
  1074. }
  1075. if ($holding)
  1076. {
  1077. $s_forums .= $holding;
  1078. }
  1079. $db->sql_freeresult($result);
  1080. unset($pad_store);
  1081. if (!$s_forums)
  1082. {
  1083. trigger_error('NO_SEARCH');
  1084. }
  1085. // Number of chars returned
  1086. $s_characters = '<option value="-1">' . $user->lang['ALL_AVAILABLE'] . '</option>';
  1087. $s_characters .= '<option value="0">0</option>';
  1088. $s_characters .= '<option value="25">25</option>';
  1089. $s_characters .= '<option value="50">50</option>';
  1090. for ($i = 100; $i <= 1000; $i += 100)
  1091. {
  1092. $selected = ($i == 300) ? ' selected="selected"' : '';
  1093. $s_characters .= '<option value="' . $i . '"' . $selected . '>' . $i . '</option>';
  1094. }
  1095. $s_hidden_fields = array('t' => $topic_id);
  1096. if ($_SID)
  1097. {
  1098. $s_hidden_fields['sid'] = $_SID;
  1099. }
  1100. if (!empty($_EXTRA_URL))
  1101. {
  1102. foreach ($_EXTRA_URL as $url_param)
  1103. {
  1104. $url_param = explode('=', $url_param, 2);
  1105. $s_hidden_fields[$url_param[0]] = $url_param[1];
  1106. }
  1107. }
  1108. $template->assign_vars(array(
  1109. 'S_SEARCH_ACTION' => append_sid("{$phpbb_root_path}search.$phpEx", false, true, 0), // We force no ?sid= appending by using 0
  1110. 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields),
  1111. 'S_CHARACTER_OPTIONS' => $s_characters,
  1112. 'S_FORUM_OPTIONS' => $s_forums,
  1113. 'S_SELECT_SORT_DIR' => $s_sort_dir,
  1114. 'S_SELECT_SORT_KEY' => $s_sort_key,
  1115. 'S_SELECT_SORT_DAYS' => $s_limit_days,
  1116. 'S_IN_SEARCH' => true,
  1117. ));
  1118. // only show recent searches to search administrators
  1119. if ($auth->acl_get('a_search'))
  1120. {
  1121. // Handle large objects differently for Oracle and MSSQL
  1122. switch ($db->sql_layer)
  1123. {
  1124. case 'oracle':
  1125. $sql = 'SELECT search_time, search_keywords
  1126. FROM ' . SEARCH_RESULTS_TABLE . '
  1127. WHERE dbms_lob.getlength(search_keywords) > 0
  1128. ORDER BY search_time DESC';
  1129. break;
  1130. case 'mssql':
  1131. case 'mssql_odbc':
  1132. case 'mssqlnative':
  1133. $sql = 'SELECT search_time, search_keywords
  1134. FROM ' . SEARCH_RESULTS_TABLE . '
  1135. WHERE DATALENGTH(search_keywords) > 0
  1136. ORDER BY search_time DESC';
  1137. break;
  1138. default:
  1139. $sql = 'SELECT search_time, search_keywords
  1140. FROM ' . SEARCH_RESULTS_TABLE . '
  1141. WHERE search_keywords <> \'\'
  1142. ORDER BY search_time DESC';
  1143. break;
  1144. }
  1145. $result = $db->sql_query_limit($sql, 5);
  1146. while ($row = $db->sql_fetchrow($result))
  1147. {
  1148. $keywords = $row['search_keywords'];
  1149. $template->assign_block_vars('recentsearch', array(
  1150. 'KEYWORDS' => $keywords,
  1151. 'TIME' => $user->format_date($row['search_time']),
  1152. 'U_KEYWORDS' => append_sid("{$phpbb_root_path}search.$phpEx", 'keywords=' . urlencode(htmlspecialchars_decode($keywords)))
  1153. ));
  1154. }
  1155. $db->sql_freeresult($result);
  1156. }
  1157. // Output the basic page
  1158. page_header($user->lang['SEARCH']);
  1159. $template->set_filenames(array(
  1160. 'body' => 'search_body.html')
  1161. );
  1162. make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"));
  1163. page_footer();