PageRenderTime 64ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/wwwroot/phpbb/search.php

https://github.com/spring/spring-website
PHP | 1581 lines | 1236 code | 135 blank | 210 comment | 178 complexity | f9a40eb41896b490f0293aad150f0a61 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0, LGPL-3.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file