/upload/search.php

http://torrentpier2.googlecode.com/ · PHP · 959 lines · 763 code · 140 blank · 56 comment · 152 complexity · ace2655a86fa0b7f1b9e3bac6a06d445 MD5 · raw file

  1. <?php
  2. define('BB_SCRIPT', 'search');
  3. define('BB_ROOT', './');
  4. require(BB_ROOT . 'common.php');
  5. require(INC_DIR . 'bbcode.php');
  6. require(INC_DIR . 'class.utf8.php');
  7. require(INC_DIR . 'class.correct.php');
  8. require(INC_DIR . 'class.reflection.php');
  9. $page_cfg['load_tpl_vars'] = array(
  10. 'post_buttons',
  11. 'post_icons',
  12. 'topic_icons',
  13. );
  14. $user->session_start(array('req_login' => $bb_cfg['disable_search_for_guest']));
  15. set_die_append_msg();
  16. if (isset($_POST['del_my_post']))
  17. {
  18. $template->assign_var('BB_DIE_APPEND_MSG', '
  19. <a href="#" onclick="window.close(); window.opener.focus();">'. $lang['GOTO_MY_MESSAGE'] .'</a>
  20. <br /><br />
  21. <a href="index.php">'. $lang['INDEX_RETURN'] .'</a>
  22. ');
  23. if (empty($_POST['topic_id_list']) OR !$topic_csv = get_id_csv($_POST['topic_id_list']))
  24. {
  25. bb_die($lang['NONE_SELECTED']);
  26. }
  27. DB()->query("UPDATE ". BB_POSTS ." SET user_post = 0 WHERE poster_id = {$user->id} AND topic_id IN($topic_csv)");
  28. if (DB()->affected_rows())
  29. {
  30. //bb_die('????????? ???? ['. count($_POST['topic_id_list']) .' ??.] ??????? ?? ?????? "??? ?????????"');
  31. bb_die($lang['DEL_MY_MESSAGE']);
  32. }
  33. else
  34. {
  35. bb_die($lang['NO_TOPICS_MY_MESSAGE']);
  36. }
  37. }
  38. else if(isset($_POST['add_my_post']))
  39. {
  40. $template->assign_var('BB_DIE_APPEND_MSG', '
  41. <a href="#" onclick="window.close(); window.opener.focus();">'. $lang['GOTO_MY_MESSAGE'] .'</a>
  42. <br /><br />
  43. <a href="index.php">'. $lang['INDEX_RETURN'] .'</a>
  44. ');
  45. if (IS_GUEST)
  46. {
  47. redirect('index.php');
  48. }
  49. DB()->query("UPDATE ". BB_POSTS ." SET user_post = 1 WHERE poster_id = {$user->id}");
  50. redirect("search.php?u={$user->id}");
  51. }
  52. $tracking_topics = get_tracks('topic');
  53. $tracking_forums = get_tracks('forum');
  54. if ($mode =& $_REQUEST['mode'])
  55. {
  56. // This handles the simple windowed user search functions called from various other scripts
  57. if ($mode == 'searchuser')
  58. {
  59. $username = isset($_POST['search_username']) ? $_POST['search_username'] : '';
  60. username_search($username);
  61. exit;
  62. }
  63. }
  64. $excluded_forums_csv = $user->get_excluded_forums(AUTH_READ);
  65. $search_limit = 500;
  66. $forum_select_size = 16; // forum select box max rows
  67. $max_forum_name_len = 60; // inside forum select box
  68. $text_match_max_len = 60;
  69. $poster_name_max_len = 25;
  70. $start = isset($_REQUEST['start']) ? abs(intval($_REQUEST['start'])) : 0;
  71. $url = basename(__FILE__);
  72. $anon_id = GUEST_UID;
  73. $user_id = $userdata['user_id'];
  74. $lastvisit = (IS_GUEST) ? TIMENOW : $userdata['user_lastvisit'];
  75. $search_id = (isset($_GET['id']) && verify_id($_GET['id'], SEARCH_ID_LENGTH)) ? $_GET['id'] : '';
  76. $session_id = $userdata['session_id'];
  77. $items_found = $items_display = $previous_settings = null;
  78. $text_match_sql = '';
  79. $cat_tbl = BB_CATEGORIES .' c';
  80. $dl_stat_tbl = BB_BT_DLSTATUS .' dl';
  81. $forums_tbl = BB_FORUMS .' f';
  82. $posts_tbl = BB_POSTS .' p';
  83. $posts_text_tbl = BB_POSTS_TEXT .' pt';
  84. $posts_html_tbl = BB_POSTS_HTML .' h';
  85. $tr_snap_tbl = BB_BT_TRACKER_SNAP .' sn';
  86. $topics_tbl = BB_TOPICS .' t';
  87. $torrents_tbl = BB_BT_TORRENTS .' tor';
  88. $tracker_tbl = BB_BT_TRACKER .' tr';
  89. $users_tbl = BB_USERS .' u';
  90. // Cat/forum data
  91. if (!$forums = $datastore->get('cat_forums'))
  92. {
  93. $datastore->update('cat_forums');
  94. $forums = $datastore->get('cat_forums');
  95. }
  96. $forum_name_html = $forums['forum_name_html'];
  97. //
  98. // Search options
  99. //
  100. // Key values
  101. $search_all = 0;
  102. $sort_asc = 1;
  103. $sort_desc = 0;
  104. $as_topics = 0;
  105. $as_posts = 1;
  106. $show_all = 0;
  107. $show_briefly = 1;
  108. $ord_posted = 1;
  109. $ord_name = 2;
  110. $ord_repl = 3;
  111. $ord_views = 4;
  112. $ord_last_p = 5;
  113. $ord_created = 6;
  114. // Order options
  115. $order_opt = array(
  116. $ord_posted => array(
  117. 'lang' => $lang['SORT_TIME'],
  118. 'sql' => 'item_id',
  119. ),
  120. $ord_last_p => array(
  121. 'lang' => $lang['BT_LAST_POST'],
  122. 'sql' => 't.topic_last_post_id',
  123. ),
  124. $ord_created => array(
  125. 'lang' => $lang['BT_CREATED'],
  126. 'sql' => 't.topic_time',
  127. ),
  128. $ord_name => array(
  129. 'lang' => $lang['SORT_TOPIC_TITLE'],
  130. 'sql' => 't.topic_title',
  131. ),
  132. $ord_repl => array(
  133. 'lang' => $lang['REPLIES'],
  134. 'sql' => 't.topic_replies',
  135. ),
  136. );
  137. $order_select = array();
  138. foreach ($order_opt as $val => $opt)
  139. {
  140. $order_select[$opt['lang']] = $val;
  141. }
  142. // Sort direction
  143. $sort_opt = array(
  144. $sort_asc => array(
  145. 'lang' => $lang['ASC'],
  146. 'sql' => ' ASC ',
  147. ),
  148. $sort_desc => array(
  149. 'lang' => $lang['DESC'],
  150. 'sql' => ' DESC ',
  151. ),
  152. );
  153. $sort_select = array();
  154. foreach ($sort_opt as $val => $opt)
  155. {
  156. $sort_select[$opt['lang']] = $val;
  157. }
  158. // Previous days
  159. $time_opt = array(
  160. $search_all => array(
  161. 'lang' => $lang['BT_ALL_DAYS_FOR'],
  162. 'sql' => 0,
  163. ),
  164. 1 => array(
  165. 'lang' => $lang['BT_1_DAY_FOR'],
  166. 'sql' => TIMENOW - 86400,
  167. ),
  168. 3 => array(
  169. 'lang' => $lang['BT_3_DAY_FOR'],
  170. 'sql' => TIMENOW - 86400*3,
  171. ),
  172. 7 => array(
  173. 'lang' => $lang['BT_7_DAYS_FOR'],
  174. 'sql' => TIMENOW - 86400*7,
  175. ),
  176. 14 => array(
  177. 'lang' => $lang['BT_2_WEEKS_FOR'],
  178. 'sql' => TIMENOW - 86400*14,
  179. ),
  180. 30 => array(
  181. 'lang' => $lang['BT_1_MONTH_FOR'],
  182. 'sql' => TIMENOW - 86400*30,
  183. ),
  184. );
  185. $time_select = array();
  186. foreach ($time_opt as $val => $opt)
  187. {
  188. $time_select[$opt['lang']] = $val;
  189. }
  190. // Display as
  191. $display_as_opt = array(
  192. $as_topics => array(
  193. 'lang' => $lang['TOPICS'],
  194. ),
  195. $as_posts => array(
  196. 'lang' => $lang['MESSAGE'],
  197. ),
  198. );
  199. $display_as_select = array();
  200. foreach ($display_as_opt as $val => $opt)
  201. {
  202. $display_as_select[$opt['lang']] = $val;
  203. }
  204. // Chars
  205. $chars_opt = array(
  206. $show_all => array(
  207. 'lang' => $lang['ALL_AVAILABLE'],
  208. ),
  209. $show_briefly => array(
  210. 'lang' => $lang['BRIEFLY'],
  211. ),
  212. );
  213. $chars_select = array();
  214. foreach ($chars_opt as $val => $opt)
  215. {
  216. $chars_select[$opt['lang']] = $val;
  217. }
  218. $GPC = array(
  219. # var_name key_name def_value GPC type
  220. 'all_words' => array('allw', 1, CHBOX),
  221. 'cat' => array('c', null, REQUEST),
  222. 'chars' => array('ch', $show_all, SELECT),
  223. 'display_as' => array('dm', $as_topics, SELECT),
  224. 'dl_cancel' => array('dla', 0, CHBOX),
  225. 'dl_compl' => array('dlc', 0, CHBOX),
  226. 'dl_down' => array('dld', 0, CHBOX),
  227. 'dl_user_id' => array('dlu', $user_id, CHBOX),
  228. 'dl_will' => array('dlw', 0, CHBOX),
  229. 'forum' => array('f', $search_all, REQUEST),
  230. 'my_topics' => array('myt', 0, CHBOX),
  231. 'new' => array('new', 0, CHBOX),
  232. 'new_topics' => array('nt', 0, CHBOX),
  233. 'order' => array('o', $ord_posted, SELECT),
  234. 'poster_id' => array('uid', null, REQUEST),
  235. 'poster_name' => array('pn', null, REQUEST),
  236. 'sort' => array('s', $sort_desc, SELECT),
  237. 'text_match' => array('nm', null, REQUEST),
  238. 'time' => array('tm', $search_all, SELECT),
  239. 'title_only' => array('to', 0, CHBOX),
  240. 'topic' => array('t', null, REQUEST),
  241. );
  242. // Define all GPC vars with default values
  243. foreach ($GPC as $var_name => $var_options)
  244. {
  245. $GLOBALS["{$var_name}_key"] = $var_options[KEY_NAME];
  246. $GLOBALS["{$var_name}_val"] = $var_options[DEF_VAL];
  247. }
  248. // Output basic page
  249. if (empty($_GET) && empty($_POST))
  250. {
  251. // Make forum select box
  252. $forum_select_mode = explode(',', $excluded_forums_csv);
  253. $forum_select = get_forum_select($forum_select_mode, "{$forum_key}[]", $search_all, $max_forum_name_len, $forum_select_size, 'style="width: 95%;"', $search_all);
  254. $template->assign_vars(array(
  255. 'TPL_SEARCH_MAIN' => true,
  256. 'PAGE_TITLE' => $lang['SEARCH'],
  257. 'POSTER_ID_KEY' => $poster_id_key,
  258. 'TEXT_MATCH_KEY' => $text_match_key,
  259. 'POSTER_NAME_KEY' => $poster_name_key,
  260. 'THIS_USER_ID' => $userdata['user_id'],
  261. 'THIS_USER_NAME' => addslashes($userdata['username']),
  262. 'SEARCH_ACTION' => "search.php",
  263. 'U_SEARCH_USER' => "search.php?mode=searchuser&amp;input_name=$poster_name_key",
  264. 'ONLOAD_FOCUS_ID' => 'text_match_input',
  265. 'MY_TOPICS_ID' => 'my_topics',
  266. 'MY_TOPICS_CHBOX' => build_checkbox ($my_topics_key, $lang['SEARCH_MY_TOPICS'], $my_topics_val, true, null, 'my_topics'),
  267. 'TITLE_ONLY_CHBOX' => build_checkbox ($title_only_key, $lang['SEARCH_TITLES_ONLY'], true, $bb_cfg['disable_ft_search_in_posts']),
  268. 'ALL_WORDS_CHBOX' => build_checkbox ($all_words_key, $lang['SEARCH_ALL_WORDS'], true),
  269. 'DL_CANCEL_CHBOX' => build_checkbox ($dl_cancel_key, $lang['SEARCH_DL_CANCEL'], $dl_cancel_val, IS_GUEST, 'dlCancel'),
  270. 'DL_COMPL_CHBOX' => build_checkbox ($dl_compl_key, $lang['SEARCH_DL_COMPLETE'], $dl_compl_val, IS_GUEST, 'dlComplete'),
  271. 'DL_DOWN_CHBOX' => build_checkbox ($dl_down_key, $lang['SEARCH_DL_DOWN'], $dl_down_val, IS_GUEST, 'dlDown'),
  272. 'DL_WILL_CHBOX' => build_checkbox ($dl_will_key, $lang['SEARCH_DL_WILL'], $dl_will_val, IS_GUEST, 'dlWill'),
  273. 'ONLY_NEW_CHBOX' => build_checkbox ($new_key, $lang['BT_ONLY_NEW'], $new_val, IS_GUEST),
  274. 'NEW_TOPICS_CHBOX' => build_checkbox ($new_topics_key, $lang['NEW_TOPICS'], $new_topics_val, IS_GUEST),
  275. 'FORUM_SELECT' => $forum_select,
  276. 'TIME_SELECT' => build_select ($time_key, $time_select, $time_val),
  277. 'ORDER_SELECT' => build_select ($order_key, $order_select, $order_val),
  278. 'SORT_SELECT' => build_select ($sort_key, $sort_select, $sort_val),
  279. 'CHARS_SELECT' => '', # build_select ($chars_key, $chars_select, $chars_val),
  280. 'DISPLAY_AS_SELECT' => build_select ($display_as_key, $display_as_select, $display_as_val),
  281. ));
  282. print_page('search.tpl');
  283. }
  284. unset($forums);
  285. $datastore->rm('cat_forums');
  286. // Restore previously found items list and search settings if we have valid $search_id
  287. if ($search_id)
  288. {
  289. $row = DB()->fetch_row("
  290. SELECT search_array, search_settings
  291. FROM ". BB_SEARCH ."
  292. WHERE session_id = '$session_id'
  293. AND search_type = ". SEARCH_TYPE_POST ."
  294. AND search_id = '$search_id'
  295. LIMIT 1
  296. ");
  297. if (empty($row['search_settings']))
  298. {
  299. bb_die($lang['SESSION_EXPIRED']);
  300. }
  301. $previous_settings = unserialize($row['search_settings']);
  302. $items_found = explode(',', $row['search_array']);
  303. }
  304. // Get simple "CHBOX" and "SELECT" type vars
  305. foreach ($GPC as $name => $params)
  306. {
  307. if ($params[GPC_TYPE] == CHBOX)
  308. {
  309. checkbox_get_val($params[KEY_NAME], ${"{$name}_val"}, $params[DEF_VAL]);
  310. }
  311. else if ($params[GPC_TYPE] == SELECT)
  312. {
  313. select_get_val($params[KEY_NAME], ${"{$name}_val"}, ${"{$name}_opt"}, $params[DEF_VAL]);
  314. }
  315. }
  316. // Get other "REQUEST" vars
  317. $egosearch = false;
  318. if (!$items_found)
  319. {
  320. // For compatibility with old-style params
  321. if (isset($_REQUEST['search_id']))
  322. {
  323. switch ($_REQUEST['search_id'])
  324. {
  325. case 'egosearch':
  326. $egosearch = true;
  327. $display_as_val = $as_topics;
  328. if (empty($_REQUEST[$poster_id_key]))
  329. {
  330. $_REQUEST[$poster_id_key] = $user_id;
  331. }
  332. break;
  333. case 'newposts':
  334. $new_val = true;
  335. break;
  336. }
  337. }
  338. // Forum
  339. $forum_selected = '';
  340. if ($var =& $_REQUEST[$forum_key])
  341. {
  342. $forum_selected = get_id_ary($var);
  343. if (!in_array($search_all, $forum_selected))
  344. {
  345. $forum_val = join(',', $forum_selected);
  346. }
  347. }
  348. // Topic
  349. if ($var =& $_REQUEST[$topic_key])
  350. {
  351. $topic_val = join(',', get_id_ary($var));
  352. }
  353. // Poster id (from requested name or id)
  354. if ($var = request_var($poster_id_key, 0))
  355. {
  356. $poster_id_val = (int) $var;
  357. if ($poster_id_val != $user_id && !get_username($poster_id_val))
  358. {
  359. bb_die($lang['USER_NOT_EXIST']);
  360. }
  361. }
  362. else if ($var =& $_POST[$poster_name_key])
  363. {
  364. $poster_name_sql = str_replace("\\'", "''", clean_username($var));
  365. if (!$poster_id_val = get_user_id($poster_name_sql))
  366. {
  367. bb_die($lang['USER_NOT_EXIST']);
  368. }
  369. }
  370. // Search words
  371. if ($var =& $_REQUEST[$text_match_key])
  372. {
  373. if ($tmp = substr(trim($var), 0, $text_match_max_len))
  374. {
  375. // Autocorrect wrong keyboard layout
  376. $tlc = new Text_LangCorrect();
  377. $title_match_val = $tlc->parse($tlc->parse($tmp, 1), 2);
  378. $text_match_sql = clean_text_match($title_match_val, $all_words_val, false, true);
  379. }
  380. }
  381. }
  382. $dl_status = array();
  383. if ($dl_cancel_val) $dl_status[] = DL_STATUS_CANCEL;
  384. if ($dl_compl_val) $dl_status[] = DL_STATUS_COMPLETE;
  385. if ($dl_down_val) $dl_status[] = DL_STATUS_DOWN;
  386. if ($dl_will_val) $dl_status[] = DL_STATUS_WILL;
  387. $dl_status_csv = join(',', $dl_status);
  388. // Switches
  389. $dl_search = ($dl_status && !IS_GUEST);
  390. $new_posts = ($new_val && !IS_GUEST);
  391. $prev_days = ($time_val != $search_all);
  392. $new_topics = (!IS_GUEST && ($new_topics_val || isset($_GET['newposts'])));
  393. $my_topics = ($poster_id_val && $my_topics_val);
  394. $my_posts = ($poster_id_val && !$my_topics_val);
  395. $title_match = ($text_match_sql && ($title_only_val || $bb_cfg['disable_ft_search_in_posts']));
  396. // "Display as" mode (posts or topics)
  397. $post_mode = (!$dl_search && ($display_as_val == $as_posts || isset($_GET['search_author'])));
  398. // Start building SQL
  399. $SQL = DB()->get_empty_sql_array();
  400. // Displaying "as posts" mode
  401. if ($post_mode)
  402. {
  403. $order = $order_opt[$order_val]['sql'];
  404. $sort = $sort_opt[$sort_val]['sql'];
  405. $per_page = $bb_cfg['posts_per_page'];
  406. $display_as_val = $as_posts;
  407. // Run initial search for post_ids
  408. if (!$items_found)
  409. {
  410. $join_t = ($title_match || $my_topics || $new_topics || in_array($order_val, array($ord_last_p, $ord_created, $ord_name, $ord_repl)));
  411. $join_s = ($text_match_sql && !$title_match);
  412. $join_p = ($my_posts || $join_s);
  413. $tbl = ($join_t && !$join_p) ? 't' : 'p';
  414. $time_field = ($join_t && !$join_p) ? 'topic_last_post_time' : 'post_time';
  415. // SELECT
  416. $SQL['SELECT'][] = ($join_t && !$join_p) ? 't.topic_first_post_id AS item_id' : 'p.post_id AS item_id';
  417. // FROM
  418. if ($join_t) $SQL['FROM'][] = $topics_tbl;
  419. if ($join_p) $SQL['FROM'][] = $posts_tbl;
  420. if (!$SQL['FROM'])
  421. {
  422. $join_p = true;
  423. $SQL['FROM'][] = $posts_tbl;
  424. }
  425. // WHERE
  426. if ($join_p && $join_t) $SQL['WHERE'][] = "t.topic_id = p.topic_id";
  427. if ($excluded_forums_csv) $SQL['WHERE'][] = "$tbl.forum_id NOT IN($excluded_forums_csv)";
  428. if ($forum_val) $SQL['WHERE'][] = "$tbl.forum_id IN($forum_val)";
  429. if ($topic_val) $SQL['WHERE'][] = "$tbl.topic_id IN($topic_val)";
  430. if ($new_posts) $SQL['WHERE'][] = "$tbl.$time_field > $lastvisit";
  431. if ($new_topics) $SQL['WHERE'][] = "t.topic_time > $lastvisit";
  432. if ($prev_days) $SQL['WHERE'][] = "$tbl.$time_field > ". $time_opt[$time_val]['sql'];
  433. if ($my_posts) $SQL['WHERE'][] = "p.poster_id = $poster_id_val";
  434. if ($my_topics) $SQL['WHERE'][] = "t.topic_poster = $poster_id_val";
  435. if ($text_match_sql)
  436. {
  437. $search_match_topics_csv = '';
  438. $title_match_topics = get_title_match_topics($text_match_sql, $forum_selected);
  439. if (!$search_match_topics_csv = join(',', $title_match_topics))
  440. {
  441. bb_die($lang['NO_SEARCH_MATCH']);
  442. }
  443. $where_id = ($title_match) ? 'topic_id' : 'post_id';
  444. $SQL['WHERE'][] = "$tbl.$where_id IN($search_match_topics_csv)";
  445. prevent_huge_searches($SQL);
  446. }
  447. if (!$SQL['WHERE']) redirect(basename(__FILE__));
  448. $SQL['GROUP BY'][] = "item_id";
  449. $SQL['ORDER BY'][] = ($new_posts && $join_p) ? "p.topic_id ASC, p.post_time ASC" : "$order $sort";
  450. $SQL['LIMIT'][] = "$search_limit";
  451. $items_display = fetch_search_ids($SQL);
  452. }
  453. else if (!$items_display = array_slice($items_found, $start, $per_page))
  454. {
  455. bb_die($lang['NO_SEARCH_MATCH']);
  456. }
  457. // Build SQL for displaying posts
  458. $excluded_forums_sql = ($excluded_forums_csv) ? " AND t.forum_id NOT IN($excluded_forums_csv) " : '';
  459. $sql = "
  460. SELECT
  461. p.post_id AS item_id,
  462. t.*,
  463. p.*,
  464. h.post_html, IF(h.post_html IS NULL, pt.post_text, NULL) AS post_text,
  465. IF(p.poster_id = $anon_id, p.post_username, u.username) AS username, u.user_id, u.user_rank
  466. FROM $posts_tbl
  467. INNER JOIN $topics_tbl ON(t.topic_id = p.topic_id)
  468. INNER JOIN $posts_text_tbl ON(pt.post_id = p.post_id)
  469. LEFT JOIN $posts_html_tbl ON(h.post_id = pt.post_id)
  470. INNER JOIN $users_tbl ON(u.user_id = p.poster_id)
  471. WHERE
  472. p.post_id IN(". join(',', $items_display) .")
  473. $excluded_forums_sql
  474. LIMIT $per_page
  475. ";
  476. // Fetch posts data
  477. if (!$unsorted_rows = DB()->fetch_rowset($sql))
  478. {
  479. bb_die($lang['NO_SEARCH_MATCH']);
  480. }
  481. $tmp = $sorted_rows = array();
  482. foreach ($unsorted_rows as $row)
  483. {
  484. $tmp[$row['post_id']] = $row;
  485. }
  486. foreach ($items_display as $post_id)
  487. {
  488. if (empty($tmp[$post_id]))
  489. {
  490. continue; // if post was deleted but still remain in search results
  491. }
  492. $topic_id = $tmp[$post_id]['topic_id'];
  493. $sorted_rows[$topic_id][] = $tmp[$post_id];
  494. }
  495. // Output page
  496. $new_tracks = array();
  497. foreach ($sorted_rows as $topic_id => $topic_posts)
  498. {
  499. // Topic title block
  500. $first_post = $topic_posts[0];
  501. $topic_id = (int) $topic_id;
  502. $forum_id = (int) $first_post['forum_id'];
  503. $is_unread_t = is_unread($first_post['topic_last_post_time'], $topic_id, $forum_id);
  504. $template->assign_block_vars('t', array(
  505. 'FORUM_ID' => $forum_id,
  506. 'FORUM_NAME' => $forum_name_html[$forum_id],
  507. 'TOPIC_ID' => $topic_id,
  508. 'TOPIC_TITLE' => $first_post['topic_title'],
  509. 'TOPIC_ICON' => get_topic_icon($first_post, $is_unread_t),
  510. ));
  511. $quote_btn = true;
  512. $edit_btn = $delpost_btn = $ip_btn = (IS_AM);
  513. // Topic posts block
  514. foreach ($topic_posts as $row_num => $post)
  515. {
  516. $template->assign_block_vars('t.p', array(
  517. 'ROW_NUM' => $row_num,
  518. 'POSTER_ID' => $post['poster_id'],
  519. 'POSTER' => profile_url($post),
  520. 'POST_ID' => $post['post_id'],
  521. 'POST_DATE' => bb_date($post['post_time'], $bb_cfg['post_date_format']),
  522. 'IS_UNREAD' => is_unread($post['post_time'], $topic_id, $forum_id),
  523. 'MESSAGE' => ($chars_val == $show_all) ? get_parsed_post($post, 'full') : get_parsed_post($post, 'briefly'),
  524. 'POSTED_AFTER' => '',
  525. 'QUOTE' => $quote_btn,
  526. 'EDIT' => $edit_btn,
  527. 'DELETE' => $delpost_btn,
  528. 'IP' => $ip_btn,
  529. ));
  530. $curr_new_track_val = !empty($new_tracks[$topic_id]) ? $new_tracks[$topic_id] : 0;
  531. $new_tracks[$topic_id] = max($curr_new_track_val, $post['post_time']);
  532. }
  533. }
  534. set_tracks(COOKIE_TOPIC, $tracking_topics, $new_tracks);
  535. }
  536. // Displaying "as topics" mode
  537. else
  538. {
  539. $order = $order_opt[$order_val]['sql'];
  540. $sort = $sort_opt[$sort_val]['sql'];
  541. $per_page = $bb_cfg['topics_per_page'];
  542. $display_as_val = $as_topics;
  543. // Run initial search for topic_ids
  544. if (!$items_found)
  545. {
  546. $join_t = ($title_match || $my_topics || $new_topics || $dl_search || $new_posts || in_array($order_val, array($ord_last_p, $ord_created, $ord_name, $ord_repl)));
  547. $join_s = ($text_match_sql && !$title_match);
  548. $join_p = ($my_posts || $join_s);
  549. $join_dl = ($dl_search);
  550. $tbl = ($join_p && !$join_t) ? 'p' : 't';
  551. $time_field = ($join_p && !$join_t) ? 'post_time' : 'topic_last_post_time';
  552. // SELECT
  553. if ($egosearch)
  554. {
  555. $SQL['SELECT'][] = 'p.topic_id AS item_id, MAX(p.post_time) AS max_post_time';
  556. }
  557. else
  558. {
  559. $SQL['SELECT'][] = ($join_p && !$join_t) ? 'p.topic_id AS item_id' : 't.topic_id AS item_id';
  560. }
  561. // FROM
  562. if ($join_t) $SQL['FROM'][] = $topics_tbl;
  563. if ($join_p) $SQL['FROM'][] = $posts_tbl;
  564. if (!$SQL['FROM'])
  565. {
  566. $join_t = true;
  567. $SQL['FROM'][] = $topics_tbl;
  568. }
  569. // WHERE
  570. if ($join_p && $join_t) $SQL['WHERE'][] = "t.topic_id = p.topic_id";
  571. if ($excluded_forums_csv) $SQL['WHERE'][] = "$tbl.forum_id NOT IN($excluded_forums_csv)";
  572. if ($join_t) $SQL['WHERE'][] = "t.topic_status != ". TOPIC_MOVED;
  573. if ($forum_val) $SQL['WHERE'][] = "$tbl.forum_id IN($forum_val)";
  574. if ($topic_val) $SQL['WHERE'][] = "$tbl.topic_id IN($topic_val)";
  575. if ($new_posts) $SQL['WHERE'][] = "$tbl.$time_field > $lastvisit";
  576. if ($new_topics) $SQL['WHERE'][] = "t.topic_time > $lastvisit";
  577. if ($prev_days) $SQL['WHERE'][] = "$tbl.$time_field > ". $time_opt[$time_val]['sql'];
  578. if ($my_posts) $SQL['WHERE'][] = "p.poster_id = $poster_id_val";
  579. if ($my_posts && $user->id == $poster_id_val)
  580. {
  581. $SQL['WHERE'][] = "p.user_post = 1";
  582. if($userdata['user_posts'])
  583. {
  584. $template->assign_var('BB_DIE_APPEND_MSG', '
  585. <form id="mod-action" method="POST" action="search.php">
  586. <input type="submit" name="add_my_post" value="'. $lang['RESTORE_ALL_POSTS'] .'" class="bold" onclick="if (!window.confirm( this.value +\'?\' )){ return false };" />
  587. </form>
  588. <br /><br />
  589. <a href="index.php">'. $lang['INDEX_RETURN'] .'</a>
  590. ');
  591. }
  592. }
  593. if ($my_topics) $SQL['WHERE'][] = "t.topic_poster = $poster_id_val";
  594. if ($text_match_sql)
  595. {
  596. $search_match_topics_csv = '';
  597. $title_match_topics = get_title_match_topics($text_match_sql, $forum_selected);
  598. if (!$search_match_topics_csv = join(',', $title_match_topics))
  599. {
  600. bb_die($lang['NO_SEARCH_MATCH']);
  601. }
  602. $where_id = ($title_match) ? 't.topic_id' : 'p.post_id';
  603. $SQL['WHERE'][] = "$where_id IN($search_match_topics_csv)";
  604. prevent_huge_searches($SQL);
  605. }
  606. if ($join_dl) $SQL['FROM'][] = $dl_stat_tbl;
  607. if ($join_dl) $SQL['WHERE'][] = "dl.topic_id = t.topic_id AND dl.user_id = $dl_user_id_val AND dl.user_status IN($dl_status_csv)";
  608. if (!$SQL['WHERE']) redirect(basename(__FILE__));
  609. $SQL['GROUP BY'][] = "item_id";
  610. $SQL['LIMIT'][] = "$search_limit";
  611. if ($egosearch)
  612. {
  613. $SQL['ORDER BY'][] = 'max_post_time DESC';
  614. }
  615. else
  616. {
  617. $SQL['ORDER BY'][] = ($order_val == $ord_posted) ? "$tbl.$time_field $sort" : "$order $sort";
  618. }
  619. $items_display = fetch_search_ids($SQL);
  620. }
  621. else if (!$items_display = array_slice($items_found, $start, $per_page))
  622. {
  623. bb_die($lang['NO_SEARCH_MATCH']);
  624. }
  625. // Build SQL for displaying topics
  626. $SQL = DB()->get_empty_sql_array();
  627. $join_dl = ($bb_cfg['show_dl_status_in_search'] && !IS_GUEST);
  628. $SQL['SELECT'][] = "
  629. t.*, t.topic_poster AS first_user_id, u1.user_rank AS first_user_rank,
  630. IF(t.topic_poster = $anon_id, p1.post_username, u1.username) AS first_username,
  631. p2.poster_id AS last_user_id, u2.user_rank AS last_user_rank,
  632. IF(p2.poster_id = $anon_id, p2.post_username, u2.username) AS last_username
  633. ";
  634. if ($join_dl) $SQL['SELECT'][] = "dl.user_status AS dl_status";
  635. $SQL['FROM'][] = BB_TOPICS ." t";
  636. $SQL['LEFT JOIN'][] = BB_POSTS ." p1 ON(t.topic_first_post_id = p1.post_id)";
  637. $SQL['LEFT JOIN'][] = BB_USERS ." u1 ON(t.topic_poster = u1.user_id)";
  638. $SQL['LEFT JOIN'][] = BB_POSTS ." p2 ON(t.topic_last_post_id = p2.post_id)";
  639. $SQL['LEFT JOIN'][] = BB_USERS ." u2 ON(p2.poster_id = u2.user_id)";
  640. if ($join_dl)
  641. {
  642. $SQL['LEFT JOIN'][] = BB_BT_DLSTATUS ." dl ON(dl.user_id = $user_id AND dl.topic_id = t.topic_id)";
  643. }
  644. $SQL['WHERE'][] = "t.topic_id IN(". join(',', $items_display) .")";
  645. if ($excluded_forums_csv)
  646. {
  647. $SQL['WHERE'][] = "t.forum_id NOT IN($excluded_forums_csv)";
  648. }
  649. $SQL['LIMIT'][] = "$per_page";
  650. // Fetch topics data
  651. $topic_rows = array();
  652. foreach (DB()->fetch_rowset($SQL) as $row)
  653. {
  654. $topic_rows[$row['topic_id']] = $row;
  655. }
  656. if (!$topic_rows)
  657. {
  658. bb_die($lang['NO_SEARCH_MATCH']);
  659. }
  660. // Output page
  661. foreach ($items_display as $row_num => $item_id)
  662. {
  663. if (empty($topic_rows[$item_id]))
  664. {
  665. continue; // if topic was deleted but still remain in search results
  666. }
  667. $topic = $topic_rows[$item_id];
  668. $topic_id = $topic['topic_id'];
  669. $forum_id = $topic['forum_id'];
  670. $is_unread = is_unread($topic['topic_last_post_time'], $topic_id, $forum_id);
  671. $moved = ($topic['topic_status'] == TOPIC_MOVED);
  672. $template->assign_block_vars('t', array(
  673. 'ROW_NUM' => $row_num,
  674. 'FORUM_ID' => $forum_id,
  675. 'FORUM_NAME' => $forum_name_html[$forum_id],
  676. 'TOPIC_ID' => $topic_id,
  677. 'HREF_TOPIC_ID' => ($moved) ? $topic['topic_moved_id'] : $topic['topic_id'],
  678. 'TOPIC_TITLE' => wbr($topic['topic_title']),
  679. 'IS_UNREAD' => $is_unread,
  680. 'TOPIC_ICON' => get_topic_icon($topic, $is_unread),
  681. 'PAGINATION' => ($moved) ? '' : build_topic_pagination(TOPIC_URL . $topic_id, $topic['topic_replies'], $bb_cfg['posts_per_page']),
  682. 'REPLIES' => $topic['topic_replies'],
  683. 'ATTACH' => $topic['topic_attachment'],
  684. 'STATUS' => $topic['topic_status'],
  685. 'TYPE' => $topic['topic_type'],
  686. 'DL' => ($topic['topic_dl_type'] == TOPIC_DL_TYPE_DL),
  687. 'POLL' => $topic['topic_vote'],
  688. 'DL_CLASS' => isset($topic['dl_status']) ? $dl_link_css[$topic['dl_status']] : '',
  689. 'TOPIC_AUTHOR' => profile_url(array('username' => $topic['first_username'], 'user_id' => $topic['first_user_id'], 'user_rank' => $topic['first_user_rank'])),
  690. 'LAST_POSTER' => profile_url(array('username' => $topic['last_username'], 'user_id' => $topic['last_user_id'], 'user_rank' => $topic['last_user_rank'])),
  691. 'LAST_POST_TIME' => bb_date($topic['topic_last_post_time']),
  692. 'LAST_POST_ID' => $topic['topic_last_post_id'],
  693. ));
  694. }
  695. }
  696. if ($items_display)
  697. {
  698. $items_count = count($items_found);
  699. $pages = (!$items_count) ? 1 : ceil($items_count / $per_page);
  700. $url = ($search_id) ? url_arg($url, 'id', $search_id) : $url;
  701. generate_pagination($url, $items_count, $per_page, $start);
  702. $template->assign_vars(array(
  703. 'PAGE_TITLE' => $lang['SEARCH'],
  704. 'SEARCH_MATCHES' => ($items_count) ? sprintf($lang['FOUND_SEARCH_MATCHES'], $items_count) : '',
  705. 'DISPLAY_AS_POSTS' => $post_mode,
  706. 'DL_CONTROLS' => ($dl_search && $dl_user_id_val == $user_id),
  707. 'DL_ACTION' => 'dl_list.php',
  708. 'MY_POSTS' => (!$post_mode && $my_posts && $user->id == $poster_id_val),
  709. ));
  710. print_page('search_results.tpl');
  711. }
  712. redirect(basename(__FILE__));
  713. // ----------------------------------------------------------- //
  714. // Functions
  715. //
  716. function fetch_search_ids ($sql, $search_type = SEARCH_TYPE_POST, $redirect_to_result = UA_IE)
  717. {
  718. global $lang, $search_id, $session_id, $items_found, $per_page;
  719. $items_found = array();
  720. foreach (DB()->fetch_rowset($sql) as $row)
  721. {
  722. $items_found[] = $row['item_id'];
  723. }
  724. if (!$items_count = count($items_found))
  725. {
  726. bb_die($lang['NO_SEARCH_MATCH']);
  727. }
  728. // Save results in DB
  729. $search_id = make_rand_str(SEARCH_ID_LENGTH);
  730. $redirect = ($redirect_to_result && isset($_POST['submit']));
  731. if ($items_count > $per_page || $redirect)
  732. {
  733. $search_array = join(',', $items_found);
  734. $save_in_db = array(
  735. 'order',
  736. 'sort',
  737. 'display_as',
  738. 'chars',
  739. );
  740. if ($GLOBALS['dl_cancel_val']) $save_in_db[] = 'dl_cancel';
  741. if ($GLOBALS['dl_compl_val']) $save_in_db[] = 'dl_compl';
  742. if ($GLOBALS['dl_down_val']) $save_in_db[] = 'dl_down';
  743. if ($GLOBALS['dl_will_val']) $save_in_db[] = 'dl_will';
  744. $curr_set = array();
  745. foreach ($save_in_db as $name)
  746. {
  747. $curr_set[$GLOBALS["{$name}_key"]] = $GLOBALS["{$name}_val"];
  748. }
  749. $search_settings = DB()->escape(serialize($curr_set));
  750. $columns = 'session_id, search_type, search_id, search_time, search_settings, search_array';
  751. $values = "'$session_id', $search_type, '$search_id', ". TIMENOW .", '$search_settings', '$search_array'";
  752. DB()->query("REPLACE INTO ". BB_SEARCH ." ($columns) VALUES ($values)");
  753. }
  754. if ($redirect)
  755. {
  756. redirect("search.php?id=$search_id");
  757. }
  758. return array_slice($items_found, 0, $per_page);
  759. }
  760. function prevent_huge_searches ($SQL)
  761. {
  762. global $bb_cfg;
  763. if ($bb_cfg['limit_max_search_results'])
  764. {
  765. $SQL['select_options'][] = 'SQL_CALC_FOUND_ROWS';
  766. $SQL['ORDER BY'] = array();
  767. $SQL['LIMIT'] = array('0');
  768. if (DB()->query($SQL) AND $row = DB()->fetch_row("SELECT FOUND_ROWS() AS rows_count"))
  769. {
  770. if ($row['rows_count'] > $bb_cfg['limit_max_search_results'])
  771. {
  772. # bb_log(str_compact(DB()->build_sql($SQL)) ." [{$row['rows_count']} rows]". LOG_LF, 'sql_huge_search');
  773. bb_die('Too_many_search_results');
  774. }
  775. }
  776. ### TEMP ###
  777. # preg_match("#MATCH \((\w).*?\) AGAINST \('(.*?)' IN BOOLEAN MODE\)#", stripslashes($SQL['WHERE'][count($SQL['WHERE'])-1]), $m);
  778. # $msg = date('m-d | H:i:s | ') . sprintf('%-18s', $GLOBALS['userdata']['username']) .' | '. sprintf('%04d', $row['rows_count']) .' | '. $m[1] .' | '. sprintf('%-40s', $m[2]) .' | ';
  779. # bb_log($msg . str_compact(DB()->build_sql($SQL)) . LOG_LF, 'sql_text_search');
  780. ### / TEMP ###
  781. }
  782. }
  783. function username_search ($search_match)
  784. {
  785. global $template, $lang;
  786. global $gen_simple_header;
  787. $username_list = '';
  788. if (!empty($search_match))
  789. {
  790. $username_search = preg_replace('/\*/', '%', clean_username($search_match));
  791. $sql = "
  792. SELECT username
  793. FROM ". BB_USERS ."
  794. WHERE username LIKE '". DB()->escape($username_search) . "'
  795. AND user_id <> ". GUEST_UID ."
  796. ORDER BY username
  797. LIMIT 200
  798. ";
  799. foreach (DB()->fetch_rowset($sql) as $row)
  800. {
  801. $username = htmlCHR(stripslashes(html_entity_decode($row['username'])));
  802. $username_list .= '<option value="'. $username .'">'. $username .'</option>';
  803. }
  804. if (!$username_list)
  805. {
  806. $username_list = '<option>'. $lang['NO_MATCH'] .'</option>';
  807. }
  808. }
  809. $input_name = isset($_REQUEST['input_name']) ? htmlCHR($_REQUEST['input_name']) : 'username';
  810. $template->assign_vars(array(
  811. 'TPL_SEARCH_USERNAME' => true,
  812. 'PAGE_TITLE' => $lang['SEARCH'],
  813. 'USERNAME' => !empty($search_match) ? htmlCHR(stripslashes(html_entity_decode($search_match))) : '',
  814. 'INPUT_NAME' => $input_name,
  815. 'USERNAME_OPTIONS' => $username_list,
  816. 'SEARCH_ACTION' => "search.php?mode=searchuser&amp;input_name=$input_name",
  817. ));
  818. print_page('search.tpl', 'simple');
  819. }