Yoshi2889 /
SMF2.1
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * Handle all of the searching from here. |
||
| 5 | * |
||
| 6 | * Simple Machines Forum (SMF) |
||
| 7 | * |
||
| 8 | * @package SMF |
||
| 9 | * @author Simple Machines http://www.simplemachines.org |
||
| 10 | * @copyright 2017 Simple Machines and individual contributors |
||
| 11 | * @license http://www.simplemachines.org/about/smf/license.php BSD |
||
| 12 | * |
||
| 13 | * @version 2.1 Beta 4 |
||
| 14 | */ |
||
| 15 | |||
| 16 | if (!defined('SMF')) |
||
| 17 | die('No direct access...'); |
||
| 18 | |||
| 19 | // This defines two version types for checking the API's are compatible with this version of SMF. |
||
| 20 | $GLOBALS['search_versions'] = array( |
||
| 21 | // This is the forum version but is repeated due to some people rewriting $forum_version. |
||
| 22 | 'forum_version' => 'SMF 2.1 Beta 4', |
||
| 23 | // This is the minimum version of SMF that an API could have been written for to work. (strtr to stop accidentally updating version on release) |
||
| 24 | 'search_version' => strtr('SMF 2+1=Alpha=1', array('+' => '.', '=' => ' ')), |
||
| 25 | ); |
||
| 26 | |||
| 27 | /** |
||
| 28 | * Ask the user what they want to search for. |
||
| 29 | * What it does: |
||
| 30 | * - shows the screen to search forum posts (action=search) |
||
| 31 | * - uses the main sub template of the Search template. |
||
| 32 | * - uses the Search language file. |
||
| 33 | * - requires the search_posts permission. |
||
| 34 | * - decodes and loads search parameters given in the URL (if any). |
||
| 35 | * - the form redirects to index.php?action=search2. |
||
| 36 | */ |
||
| 37 | function PlushSearch1() |
||
| 38 | { |
||
| 39 | global $txt, $scripturl, $modSettings, $user_info, $context, $smcFunc, $sourcedir; |
||
| 40 | |||
| 41 | // Is the load average too high to allow searching just now? |
||
| 42 | View Code Duplication | if (!empty($context['load_average']) && !empty($modSettings['loadavg_search']) && $context['load_average'] >= $modSettings['loadavg_search']) |
|
| 43 | fatal_lang_error('loadavg_search_disabled', false); |
||
| 44 | |||
| 45 | loadLanguage('Search'); |
||
| 46 | // Don't load this in XML mode. |
||
| 47 | if (!isset($_REQUEST['xml'])) |
||
| 48 | { |
||
| 49 | loadTemplate('Search'); |
||
| 50 | loadJavaScriptFile('suggest.js', array('defer' => false), 'smf_suggest'); |
||
| 51 | } |
||
| 52 | |||
| 53 | // Check the user's permissions. |
||
| 54 | isAllowedTo('search_posts'); |
||
| 55 | |||
| 56 | // Link tree.... |
||
| 57 | $context['linktree'][] = array( |
||
| 58 | 'url' => $scripturl . '?action=search', |
||
| 59 | 'name' => $txt['search'] |
||
| 60 | ); |
||
| 61 | |||
| 62 | // This is hard coded maximum string length. |
||
| 63 | $context['search_string_limit'] = 100; |
||
| 64 | |||
| 65 | $context['require_verification'] = $user_info['is_guest'] && !empty($modSettings['search_enable_captcha']) && empty($_SESSION['ss_vv_passed']); |
||
| 66 | View Code Duplication | if ($context['require_verification']) |
|
| 67 | { |
||
| 68 | require_once($sourcedir . '/Subs-Editor.php'); |
||
| 69 | $verificationOptions = array( |
||
| 70 | 'id' => 'search', |
||
| 71 | ); |
||
| 72 | $context['require_verification'] = create_control_verification($verificationOptions); |
||
| 73 | $context['visual_verification_id'] = $verificationOptions['id']; |
||
| 74 | } |
||
| 75 | |||
| 76 | // If you got back from search2 by using the linktree, you get your original search parameters back. |
||
| 77 | if (isset($_REQUEST['params'])) |
||
| 78 | { |
||
| 79 | // Due to IE's 2083 character limit, we have to compress long search strings |
||
| 80 | $temp_params = base64_decode(str_replace(array('-', '_', '.'), array('+', '/', '='), $_REQUEST['params'])); |
||
| 81 | // Test for gzuncompress failing |
||
| 82 | $temp_params2 = @gzuncompress($temp_params); |
||
| 83 | $temp_params = explode('|"|', !empty($temp_params2) ? $temp_params2 : $temp_params); |
||
| 84 | |||
| 85 | $context['search_params'] = array(); |
||
| 86 | View Code Duplication | foreach ($temp_params as $i => $data) |
|
| 87 | { |
||
| 88 | @list ($k, $v) = explode('|\'|', $data); |
||
|
0 ignored issues
–
show
|
|||
| 89 | $context['search_params'][$k] = $v; |
||
| 90 | } |
||
| 91 | if (isset($context['search_params']['brd'])) |
||
| 92 | $context['search_params']['brd'] = $context['search_params']['brd'] == '' ? array() : explode(',', $context['search_params']['brd']); |
||
| 93 | } |
||
| 94 | |||
| 95 | View Code Duplication | if (isset($_REQUEST['search'])) |
|
| 96 | $context['search_params']['search'] = un_htmlspecialchars($_REQUEST['search']); |
||
| 97 | |||
| 98 | View Code Duplication | if (isset($context['search_params']['search'])) |
|
| 99 | $context['search_params']['search'] = $smcFunc['htmlspecialchars']($context['search_params']['search']); |
||
| 100 | View Code Duplication | if (isset($context['search_params']['userspec'])) |
|
| 101 | $context['search_params']['userspec'] = $smcFunc['htmlspecialchars']($context['search_params']['userspec']); |
||
| 102 | if (!empty($context['search_params']['searchtype'])) |
||
| 103 | $context['search_params']['searchtype'] = 2; |
||
| 104 | View Code Duplication | if (!empty($context['search_params']['minage'])) |
|
| 105 | $context['search_params']['minage'] = (int) $context['search_params']['minage']; |
||
| 106 | View Code Duplication | if (!empty($context['search_params']['maxage'])) |
|
| 107 | $context['search_params']['maxage'] = (int) $context['search_params']['maxage']; |
||
| 108 | |||
| 109 | $context['search_params']['show_complete'] = !empty($context['search_params']['show_complete']); |
||
| 110 | $context['search_params']['subject_only'] = !empty($context['search_params']['subject_only']); |
||
| 111 | |||
| 112 | // Load the error text strings if there were errors in the search. |
||
| 113 | if (!empty($context['search_errors'])) |
||
| 114 | { |
||
| 115 | loadLanguage('Errors'); |
||
| 116 | $context['search_errors']['messages'] = array(); |
||
| 117 | foreach ($context['search_errors'] as $search_error => $dummy) |
||
| 118 | { |
||
| 119 | if ($search_error === 'messages') |
||
| 120 | continue; |
||
| 121 | |||
| 122 | if ($search_error == 'string_too_long') |
||
| 123 | $txt['error_string_too_long'] = sprintf($txt['error_string_too_long'], $context['search_string_limit']); |
||
| 124 | |||
| 125 | $context['search_errors']['messages'][] = $txt['error_' . $search_error]; |
||
| 126 | } |
||
| 127 | } |
||
| 128 | |||
| 129 | // Find all the boards this user is allowed to see. |
||
| 130 | $request = $smcFunc['db_query']('order_by_board_order', ' |
||
| 131 | SELECT b.id_cat, c.name AS cat_name, b.id_board, b.name, b.child_level |
||
| 132 | FROM {db_prefix}boards AS b |
||
| 133 | LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat) |
||
| 134 | WHERE {query_see_board} |
||
| 135 | AND redirect = {string:empty_string}', |
||
| 136 | array( |
||
| 137 | 'empty_string' => '', |
||
| 138 | ) |
||
| 139 | ); |
||
| 140 | $context['num_boards'] = $smcFunc['db_num_rows']($request); |
||
| 141 | $context['boards_check_all'] = true; |
||
| 142 | $context['categories'] = array(); |
||
| 143 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 144 | { |
||
| 145 | // This category hasn't been set up yet.. |
||
| 146 | if (!isset($context['categories'][$row['id_cat']])) |
||
| 147 | $context['categories'][$row['id_cat']] = array( |
||
| 148 | 'id' => $row['id_cat'], |
||
| 149 | 'name' => $row['cat_name'], |
||
| 150 | 'boards' => array() |
||
| 151 | ); |
||
| 152 | |||
| 153 | // Set this board up, and let the template know when it's a child. (indent them..) |
||
| 154 | $context['categories'][$row['id_cat']]['boards'][$row['id_board']] = array( |
||
| 155 | 'id' => $row['id_board'], |
||
| 156 | 'name' => $row['name'], |
||
| 157 | 'child_level' => $row['child_level'], |
||
| 158 | 'selected' => (empty($context['search_params']['brd']) && (empty($modSettings['recycle_enable']) || $row['id_board'] != $modSettings['recycle_board']) && !in_array($row['id_board'], $user_info['ignoreboards'])) || (!empty($context['search_params']['brd']) && in_array($row['id_board'], $context['search_params']['brd'])) |
||
| 159 | ); |
||
| 160 | |||
| 161 | // If a board wasn't checked that probably should have been ensure the board selection is selected, yo! |
||
| 162 | if (!$context['categories'][$row['id_cat']]['boards'][$row['id_board']]['selected'] && (empty($modSettings['recycle_enable']) || $row['id_board'] != $modSettings['recycle_board'])) |
||
| 163 | $context['boards_check_all'] = false; |
||
| 164 | } |
||
| 165 | $smcFunc['db_free_result']($request); |
||
| 166 | |||
| 167 | require_once($sourcedir . '/Subs-Boards.php'); |
||
| 168 | sortCategories($context['categories']); |
||
| 169 | |||
| 170 | // Now, let's sort the list of categories into the boards for templates that like that. |
||
| 171 | $temp_boards = array(); |
||
| 172 | View Code Duplication | foreach ($context['categories'] as $category) |
|
| 173 | { |
||
| 174 | $temp_boards[] = array( |
||
| 175 | 'name' => $category['name'], |
||
| 176 | 'child_ids' => array_keys($category['boards']) |
||
| 177 | ); |
||
| 178 | $temp_boards = array_merge($temp_boards, array_values($category['boards'])); |
||
| 179 | |||
| 180 | // Include a list of boards per category for easy toggling. |
||
| 181 | $context['categories'][$category['id']]['child_ids'] = array_keys($category['boards']); |
||
| 182 | } |
||
| 183 | |||
| 184 | $max_boards = ceil(count($temp_boards) / 2); |
||
| 185 | if ($max_boards == 1) |
||
| 186 | $max_boards = 2; |
||
| 187 | |||
| 188 | // Now, alternate them so they can be shown left and right ;). |
||
| 189 | $context['board_columns'] = array(); |
||
| 190 | View Code Duplication | for ($i = 0; $i < $max_boards; $i++) |
|
| 191 | { |
||
| 192 | $context['board_columns'][] = $temp_boards[$i]; |
||
| 193 | if (isset($temp_boards[$i + $max_boards])) |
||
| 194 | $context['board_columns'][] = $temp_boards[$i + $max_boards]; |
||
| 195 | else |
||
| 196 | $context['board_columns'][] = array(); |
||
| 197 | } |
||
| 198 | |||
| 199 | if (!empty($_REQUEST['topic'])) |
||
| 200 | { |
||
| 201 | $context['search_params']['topic'] = (int) $_REQUEST['topic']; |
||
| 202 | $context['search_params']['show_complete'] = true; |
||
| 203 | } |
||
| 204 | if (!empty($context['search_params']['topic'])) |
||
| 205 | { |
||
| 206 | $context['search_params']['topic'] = (int) $context['search_params']['topic']; |
||
| 207 | |||
| 208 | $context['search_topic'] = array( |
||
| 209 | 'id' => $context['search_params']['topic'], |
||
| 210 | 'href' => $scripturl . '?topic=' . $context['search_params']['topic'] . '.0', |
||
| 211 | ); |
||
| 212 | |||
| 213 | $request = $smcFunc['db_query']('', ' |
||
| 214 | SELECT ms.subject |
||
| 215 | FROM {db_prefix}topics AS t |
||
| 216 | INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
||
| 217 | INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg) |
||
| 218 | WHERE t.id_topic = {int:search_topic_id} |
||
| 219 | AND {query_see_board}' . ($modSettings['postmod_active'] ? ' |
||
| 220 | AND t.approved = {int:is_approved_true}' : '') . ' |
||
| 221 | LIMIT 1', |
||
| 222 | array( |
||
| 223 | 'is_approved_true' => 1, |
||
| 224 | 'search_topic_id' => $context['search_params']['topic'], |
||
| 225 | ) |
||
| 226 | ); |
||
| 227 | |||
| 228 | if ($smcFunc['db_num_rows']($request) == 0) |
||
| 229 | fatal_lang_error('topic_gone', false); |
||
| 230 | |||
| 231 | list ($context['search_topic']['subject']) = $smcFunc['db_fetch_row']($request); |
||
| 232 | $smcFunc['db_free_result']($request); |
||
| 233 | |||
| 234 | $context['search_topic']['link'] = '<a href="' . $context['search_topic']['href'] . '">' . $context['search_topic']['subject'] . '</a>'; |
||
| 235 | } |
||
| 236 | |||
| 237 | $context['page_title'] = $txt['set_parameters']; |
||
| 238 | |||
| 239 | call_integration_hook('integrate_search'); |
||
| 240 | } |
||
| 241 | |||
| 242 | /** |
||
| 243 | * Gather the results and show them. |
||
| 244 | * What it does: |
||
| 245 | * - checks user input and searches the messages table for messages matching the query. |
||
| 246 | * - requires the search_posts permission. |
||
| 247 | * - uses the results sub template of the Search template. |
||
| 248 | * - uses the Search language file. |
||
| 249 | * - stores the results into the search cache. |
||
| 250 | * - show the results of the search query. |
||
| 251 | */ |
||
| 252 | function PlushSearch2() |
||
| 253 | { |
||
| 254 | global $scripturl, $modSettings, $sourcedir, $txt; |
||
| 255 | global $user_info, $context, $options, $messages_request, $boards_can; |
||
| 256 | global $excludedWords, $participants, $smcFunc; |
||
| 257 | |||
| 258 | // if comming from the quick search box, and we want to search on members, well we need to do that ;) |
||
| 259 | if (isset($_REQUEST['search_selection']) && $_REQUEST['search_selection'] === 'members') |
||
| 260 | redirectexit($scripturl . '?action=mlist;sa=search;fields=name,email;search=' . urlencode($_REQUEST['search'])); |
||
| 261 | |||
| 262 | View Code Duplication | if (!empty($context['load_average']) && !empty($modSettings['loadavg_search']) && $context['load_average'] >= $modSettings['loadavg_search']) |
|
| 263 | fatal_lang_error('loadavg_search_disabled', false); |
||
| 264 | |||
| 265 | // No, no, no... this is a bit hard on the server, so don't you go prefetching it! |
||
| 266 | View Code Duplication | if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') |
|
| 267 | { |
||
| 268 | ob_end_clean(); |
||
| 269 | header('HTTP/1.1 403 Forbidden'); |
||
| 270 | die; |
||
| 271 | } |
||
| 272 | |||
| 273 | $weight_factors = array( |
||
| 274 | 'frequency' => array( |
||
| 275 | 'search' => 'COUNT(*) / (MAX(t.num_replies) + 1)', |
||
| 276 | 'results' => '(t.num_replies + 1)', |
||
| 277 | ), |
||
| 278 | 'age' => array( |
||
| 279 | 'search' => 'CASE WHEN MAX(m.id_msg) < {int:min_msg} THEN 0 ELSE (MAX(m.id_msg) - {int:min_msg}) / {int:recent_message} END', |
||
| 280 | 'results' => 'CASE WHEN t.id_first_msg < {int:min_msg} THEN 0 ELSE (t.id_first_msg - {int:min_msg}) / {int:recent_message} END', |
||
| 281 | ), |
||
| 282 | 'length' => array( |
||
| 283 | 'search' => 'CASE WHEN MAX(t.num_replies) < {int:huge_topic_posts} THEN MAX(t.num_replies) / {int:huge_topic_posts} ELSE 1 END', |
||
| 284 | 'results' => 'CASE WHEN t.num_replies < {int:huge_topic_posts} THEN t.num_replies / {int:huge_topic_posts} ELSE 1 END', |
||
| 285 | ), |
||
| 286 | 'subject' => array( |
||
| 287 | 'search' => 0, |
||
| 288 | 'results' => 0, |
||
| 289 | ), |
||
| 290 | 'first_message' => array( |
||
| 291 | 'search' => 'CASE WHEN MIN(m.id_msg) = MAX(t.id_first_msg) THEN 1 ELSE 0 END', |
||
| 292 | ), |
||
| 293 | 'sticky' => array( |
||
| 294 | 'search' => 'MAX(t.is_sticky)', |
||
| 295 | 'results' => 't.is_sticky', |
||
| 296 | ), |
||
| 297 | ); |
||
| 298 | |||
| 299 | call_integration_hook('integrate_search_weights', array(&$weight_factors)); |
||
| 300 | |||
| 301 | $weight = array(); |
||
| 302 | $weight_total = 0; |
||
| 303 | foreach ($weight_factors as $weight_factor => $value) |
||
| 304 | { |
||
| 305 | $weight[$weight_factor] = empty($modSettings['search_weight_' . $weight_factor]) ? 0 : (int) $modSettings['search_weight_' . $weight_factor]; |
||
| 306 | $weight_total += $weight[$weight_factor]; |
||
| 307 | } |
||
| 308 | |||
| 309 | // Zero weight. Weightless :P. |
||
| 310 | if (empty($weight_total)) |
||
| 311 | fatal_lang_error('search_invalid_weights'); |
||
| 312 | |||
| 313 | // These vars don't require an interface, they're just here for tweaking. |
||
| 314 | $recentPercentage = 0.30; |
||
| 315 | $humungousTopicPosts = 200; |
||
| 316 | $maxMembersToSearch = 500; |
||
| 317 | $maxMessageResults = empty($modSettings['search_max_results']) ? 0 : $modSettings['search_max_results'] * 5; |
||
| 318 | |||
| 319 | // Start with no errors. |
||
| 320 | $context['search_errors'] = array(); |
||
| 321 | |||
| 322 | // Number of pages hard maximum - normally not set at all. |
||
| 323 | $modSettings['search_max_results'] = empty($modSettings['search_max_results']) ? 200 * $modSettings['search_results_per_page'] : (int) $modSettings['search_max_results']; |
||
| 324 | |||
| 325 | // Maximum length of the string. |
||
| 326 | $context['search_string_limit'] = 100; |
||
| 327 | |||
| 328 | loadLanguage('Search'); |
||
| 329 | if (!isset($_REQUEST['xml'])) |
||
| 330 | loadTemplate('Search'); |
||
| 331 | //If we're doing XML we need to use the results template regardless really. |
||
| 332 | else |
||
| 333 | $context['sub_template'] = 'results'; |
||
| 334 | |||
| 335 | // Are you allowed? |
||
| 336 | isAllowedTo('search_posts'); |
||
| 337 | |||
| 338 | require_once($sourcedir . '/Display.php'); |
||
| 339 | require_once($sourcedir . '/Subs-Package.php'); |
||
| 340 | |||
| 341 | // Search has a special database set. |
||
| 342 | db_extend('search'); |
||
| 343 | |||
| 344 | // Load up the search API we are going to use. |
||
| 345 | $searchAPI = findSearchAPI(); |
||
| 346 | |||
| 347 | // $search_params will carry all settings that differ from the default search parameters. |
||
| 348 | // That way, the URLs involved in a search page will be kept as short as possible. |
||
| 349 | $search_params = array(); |
||
| 350 | |||
| 351 | if (isset($_REQUEST['params'])) |
||
| 352 | { |
||
| 353 | // Due to IE's 2083 character limit, we have to compress long search strings |
||
| 354 | $temp_params = base64_decode(str_replace(array('-', '_', '.'), array('+', '/', '='), $_REQUEST['params'])); |
||
| 355 | |||
| 356 | // Test for gzuncompress failing |
||
| 357 | $temp_params2 = @gzuncompress($temp_params); |
||
| 358 | $temp_params = explode('|"|', (!empty($temp_params2) ? $temp_params2 : $temp_params)); |
||
| 359 | |||
| 360 | View Code Duplication | foreach ($temp_params as $i => $data) |
|
| 361 | { |
||
| 362 | @list($k, $v) = explode('|\'|', $data); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 363 | $search_params[$k] = $v; |
||
| 364 | } |
||
| 365 | |||
| 366 | if (isset($search_params['brd'])) |
||
| 367 | $search_params['brd'] = empty($search_params['brd']) ? array() : explode(',', $search_params['brd']); |
||
| 368 | } |
||
| 369 | |||
| 370 | // Store whether simple search was used (needed if the user wants to do another query). |
||
| 371 | View Code Duplication | if (!isset($search_params['advanced'])) |
|
| 372 | $search_params['advanced'] = empty($_REQUEST['advanced']) ? 0 : 1; |
||
| 373 | |||
| 374 | // 1 => 'allwords' (default, don't set as param) / 2 => 'anywords'. |
||
| 375 | View Code Duplication | if (!empty($search_params['searchtype']) || (!empty($_REQUEST['searchtype']) && $_REQUEST['searchtype'] == 2)) |
|
| 376 | $search_params['searchtype'] = 2; |
||
| 377 | |||
| 378 | // Minimum age of messages. Default to zero (don't set param in that case). |
||
| 379 | View Code Duplication | if (!empty($search_params['minage']) || (!empty($_REQUEST['minage']) && $_REQUEST['minage'] > 0)) |
|
| 380 | $search_params['minage'] = !empty($search_params['minage']) ? (int) $search_params['minage'] : (int) $_REQUEST['minage']; |
||
| 381 | |||
| 382 | // Maximum age of messages. Default to infinite (9999 days: param not set). |
||
| 383 | View Code Duplication | if (!empty($search_params['maxage']) || (!empty($_REQUEST['maxage']) && $_REQUEST['maxage'] < 9999)) |
|
| 384 | $search_params['maxage'] = !empty($search_params['maxage']) ? (int) $search_params['maxage'] : (int) $_REQUEST['maxage']; |
||
| 385 | |||
| 386 | // Searching a specific topic? |
||
| 387 | if (!empty($_REQUEST['topic']) || (!empty($_REQUEST['search_selection']) && $_REQUEST['search_selection'] == 'topic')) |
||
| 388 | { |
||
| 389 | $search_params['topic'] = empty($_REQUEST['search_selection']) ? (int) $_REQUEST['topic'] : (isset($_REQUEST['sd_topic']) ? (int) $_REQUEST['sd_topic'] : ''); |
||
| 390 | $search_params['show_complete'] = true; |
||
| 391 | } |
||
| 392 | elseif (!empty($search_params['topic'])) |
||
| 393 | $search_params['topic'] = (int) $search_params['topic']; |
||
| 394 | |||
| 395 | if (!empty($search_params['minage']) || !empty($search_params['maxage'])) |
||
| 396 | { |
||
| 397 | $request = $smcFunc['db_query']('', ' |
||
| 398 | SELECT ' . (empty($search_params['maxage']) ? '0, ' : 'COALESCE(MIN(id_msg), -1), ') . (empty($search_params['minage']) ? '0' : 'COALESCE(MAX(id_msg), -1)') . ' |
||
| 399 | FROM {db_prefix}messages |
||
| 400 | WHERE 1=1' . ($modSettings['postmod_active'] ? ' |
||
| 401 | AND approved = {int:is_approved_true}' : '') . (empty($search_params['minage']) ? '' : ' |
||
| 402 | AND poster_time <= {int:timestamp_minimum_age}') . (empty($search_params['maxage']) ? '' : ' |
||
| 403 | AND poster_time >= {int:timestamp_maximum_age}'), |
||
| 404 | array( |
||
| 405 | 'timestamp_minimum_age' => empty($search_params['minage']) ? 0 : time() - 86400 * $search_params['minage'], |
||
| 406 | 'timestamp_maximum_age' => empty($search_params['maxage']) ? 0 : time() - 86400 * $search_params['maxage'], |
||
| 407 | 'is_approved_true' => 1, |
||
| 408 | ) |
||
| 409 | ); |
||
| 410 | list ($minMsgID, $maxMsgID) = $smcFunc['db_fetch_row']($request); |
||
| 411 | if ($minMsgID < 0 || $maxMsgID < 0) |
||
| 412 | $context['search_errors']['no_messages_in_time_frame'] = true; |
||
| 413 | $smcFunc['db_free_result']($request); |
||
| 414 | } |
||
| 415 | |||
| 416 | // Default the user name to a wildcard matching every user (*). |
||
| 417 | View Code Duplication | if (!empty($search_params['userspec']) || (!empty($_REQUEST['userspec']) && $_REQUEST['userspec'] != '*')) |
|
| 418 | $search_params['userspec'] = isset($search_params['userspec']) ? $search_params['userspec'] : $_REQUEST['userspec']; |
||
| 419 | |||
| 420 | // If there's no specific user, then don't mention it in the main query. |
||
| 421 | if (empty($search_params['userspec'])) |
||
| 422 | $userQuery = ''; |
||
| 423 | else |
||
| 424 | { |
||
| 425 | $userString = strtr($smcFunc['htmlspecialchars']($search_params['userspec'], ENT_QUOTES), array('"' => '"')); |
||
| 426 | $userString = strtr($userString, array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_')); |
||
| 427 | |||
| 428 | preg_match_all('~"([^"]+)"~', $userString, $matches); |
||
| 429 | $possible_users = array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $userString))); |
||
| 430 | |||
| 431 | View Code Duplication | for ($k = 0, $n = count($possible_users); $k < $n; $k++) |
|
| 432 | { |
||
| 433 | $possible_users[$k] = trim($possible_users[$k]); |
||
| 434 | |||
| 435 | if (strlen($possible_users[$k]) == 0) |
||
| 436 | unset($possible_users[$k]); |
||
| 437 | } |
||
| 438 | |||
| 439 | // Create a list of database-escaped search names. |
||
| 440 | $realNameMatches = array(); |
||
| 441 | foreach ($possible_users as $possible_user) |
||
| 442 | $realNameMatches[] = $smcFunc['db_quote']( |
||
| 443 | '{string:possible_user}', |
||
| 444 | array( |
||
| 445 | 'possible_user' => $possible_user |
||
| 446 | ) |
||
| 447 | ); |
||
| 448 | |||
| 449 | // Retrieve a list of possible members. |
||
| 450 | $request = $smcFunc['db_query']('', ' |
||
| 451 | SELECT id_member |
||
| 452 | FROM {db_prefix}members |
||
| 453 | WHERE {raw:match_possible_users}', |
||
| 454 | array( |
||
| 455 | 'match_possible_users' => 'real_name LIKE ' . implode(' OR real_name LIKE ', $realNameMatches), |
||
| 456 | ) |
||
| 457 | ); |
||
| 458 | // Simply do nothing if there're too many members matching the criteria. |
||
| 459 | if ($smcFunc['db_num_rows']($request) > $maxMembersToSearch) |
||
| 460 | $userQuery = ''; |
||
| 461 | elseif ($smcFunc['db_num_rows']($request) == 0) |
||
| 462 | { |
||
| 463 | $userQuery = $smcFunc['db_quote']( |
||
| 464 | 'm.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})', |
||
| 465 | array( |
||
| 466 | 'id_member_guest' => 0, |
||
| 467 | 'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', $realNameMatches), |
||
| 468 | ) |
||
| 469 | ); |
||
| 470 | } |
||
| 471 | else |
||
| 472 | { |
||
| 473 | $memberlist = array(); |
||
| 474 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 475 | $memberlist[] = $row['id_member']; |
||
| 476 | $userQuery = $smcFunc['db_quote']( |
||
| 477 | '(m.id_member IN ({array_int:matched_members}) OR (m.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})))', |
||
| 478 | array( |
||
| 479 | 'matched_members' => $memberlist, |
||
| 480 | 'id_member_guest' => 0, |
||
| 481 | 'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', $realNameMatches), |
||
| 482 | ) |
||
| 483 | ); |
||
| 484 | } |
||
| 485 | $smcFunc['db_free_result']($request); |
||
| 486 | } |
||
| 487 | |||
| 488 | // If the boards were passed by URL (params=), temporarily put them back in $_REQUEST. |
||
| 489 | if (!empty($search_params['brd']) && is_array($search_params['brd'])) |
||
| 490 | $_REQUEST['brd'] = $search_params['brd']; |
||
| 491 | |||
| 492 | // Ensure that brd is an array. |
||
| 493 | if ((!empty($_REQUEST['brd']) && !is_array($_REQUEST['brd'])) || (!empty($_REQUEST['search_selection']) && $_REQUEST['search_selection'] == 'board')) |
||
| 494 | { |
||
| 495 | if (!empty($_REQUEST['brd'])) |
||
| 496 | $_REQUEST['brd'] = strpos($_REQUEST['brd'], ',') !== false ? explode(',', $_REQUEST['brd']) : array($_REQUEST['brd']); |
||
| 497 | else |
||
| 498 | $_REQUEST['brd'] = isset($_REQUEST['sd_brd']) ? array($_REQUEST['sd_brd']) : array(); |
||
| 499 | } |
||
| 500 | |||
| 501 | // Make sure all boards are integers. |
||
| 502 | if (!empty($_REQUEST['brd'])) |
||
| 503 | foreach ($_REQUEST['brd'] as $id => $brd) |
||
| 504 | $_REQUEST['brd'][$id] = (int) $brd; |
||
| 505 | |||
| 506 | // Special case for boards: searching just one topic? |
||
| 507 | if (!empty($search_params['topic'])) |
||
| 508 | { |
||
| 509 | $request = $smcFunc['db_query']('', ' |
||
| 510 | SELECT b.id_board |
||
| 511 | FROM {db_prefix}topics AS t |
||
| 512 | INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
||
| 513 | WHERE t.id_topic = {int:search_topic_id} |
||
| 514 | AND {query_see_board}' . ($modSettings['postmod_active'] ? ' |
||
| 515 | AND t.approved = {int:is_approved_true}' : '') . ' |
||
| 516 | LIMIT 1', |
||
| 517 | array( |
||
| 518 | 'search_topic_id' => $search_params['topic'], |
||
| 519 | 'is_approved_true' => 1, |
||
| 520 | ) |
||
| 521 | ); |
||
| 522 | |||
| 523 | if ($smcFunc['db_num_rows']($request) == 0) |
||
| 524 | fatal_lang_error('topic_gone', false); |
||
| 525 | |||
| 526 | $search_params['brd'] = array(); |
||
| 527 | list ($search_params['brd'][0]) = $smcFunc['db_fetch_row']($request); |
||
| 528 | $smcFunc['db_free_result']($request); |
||
| 529 | } |
||
| 530 | // Select all boards you've selected AND are allowed to see. |
||
| 531 | elseif ($user_info['is_admin'] && (!empty($search_params['advanced']) || !empty($_REQUEST['brd']))) |
||
| 532 | $search_params['brd'] = empty($_REQUEST['brd']) ? array() : $_REQUEST['brd']; |
||
| 533 | else |
||
| 534 | { |
||
| 535 | $see_board = empty($search_params['advanced']) ? 'query_wanna_see_board' : 'query_see_board'; |
||
| 536 | $request = $smcFunc['db_query']('', ' |
||
| 537 | SELECT b.id_board |
||
| 538 | FROM {db_prefix}boards AS b |
||
| 539 | WHERE {raw:boards_allowed_to_see} |
||
| 540 | AND redirect = {string:empty_string}' . (empty($_REQUEST['brd']) ? (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? ' |
||
| 541 | AND b.id_board != {int:recycle_board_id}' : '') : ' |
||
| 542 | AND b.id_board IN ({array_int:selected_search_boards})'), |
||
| 543 | array( |
||
| 544 | 'boards_allowed_to_see' => $user_info[$see_board], |
||
| 545 | 'empty_string' => '', |
||
| 546 | 'selected_search_boards' => empty($_REQUEST['brd']) ? array() : $_REQUEST['brd'], |
||
| 547 | 'recycle_board_id' => $modSettings['recycle_board'], |
||
| 548 | ) |
||
| 549 | ); |
||
| 550 | $search_params['brd'] = array(); |
||
| 551 | View Code Duplication | while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
| 552 | $search_params['brd'][] = $row['id_board']; |
||
| 553 | $smcFunc['db_free_result']($request); |
||
| 554 | |||
| 555 | // This error should pro'bly only happen for hackers. |
||
| 556 | if (empty($search_params['brd'])) |
||
| 557 | $context['search_errors']['no_boards_selected'] = true; |
||
| 558 | } |
||
| 559 | |||
| 560 | if (count($search_params['brd']) != 0) |
||
| 561 | { |
||
| 562 | foreach ($search_params['brd'] as $k => $v) |
||
| 563 | $search_params['brd'][$k] = (int) $v; |
||
| 564 | |||
| 565 | // If we've selected all boards, this parameter can be left empty. |
||
| 566 | $request = $smcFunc['db_query']('', ' |
||
| 567 | SELECT COUNT(*) |
||
| 568 | FROM {db_prefix}boards |
||
| 569 | WHERE redirect = {string:empty_string}', |
||
| 570 | array( |
||
| 571 | 'empty_string' => '', |
||
| 572 | ) |
||
| 573 | ); |
||
| 574 | list ($num_boards) = $smcFunc['db_fetch_row']($request); |
||
| 575 | $smcFunc['db_free_result']($request); |
||
| 576 | |||
| 577 | if (count($search_params['brd']) == $num_boards) |
||
| 578 | $boardQuery = ''; |
||
| 579 | elseif (count($search_params['brd']) == $num_boards - 1 && !empty($modSettings['recycle_board']) && !in_array($modSettings['recycle_board'], $search_params['brd'])) |
||
| 580 | $boardQuery = '!= ' . $modSettings['recycle_board']; |
||
| 581 | else |
||
| 582 | $boardQuery = 'IN (' . implode(', ', $search_params['brd']) . ')'; |
||
| 583 | } |
||
| 584 | else |
||
| 585 | $boardQuery = ''; |
||
| 586 | |||
| 587 | $search_params['show_complete'] = !empty($search_params['show_complete']) || !empty($_REQUEST['show_complete']); |
||
| 588 | $search_params['subject_only'] = !empty($search_params['subject_only']) || !empty($_REQUEST['subject_only']); |
||
| 589 | |||
| 590 | $context['compact'] = !$search_params['show_complete']; |
||
| 591 | |||
| 592 | // Get the sorting parameters right. Default to sort by relevance descending. |
||
| 593 | $sort_columns = array( |
||
| 594 | 'relevance', |
||
| 595 | 'num_replies', |
||
| 596 | 'id_msg', |
||
| 597 | ); |
||
| 598 | call_integration_hook('integrate_search_sort_columns', array(&$sort_columns)); |
||
| 599 | View Code Duplication | if (empty($search_params['sort']) && !empty($_REQUEST['sort'])) |
|
| 600 | list ($search_params['sort'], $search_params['sort_dir']) = array_pad(explode('|', $_REQUEST['sort']), 2, ''); |
||
| 601 | $search_params['sort'] = !empty($search_params['sort']) && in_array($search_params['sort'], $sort_columns) ? $search_params['sort'] : 'relevance'; |
||
| 602 | if (!empty($search_params['topic']) && $search_params['sort'] === 'num_replies') |
||
| 603 | $search_params['sort'] = 'id_msg'; |
||
| 604 | |||
| 605 | // Sorting direction: descending unless stated otherwise. |
||
| 606 | $search_params['sort_dir'] = !empty($search_params['sort_dir']) && $search_params['sort_dir'] == 'asc' ? 'asc' : 'desc'; |
||
| 607 | |||
| 608 | // Determine some values needed to calculate the relevance. |
||
| 609 | $minMsg = (int) ((1 - $recentPercentage) * $modSettings['maxMsgID']); |
||
| 610 | $recentMsg = $modSettings['maxMsgID'] - $minMsg; |
||
| 611 | |||
| 612 | // *** Parse the search query |
||
| 613 | call_integration_hook('integrate_search_params', array(&$search_params)); |
||
| 614 | |||
| 615 | /* |
||
| 616 | * Unfortunately, searching for words like this is going to be slow, so we're blacklisting them. |
||
| 617 | * |
||
| 618 | * @todo Setting to add more here? |
||
| 619 | * @todo Maybe only blacklist if they are the only word, or "any" is used? |
||
| 620 | */ |
||
| 621 | $blacklisted_words = array('img', 'url', 'quote', 'www', 'http', 'the', 'is', 'it', 'are', 'if'); |
||
| 622 | call_integration_hook('integrate_search_blacklisted_words', array(&$blacklisted_words)); |
||
| 623 | |||
| 624 | // What are we searching for? |
||
| 625 | if (empty($search_params['search'])) |
||
| 626 | { |
||
| 627 | if (isset($_GET['search'])) |
||
| 628 | $search_params['search'] = un_htmlspecialchars($_GET['search']); |
||
| 629 | elseif (isset($_POST['search'])) |
||
| 630 | $search_params['search'] = $_POST['search']; |
||
| 631 | else |
||
| 632 | $search_params['search'] = ''; |
||
| 633 | } |
||
| 634 | |||
| 635 | // Nothing?? |
||
| 636 | if (!isset($search_params['search']) || $search_params['search'] == '') |
||
| 637 | $context['search_errors']['invalid_search_string'] = true; |
||
| 638 | // Too long? |
||
| 639 | elseif ($smcFunc['strlen']($search_params['search']) > $context['search_string_limit']) |
||
| 640 | { |
||
| 641 | $context['search_errors']['string_too_long'] = true; |
||
| 642 | } |
||
| 643 | |||
| 644 | // Change non-word characters into spaces. |
||
| 645 | $stripped_query = preg_replace('~(?:[\x0B\0' . ($context['utf8'] ? '\x{A0}' : '\xA0') . '\t\r\s\n(){}\\[\\]<>!@$%^*.,:+=`\~\?/\\\\]+|&(?:amp|lt|gt|quot);)+~' . ($context['utf8'] ? 'u' : ''), ' ', $search_params['search']); |
||
| 646 | |||
| 647 | // Make the query lower case. It's gonna be case insensitive anyway. |
||
| 648 | $stripped_query = un_htmlspecialchars($smcFunc['strtolower']($stripped_query)); |
||
| 649 | |||
| 650 | // This (hidden) setting will do fulltext searching in the most basic way. |
||
| 651 | if (!empty($modSettings['search_simple_fulltext'])) |
||
| 652 | $stripped_query = strtr($stripped_query, array('"' => '')); |
||
| 653 | |||
| 654 | $no_regexp = preg_match('~&#(?:\d{1,7}|x[0-9a-fA-F]{1,6});~', $stripped_query) === 1; |
||
| 655 | |||
| 656 | // Extract phrase parts first (e.g. some words "this is a phrase" some more words.) |
||
| 657 | preg_match_all('/(?:^|\s)([-]?)"([^"]+)"(?:$|\s)/', $stripped_query, $matches, PREG_PATTERN_ORDER); |
||
| 658 | $phraseArray = $matches[2]; |
||
| 659 | |||
| 660 | // Remove the phrase parts and extract the words. |
||
| 661 | $wordArray = preg_replace('~(?:^|\s)(?:[-]?)"(?:[^"]+)"(?:$|\s)~' . ($context['utf8'] ? 'u' : ''), ' ', $search_params['search']); |
||
| 662 | $wordArray = explode(' ', $smcFunc['htmlspecialchars'](un_htmlspecialchars($wordArray), ENT_QUOTES)); |
||
| 663 | |||
| 664 | // A minus sign in front of a word excludes the word.... so... |
||
| 665 | $excludedWords = array(); |
||
| 666 | $excludedIndexWords = array(); |
||
| 667 | $excludedSubjectWords = array(); |
||
| 668 | $excludedPhrases = array(); |
||
| 669 | |||
| 670 | // .. first, we check for things like -"some words", but not "-some words". |
||
| 671 | View Code Duplication | foreach ($matches[1] as $index => $word) |
|
| 672 | { |
||
| 673 | if ($word === '-') |
||
| 674 | { |
||
| 675 | if (($word = trim($phraseArray[$index], '-_\' ')) !== '' && !in_array($word, $blacklisted_words)) |
||
| 676 | $excludedWords[] = $word; |
||
| 677 | unset($phraseArray[$index]); |
||
| 678 | } |
||
| 679 | } |
||
| 680 | |||
| 681 | // Now we look for -test, etc.... normaller. |
||
| 682 | foreach ($wordArray as $index => $word) |
||
| 683 | { |
||
| 684 | if (strpos(trim($word), '-') === 0) |
||
| 685 | { |
||
| 686 | if (($word = trim($word, '-_\' ')) !== '' && !in_array($word, $blacklisted_words)) |
||
| 687 | $excludedWords[] = $word; |
||
| 688 | unset($wordArray[$index]); |
||
| 689 | } |
||
| 690 | } |
||
| 691 | |||
| 692 | // The remaining words and phrases are all included. |
||
| 693 | $searchArray = array_merge($phraseArray, $wordArray); |
||
| 694 | |||
| 695 | $context['search_ignored'] = array(); |
||
| 696 | // Trim everything and make sure there are no words that are the same. |
||
| 697 | foreach ($searchArray as $index => $value) |
||
| 698 | { |
||
| 699 | // Skip anything practically empty. |
||
| 700 | if (($searchArray[$index] = trim($value, '-_\' ')) === '') |
||
| 701 | unset($searchArray[$index]); |
||
| 702 | // Skip blacklisted words. Make sure to note we skipped them in case we end up with nothing. |
||
| 703 | elseif (in_array($searchArray[$index], $blacklisted_words)) |
||
| 704 | { |
||
| 705 | $foundBlackListedWords = true; |
||
| 706 | unset($searchArray[$index]); |
||
| 707 | } |
||
| 708 | // Don't allow very, very short words. |
||
| 709 | elseif ($smcFunc['strlen']($value) < 2) |
||
| 710 | { |
||
| 711 | $context['search_ignored'][] = $value; |
||
| 712 | unset($searchArray[$index]); |
||
| 713 | } |
||
| 714 | } |
||
| 715 | $searchArray = array_slice(array_unique($searchArray), 0, 10); |
||
| 716 | |||
| 717 | // Create an array of replacements for highlighting. |
||
| 718 | $context['mark'] = array(); |
||
| 719 | foreach ($searchArray as $word) |
||
| 720 | $context['mark'][$word] = '<strong class="highlight">' . $word . '</strong>'; |
||
| 721 | |||
| 722 | // Initialize two arrays storing the words that have to be searched for. |
||
| 723 | $orParts = array(); |
||
| 724 | $searchWords = array(); |
||
| 725 | |||
| 726 | // Make sure at least one word is being searched for. |
||
| 727 | if (empty($searchArray)) |
||
| 728 | $context['search_errors']['invalid_search_string' . (!empty($foundBlackListedWords) ? '_blacklist' : '')] = true; |
||
| 729 | // All words/sentences must match. |
||
| 730 | elseif (empty($search_params['searchtype'])) |
||
| 731 | $orParts[0] = $searchArray; |
||
| 732 | // Any word/sentence must match. |
||
| 733 | else |
||
| 734 | foreach ($searchArray as $index => $value) |
||
| 735 | $orParts[$index] = array($value); |
||
| 736 | |||
| 737 | // Don't allow duplicate error messages if one string is too short. |
||
| 738 | if (isset($context['search_errors']['search_string_small_words'], $context['search_errors']['invalid_search_string'])) |
||
| 739 | unset($context['search_errors']['invalid_search_string']); |
||
| 740 | // Make sure the excluded words are in all or-branches. |
||
| 741 | foreach ($orParts as $orIndex => $andParts) |
||
| 742 | foreach ($excludedWords as $word) |
||
| 743 | $orParts[$orIndex][] = $word; |
||
| 744 | |||
| 745 | // Determine the or-branches and the fulltext search words. |
||
| 746 | foreach ($orParts as $orIndex => $andParts) |
||
| 747 | { |
||
| 748 | $searchWords[$orIndex] = array( |
||
| 749 | 'indexed_words' => array(), |
||
| 750 | 'words' => array(), |
||
| 751 | 'subject_words' => array(), |
||
| 752 | 'all_words' => array(), |
||
| 753 | 'complex_words' => array(), |
||
| 754 | ); |
||
| 755 | |||
| 756 | // Sort the indexed words (large words -> small words -> excluded words). |
||
| 757 | if ($searchAPI->supportsMethod('searchSort')) |
||
| 758 | usort($orParts[$orIndex], 'searchSort'); |
||
| 759 | |||
| 760 | foreach ($orParts[$orIndex] as $word) |
||
| 761 | { |
||
| 762 | $is_excluded = in_array($word, $excludedWords); |
||
| 763 | |||
| 764 | $searchWords[$orIndex]['all_words'][] = $word; |
||
| 765 | |||
| 766 | $subjectWords = text2words($word); |
||
| 767 | if (!$is_excluded || count($subjectWords) === 1) |
||
| 768 | { |
||
| 769 | $searchWords[$orIndex]['subject_words'] = array_merge($searchWords[$orIndex]['subject_words'], $subjectWords); |
||
| 770 | if ($is_excluded) |
||
| 771 | $excludedSubjectWords = array_merge($excludedSubjectWords, $subjectWords); |
||
| 772 | } |
||
| 773 | else |
||
| 774 | $excludedPhrases[] = $word; |
||
| 775 | |||
| 776 | // Have we got indexes to prepare? |
||
| 777 | if ($searchAPI->supportsMethod('prepareIndexes')) |
||
| 778 | $searchAPI->prepareIndexes($word, $searchWords[$orIndex], $excludedIndexWords, $is_excluded); |
||
| 779 | } |
||
| 780 | |||
| 781 | // Search_force_index requires all AND parts to have at least one fulltext word. |
||
| 782 | if (!empty($modSettings['search_force_index']) && empty($searchWords[$orIndex]['indexed_words'])) |
||
| 783 | { |
||
| 784 | $context['search_errors']['query_not_specific_enough'] = true; |
||
| 785 | break; |
||
| 786 | } |
||
| 787 | elseif ($search_params['subject_only'] && empty($searchWords[$orIndex]['subject_words']) && empty($excludedSubjectWords)) |
||
| 788 | { |
||
| 789 | $context['search_errors']['query_not_specific_enough'] = true; |
||
| 790 | break; |
||
| 791 | } |
||
| 792 | |||
| 793 | // Make sure we aren't searching for too many indexed words. |
||
| 794 | else |
||
| 795 | { |
||
| 796 | $searchWords[$orIndex]['indexed_words'] = array_slice($searchWords[$orIndex]['indexed_words'], 0, 7); |
||
| 797 | $searchWords[$orIndex]['subject_words'] = array_slice($searchWords[$orIndex]['subject_words'], 0, 7); |
||
| 798 | $searchWords[$orIndex]['words'] = array_slice($searchWords[$orIndex]['words'], 0, 4); |
||
| 799 | } |
||
| 800 | } |
||
| 801 | |||
| 802 | // *** Spell checking |
||
| 803 | $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && (function_exists('pspell_new') || (function_exists('enchant_broker_init') && ($txt['lang_charset'] == 'UTF-8' || function_exists('iconv')))); |
||
| 804 | if ($context['show_spellchecking']) |
||
| 805 | { |
||
| 806 | require_once($sourcedir . '/Subs-Post.php'); |
||
| 807 | |||
| 808 | // Don't hardcode spellchecking functions! |
||
| 809 | $link = spell_init(); |
||
| 810 | |||
| 811 | $did_you_mean = array('search' => array(), 'display' => array()); |
||
| 812 | $found_misspelling = false; |
||
| 813 | foreach ($searchArray as $word) |
||
| 814 | { |
||
| 815 | if (empty($link)) |
||
| 816 | continue; |
||
| 817 | |||
| 818 | // Don't check phrases. |
||
| 819 | if (preg_match('~^\w+$~', $word) === 0) |
||
| 820 | { |
||
| 821 | $did_you_mean['search'][] = '"' . $word . '"'; |
||
| 822 | $did_you_mean['display'][] = '"' . $smcFunc['htmlspecialchars']($word) . '"'; |
||
| 823 | continue; |
||
| 824 | } |
||
| 825 | // For some strange reason spell check can crash PHP on decimals. |
||
| 826 | elseif (preg_match('~\d~', $word) === 1) |
||
| 827 | { |
||
| 828 | $did_you_mean['search'][] = $word; |
||
| 829 | $did_you_mean['display'][] = $smcFunc['htmlspecialchars']($word); |
||
| 830 | continue; |
||
| 831 | } |
||
| 832 | View Code Duplication | elseif (spell_check($link, $word)) |
|
| 833 | { |
||
| 834 | $did_you_mean['search'][] = $word; |
||
| 835 | $did_you_mean['display'][] = $smcFunc['htmlspecialchars']($word); |
||
| 836 | continue; |
||
| 837 | } |
||
| 838 | |||
| 839 | $suggestions = spell_suggest($link, $word); |
||
| 840 | foreach ($suggestions as $i => $s) |
||
| 841 | { |
||
| 842 | // Search is case insensitive. |
||
| 843 | if ($smcFunc['strtolower']($s) == $smcFunc['strtolower']($word)) |
||
| 844 | unset($suggestions[$i]); |
||
| 845 | // Plus, don't suggest something the user thinks is rude! |
||
| 846 | elseif ($suggestions[$i] != censorText($s)) |
||
| 847 | unset($suggestions[$i]); |
||
| 848 | } |
||
| 849 | |||
| 850 | // Anything found? If so, correct it! |
||
| 851 | if (!empty($suggestions)) |
||
| 852 | { |
||
| 853 | $suggestions = array_values($suggestions); |
||
| 854 | $did_you_mean['search'][] = $suggestions[0]; |
||
| 855 | $did_you_mean['display'][] = '<em><strong>' . $smcFunc['htmlspecialchars']($suggestions[0]) . '</strong></em>'; |
||
| 856 | $found_misspelling = true; |
||
| 857 | } |
||
| 858 | View Code Duplication | else |
|
| 859 | { |
||
| 860 | $did_you_mean['search'][] = $word; |
||
| 861 | $did_you_mean['display'][] = $smcFunc['htmlspecialchars']($word); |
||
| 862 | } |
||
| 863 | } |
||
| 864 | |||
| 865 | if ($found_misspelling) |
||
| 866 | { |
||
| 867 | // Don't spell check excluded words, but add them still... |
||
| 868 | $temp_excluded = array('search' => array(), 'display' => array()); |
||
| 869 | foreach ($excludedWords as $word) |
||
| 870 | { |
||
| 871 | if (preg_match('~^\w+$~', $word) == 0) |
||
| 872 | { |
||
| 873 | $temp_excluded['search'][] = '-"' . $word . '"'; |
||
| 874 | $temp_excluded['display'][] = '-"' . $smcFunc['htmlspecialchars']($word) . '"'; |
||
| 875 | } |
||
| 876 | else |
||
| 877 | { |
||
| 878 | $temp_excluded['search'][] = '-' . $word; |
||
| 879 | $temp_excluded['display'][] = '-' . $smcFunc['htmlspecialchars']($word); |
||
| 880 | } |
||
| 881 | } |
||
| 882 | |||
| 883 | $did_you_mean['search'] = array_merge($did_you_mean['search'], $temp_excluded['search']); |
||
| 884 | $did_you_mean['display'] = array_merge($did_you_mean['display'], $temp_excluded['display']); |
||
| 885 | |||
| 886 | $temp_params = $search_params; |
||
| 887 | $temp_params['search'] = implode(' ', $did_you_mean['search']); |
||
| 888 | if (isset($temp_params['brd'])) |
||
| 889 | $temp_params['brd'] = implode(',', $temp_params['brd']); |
||
| 890 | $context['params'] = array(); |
||
| 891 | foreach ($temp_params as $k => $v) |
||
| 892 | $context['did_you_mean_params'][] = $k . '|\'|' . $v; |
||
| 893 | $context['did_you_mean_params'] = base64_encode(implode('|"|', $context['did_you_mean_params'])); |
||
| 894 | $context['did_you_mean'] = implode(' ', $did_you_mean['display']); |
||
| 895 | } |
||
| 896 | } |
||
| 897 | |||
| 898 | // Let the user adjust the search query, should they wish? |
||
| 899 | $context['search_params'] = $search_params; |
||
| 900 | View Code Duplication | if (isset($context['search_params']['search'])) |
|
| 901 | $context['search_params']['search'] = $smcFunc['htmlspecialchars']($context['search_params']['search']); |
||
| 902 | View Code Duplication | if (isset($context['search_params']['userspec'])) |
|
| 903 | $context['search_params']['userspec'] = $smcFunc['htmlspecialchars']($context['search_params']['userspec']); |
||
| 904 | |||
| 905 | // Do we have captcha enabled? |
||
| 906 | if ($user_info['is_guest'] && !empty($modSettings['search_enable_captcha']) && empty($_SESSION['ss_vv_passed']) && (empty($_SESSION['last_ss']) || $_SESSION['last_ss'] != $search_params['search'])) |
||
| 907 | { |
||
| 908 | // If we come from another search box tone down the error... |
||
| 909 | if (!isset($_REQUEST['search_vv'])) |
||
| 910 | $context['search_errors']['need_verification_code'] = true; |
||
| 911 | else |
||
| 912 | { |
||
| 913 | require_once($sourcedir . '/Subs-Editor.php'); |
||
| 914 | $verificationOptions = array( |
||
| 915 | 'id' => 'search', |
||
| 916 | ); |
||
| 917 | $context['require_verification'] = create_control_verification($verificationOptions, true); |
||
| 918 | |||
| 919 | if (is_array($context['require_verification'])) |
||
| 920 | { |
||
| 921 | foreach ($context['require_verification'] as $error) |
||
| 922 | $context['search_errors'][$error] = true; |
||
| 923 | } |
||
| 924 | // Don't keep asking for it - they've proven themselves worthy. |
||
| 925 | else |
||
| 926 | $_SESSION['ss_vv_passed'] = true; |
||
| 927 | } |
||
| 928 | } |
||
| 929 | |||
| 930 | // *** Encode all search params |
||
| 931 | |||
| 932 | // All search params have been checked, let's compile them to a single string... made less simple by PHP 4.3.9 and below. |
||
| 933 | $temp_params = $search_params; |
||
| 934 | if (isset($temp_params['brd'])) |
||
| 935 | $temp_params['brd'] = implode(',', $temp_params['brd']); |
||
| 936 | $context['params'] = array(); |
||
| 937 | foreach ($temp_params as $k => $v) |
||
| 938 | $context['params'][] = $k . '|\'|' . $v; |
||
| 939 | |||
| 940 | if (!empty($context['params'])) |
||
| 941 | { |
||
| 942 | // Due to old IE's 2083 character limit, we have to compress long search strings |
||
| 943 | $params = @gzcompress(implode('|"|', $context['params'])); |
||
| 944 | // Gzcompress failed, use try non-gz |
||
| 945 | if (empty($params)) |
||
| 946 | $params = implode('|"|', $context['params']); |
||
| 947 | // Base64 encode, then replace +/= with uri safe ones that can be reverted |
||
| 948 | $context['params'] = str_replace(array('+', '/', '='), array('-', '_', '.'), base64_encode($params)); |
||
| 949 | } |
||
| 950 | |||
| 951 | // ... and add the links to the link tree. |
||
| 952 | $context['linktree'][] = array( |
||
| 953 | 'url' => $scripturl . '?action=search;params=' . $context['params'], |
||
| 954 | 'name' => $txt['search'] |
||
| 955 | ); |
||
| 956 | $context['linktree'][] = array( |
||
| 957 | 'url' => $scripturl . '?action=search2;params=' . $context['params'], |
||
| 958 | 'name' => $txt['search_results'] |
||
| 959 | ); |
||
| 960 | |||
| 961 | // *** A last error check |
||
| 962 | call_integration_hook('integrate_search_errors'); |
||
| 963 | |||
| 964 | // One or more search errors? Go back to the first search screen. |
||
| 965 | View Code Duplication | if (!empty($context['search_errors'])) |
|
| 966 | { |
||
| 967 | $_REQUEST['params'] = $context['params']; |
||
| 968 | return PlushSearch1(); |
||
| 969 | } |
||
| 970 | |||
| 971 | // Spam me not, Spam-a-lot? |
||
| 972 | if (empty($_SESSION['last_ss']) || $_SESSION['last_ss'] != $search_params['search']) |
||
| 973 | spamProtection('search'); |
||
| 974 | // Store the last search string to allow pages of results to be browsed. |
||
| 975 | $_SESSION['last_ss'] = $search_params['search']; |
||
| 976 | |||
| 977 | // *** Reserve an ID for caching the search results. |
||
| 978 | $query_params = array_merge($search_params, array( |
||
| 979 | 'min_msg_id' => isset($minMsgID) ? (int) $minMsgID : 0, |
||
| 980 | 'max_msg_id' => isset($maxMsgID) ? (int) $maxMsgID : 0, |
||
| 981 | 'memberlist' => !empty($memberlist) ? $memberlist : array(), |
||
| 982 | )); |
||
| 983 | |||
| 984 | // Can this search rely on the API given the parameters? |
||
| 985 | if ($searchAPI->supportsMethod('searchQuery', $query_params)) |
||
| 986 | { |
||
| 987 | $participants = array(); |
||
| 988 | $searchArray = array(); |
||
| 989 | |||
| 990 | $num_results = $searchAPI->searchQuery($query_params, $searchWords, $excludedIndexWords, $participants, $searchArray); |
||
| 991 | } |
||
| 992 | |||
| 993 | // Update the cache if the current search term is not yet cached. |
||
| 994 | else |
||
| 995 | { |
||
| 996 | $update_cache = empty($_SESSION['search_cache']) || ($_SESSION['search_cache']['params'] != $context['params']); |
||
| 997 | if ($update_cache) |
||
| 998 | { |
||
| 999 | // Increase the pointer... |
||
| 1000 | $modSettings['search_pointer'] = empty($modSettings['search_pointer']) ? 0 : (int) $modSettings['search_pointer']; |
||
| 1001 | // ...and store it right off. |
||
| 1002 | updateSettings(array('search_pointer' => $modSettings['search_pointer'] >= 255 ? 0 : $modSettings['search_pointer'] + 1)); |
||
| 1003 | // As long as you don't change the parameters, the cache result is yours. |
||
| 1004 | $_SESSION['search_cache'] = array( |
||
| 1005 | 'id_search' => $modSettings['search_pointer'], |
||
| 1006 | 'num_results' => -1, |
||
| 1007 | 'params' => $context['params'], |
||
| 1008 | ); |
||
| 1009 | |||
| 1010 | // Clear the previous cache of the final results cache. |
||
| 1011 | $smcFunc['db_search_query']('delete_log_search_results', ' |
||
| 1012 | DELETE FROM {db_prefix}log_search_results |
||
| 1013 | WHERE id_search = {int:search_id}', |
||
| 1014 | array( |
||
| 1015 | 'search_id' => $_SESSION['search_cache']['id_search'], |
||
| 1016 | ) |
||
| 1017 | ); |
||
| 1018 | |||
| 1019 | if ($search_params['subject_only']) |
||
| 1020 | { |
||
| 1021 | // We do this to try and avoid duplicate keys on databases not supporting INSERT IGNORE. |
||
| 1022 | $inserts = array(); |
||
| 1023 | foreach ($searchWords as $orIndex => $words) |
||
| 1024 | { |
||
| 1025 | $subject_query_params = array(); |
||
| 1026 | $subject_query = array( |
||
| 1027 | 'from' => '{db_prefix}topics AS t', |
||
| 1028 | 'inner_join' => array(), |
||
| 1029 | 'left_join' => array(), |
||
| 1030 | 'where' => array(), |
||
| 1031 | ); |
||
| 1032 | |||
| 1033 | if ($modSettings['postmod_active']) |
||
| 1034 | $subject_query['where'][] = 't.approved = {int:is_approved}'; |
||
| 1035 | |||
| 1036 | $numTables = 0; |
||
| 1037 | $prev_join = 0; |
||
| 1038 | $numSubjectResults = 0; |
||
| 1039 | foreach ($words['subject_words'] as $subjectWord) |
||
| 1040 | { |
||
| 1041 | $numTables++; |
||
| 1042 | if (in_array($subjectWord, $excludedSubjectWords)) |
||
| 1043 | { |
||
| 1044 | $subject_query['left_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_words_' . $numTables . '_wild}' : '= {string:subject_words_' . $numTables . '}') . ' AND subj' . $numTables . '.id_topic = t.id_topic)'; |
||
| 1045 | $subject_query['where'][] = '(subj' . $numTables . '.word IS NULL)'; |
||
| 1046 | } |
||
| 1047 | else |
||
| 1048 | { |
||
| 1049 | $subject_query['inner_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.id_topic = ' . ($prev_join === 0 ? 't' : 'subj' . $prev_join) . '.id_topic)'; |
||
| 1050 | $subject_query['where'][] = 'subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_words_' . $numTables . '_wild}' : '= {string:subject_words_' . $numTables . '}'); |
||
| 1051 | $prev_join = $numTables; |
||
| 1052 | } |
||
| 1053 | $subject_query_params['subject_words_' . $numTables] = $subjectWord; |
||
| 1054 | $subject_query_params['subject_words_' . $numTables . '_wild'] = '%' . $subjectWord . '%'; |
||
| 1055 | } |
||
| 1056 | |||
| 1057 | if (!empty($userQuery)) |
||
| 1058 | { |
||
| 1059 | if ($subject_query['from'] != '{db_prefix}messages AS m') |
||
| 1060 | { |
||
| 1061 | $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_topic = t.id_topic)'; |
||
| 1062 | } |
||
| 1063 | $subject_query['where'][] = $userQuery; |
||
| 1064 | } |
||
| 1065 | if (!empty($search_params['topic'])) |
||
| 1066 | $subject_query['where'][] = 't.id_topic = ' . $search_params['topic']; |
||
| 1067 | if (!empty($minMsgID)) |
||
| 1068 | $subject_query['where'][] = 't.id_first_msg >= ' . $minMsgID; |
||
| 1069 | if (!empty($maxMsgID)) |
||
| 1070 | $subject_query['where'][] = 't.id_last_msg <= ' . $maxMsgID; |
||
| 1071 | if (!empty($boardQuery)) |
||
| 1072 | $subject_query['where'][] = 't.id_board ' . $boardQuery; |
||
| 1073 | if (!empty($excludedPhrases)) |
||
| 1074 | { |
||
| 1075 | if ($subject_query['from'] != '{db_prefix}messages AS m') |
||
| 1076 | { |
||
| 1077 | $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)'; |
||
| 1078 | } |
||
| 1079 | $count = 0; |
||
| 1080 | foreach ($excludedPhrases as $phrase) |
||
| 1081 | { |
||
| 1082 | $subject_query['where'][] = 'm.subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:excluded_phrases_' . $count . '}'; |
||
| 1083 | $subject_query_params['excluded_phrases_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\[\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . '[[:>:]]'; |
||
| 1084 | } |
||
| 1085 | } |
||
| 1086 | call_integration_hook('integrate_subject_only_search_query', array(&$subject_query, &$subject_query_params)); |
||
| 1087 | |||
| 1088 | $relevance = '1000 * ('; |
||
| 1089 | View Code Duplication | foreach ($weight_factors as $type => $value) |
|
| 1090 | { |
||
| 1091 | $relevance .= $weight[$type]; |
||
| 1092 | if (!empty($value['results'])) |
||
| 1093 | $relevance .= ' * ' . $value['results']; |
||
| 1094 | $relevance .= ' + '; |
||
| 1095 | } |
||
| 1096 | $relevance = substr($relevance, 0, -3) . ') / ' . $weight_total . ' AS relevance'; |
||
| 1097 | |||
| 1098 | $ignoreRequest = $smcFunc['db_search_query']('insert_log_search_results_subject', |
||
| 1099 | ($smcFunc['db_support_ignore'] ? ' |
||
| 1100 | INSERT IGNORE INTO {db_prefix}log_search_results |
||
| 1101 | (id_search, id_topic, relevance, id_msg, num_matches)' : '') . ' |
||
| 1102 | SELECT |
||
| 1103 | {int:id_search}, |
||
| 1104 | t.id_topic, |
||
| 1105 | ' . $relevance. ', |
||
| 1106 | ' . (empty($userQuery) ? 't.id_first_msg' : 'm.id_msg') . ', |
||
| 1107 | 1 |
||
| 1108 | FROM ' . $subject_query['from'] . (empty($subject_query['inner_join']) ? '' : ' |
||
| 1109 | INNER JOIN ' . implode(' |
||
| 1110 | INNER JOIN ', $subject_query['inner_join'])) . (empty($subject_query['left_join']) ? '' : ' |
||
| 1111 | LEFT JOIN ' . implode(' |
||
| 1112 | LEFT JOIN ', $subject_query['left_join'])) . ' |
||
| 1113 | WHERE ' . implode(' |
||
| 1114 | AND ', $subject_query['where']) . (empty($modSettings['search_max_results']) ? '' : ' |
||
| 1115 | LIMIT ' . ($modSettings['search_max_results'] - $numSubjectResults)), |
||
| 1116 | array_merge($subject_query_params, array( |
||
| 1117 | 'id_search' => $_SESSION['search_cache']['id_search'], |
||
| 1118 | 'min_msg' => $minMsg, |
||
| 1119 | 'recent_message' => $recentMsg, |
||
| 1120 | 'huge_topic_posts' => $humungousTopicPosts, |
||
| 1121 | 'is_approved' => 1, |
||
| 1122 | )) |
||
| 1123 | ); |
||
| 1124 | |||
| 1125 | // If the database doesn't support IGNORE to make this fast we need to do some tracking. |
||
| 1126 | View Code Duplication | if (!$smcFunc['db_support_ignore']) |
|
| 1127 | { |
||
| 1128 | while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) |
||
| 1129 | { |
||
| 1130 | // No duplicates! |
||
| 1131 | if (isset($inserts[$row[1]])) |
||
| 1132 | continue; |
||
| 1133 | |||
| 1134 | foreach ($row as $key => $value) |
||
| 1135 | $inserts[$row[1]][] = (int) $row[$key]; |
||
| 1136 | } |
||
| 1137 | $smcFunc['db_free_result']($ignoreRequest); |
||
| 1138 | $numSubjectResults = count($inserts); |
||
| 1139 | } |
||
| 1140 | else |
||
| 1141 | $numSubjectResults += $smcFunc['db_affected_rows'](); |
||
| 1142 | |||
| 1143 | if (!empty($modSettings['search_max_results']) && $numSubjectResults >= $modSettings['search_max_results']) |
||
| 1144 | break; |
||
| 1145 | } |
||
| 1146 | |||
| 1147 | // If there's data to be inserted for non-IGNORE databases do it here! |
||
| 1148 | View Code Duplication | if (!empty($inserts)) |
|
| 1149 | { |
||
| 1150 | $smcFunc['db_insert']('', |
||
| 1151 | '{db_prefix}log_search_results', |
||
| 1152 | array('id_search' => 'int', 'id_topic' => 'int', 'relevance' => 'int', 'id_msg' => 'int', 'num_matches' => 'int'), |
||
| 1153 | $inserts, |
||
| 1154 | array('id_search', 'id_topic') |
||
| 1155 | ); |
||
| 1156 | } |
||
| 1157 | |||
| 1158 | $_SESSION['search_cache']['num_results'] = $numSubjectResults; |
||
|
0 ignored issues
–
show
The variable
$numSubjectResults does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 1159 | } |
||
| 1160 | else |
||
| 1161 | { |
||
| 1162 | $main_query = array( |
||
| 1163 | 'select' => array( |
||
| 1164 | 'id_search' => $_SESSION['search_cache']['id_search'], |
||
| 1165 | 'relevance' => '0', |
||
| 1166 | ), |
||
| 1167 | 'weights' => array(), |
||
| 1168 | 'from' => '{db_prefix}topics AS t', |
||
| 1169 | 'inner_join' => array( |
||
| 1170 | '{db_prefix}messages AS m ON (m.id_topic = t.id_topic)' |
||
| 1171 | ), |
||
| 1172 | 'left_join' => array(), |
||
| 1173 | 'where' => array(), |
||
| 1174 | 'group_by' => array(), |
||
| 1175 | 'parameters' => array( |
||
| 1176 | 'min_msg' => $minMsg, |
||
| 1177 | 'recent_message' => $recentMsg, |
||
| 1178 | 'huge_topic_posts' => $humungousTopicPosts, |
||
| 1179 | 'is_approved' => 1, |
||
| 1180 | ), |
||
| 1181 | ); |
||
| 1182 | |||
| 1183 | if (empty($search_params['topic']) && empty($search_params['show_complete'])) |
||
| 1184 | { |
||
| 1185 | $main_query['select']['id_topic'] = 't.id_topic'; |
||
| 1186 | $main_query['select']['id_msg'] = 'MAX(m.id_msg) AS id_msg'; |
||
| 1187 | $main_query['select']['num_matches'] = 'COUNT(*) AS num_matches'; |
||
| 1188 | |||
| 1189 | $main_query['weights'] = $weight_factors; |
||
| 1190 | |||
| 1191 | $main_query['group_by'][] = 't.id_topic'; |
||
| 1192 | } |
||
| 1193 | else |
||
| 1194 | { |
||
| 1195 | // This is outrageous! |
||
| 1196 | $main_query['select']['id_topic'] = 'm.id_msg AS id_topic'; |
||
| 1197 | $main_query['select']['id_msg'] = 'm.id_msg'; |
||
| 1198 | $main_query['select']['num_matches'] = '1 AS num_matches'; |
||
| 1199 | |||
| 1200 | $main_query['weights'] = array( |
||
| 1201 | 'age' => array( |
||
| 1202 | 'search' => '((m.id_msg - t.id_first_msg) / CASE WHEN t.id_last_msg = t.id_first_msg THEN 1 ELSE t.id_last_msg - t.id_first_msg END)', |
||
| 1203 | ), |
||
| 1204 | 'first_message' => array( |
||
| 1205 | 'search' => 'CASE WHEN m.id_msg = t.id_first_msg THEN 1 ELSE 0 END', |
||
| 1206 | ), |
||
| 1207 | ); |
||
| 1208 | |||
| 1209 | View Code Duplication | if (!empty($search_params['topic'])) |
|
| 1210 | { |
||
| 1211 | $main_query['where'][] = 't.id_topic = {int:topic}'; |
||
| 1212 | $main_query['parameters']['topic'] = $search_params['topic']; |
||
| 1213 | } |
||
| 1214 | if (!empty($search_params['show_complete'])) |
||
| 1215 | $main_query['group_by'][] = 'm.id_msg, t.id_first_msg, t.id_last_msg'; |
||
| 1216 | } |
||
| 1217 | |||
| 1218 | // *** Get the subject results. |
||
| 1219 | $numSubjectResults = 0; |
||
| 1220 | if (empty($search_params['topic'])) |
||
| 1221 | { |
||
| 1222 | $inserts = array(); |
||
| 1223 | // Create a temporary table to store some preliminary results in. |
||
| 1224 | $smcFunc['db_search_query']('drop_tmp_log_search_topics', ' |
||
| 1225 | DROP TABLE IF EXISTS {db_prefix}tmp_log_search_topics', |
||
| 1226 | array( |
||
| 1227 | 'db_error_skip' => true, |
||
| 1228 | ) |
||
| 1229 | ); |
||
| 1230 | $createTemporary = $smcFunc['db_search_query']('create_tmp_log_search_topics', ' |
||
| 1231 | CREATE TEMPORARY TABLE {db_prefix}tmp_log_search_topics ( |
||
| 1232 | id_topic mediumint(8) unsigned NOT NULL default {string:string_zero}, |
||
| 1233 | PRIMARY KEY (id_topic) |
||
| 1234 | ) ENGINE=MEMORY', |
||
| 1235 | array( |
||
| 1236 | 'string_zero' => '0', |
||
| 1237 | 'db_error_skip' => true, |
||
| 1238 | ) |
||
| 1239 | ) !== false; |
||
| 1240 | |||
| 1241 | // Clean up some previous cache. |
||
| 1242 | if (!$createTemporary) |
||
| 1243 | $smcFunc['db_search_query']('delete_log_search_topics', ' |
||
| 1244 | DELETE FROM {db_prefix}log_search_topics |
||
| 1245 | WHERE id_search = {int:search_id}', |
||
| 1246 | array( |
||
| 1247 | 'search_id' => $_SESSION['search_cache']['id_search'], |
||
| 1248 | ) |
||
| 1249 | ); |
||
| 1250 | |||
| 1251 | foreach ($searchWords as $orIndex => $words) |
||
| 1252 | { |
||
| 1253 | $subject_query = array( |
||
| 1254 | 'from' => '{db_prefix}topics AS t', |
||
| 1255 | 'inner_join' => array(), |
||
| 1256 | 'left_join' => array(), |
||
| 1257 | 'where' => array(), |
||
| 1258 | 'params' => array(), |
||
| 1259 | ); |
||
| 1260 | |||
| 1261 | $numTables = 0; |
||
| 1262 | $prev_join = 0; |
||
| 1263 | $count = 0; |
||
| 1264 | $excluded = false; |
||
| 1265 | foreach ($words['subject_words'] as $subjectWord) |
||
| 1266 | { |
||
| 1267 | $numTables++; |
||
| 1268 | if (in_array($subjectWord, $excludedSubjectWords)) |
||
| 1269 | { |
||
| 1270 | if (($subject_query['from'] != '{db_prefix}messages AS m') && !$excluded) |
||
| 1271 | { |
||
| 1272 | $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)'; |
||
| 1273 | $excluded = true; |
||
| 1274 | } |
||
| 1275 | $subject_query['left_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_not_' . $count . '}' : '= {string:subject_not_' . $count . '}') . ' AND subj' . $numTables . '.id_topic = t.id_topic)'; |
||
| 1276 | $subject_query['params']['subject_not_' . $count] = empty($modSettings['search_match_words']) ? '%' . $subjectWord . '%' : $subjectWord; |
||
| 1277 | |||
| 1278 | $subject_query['where'][] = '(subj' . $numTables . '.word IS NULL)'; |
||
| 1279 | $subject_query['where'][] = 'm.body NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:body_not_' . $count . '}'; |
||
| 1280 | $subject_query['params']['body_not_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($subjectWord, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\[\]$.+*?|{}()])/'), array('[$1]'), $subjectWord), '\\\'') . '[[:>:]]'; |
||
| 1281 | } |
||
| 1282 | else |
||
| 1283 | { |
||
| 1284 | $subject_query['inner_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.id_topic = ' . ($prev_join === 0 ? 't' : 'subj' . $prev_join) . '.id_topic)'; |
||
| 1285 | $subject_query['where'][] = 'subj' . $numTables . '.word LIKE {string:subject_like_' . $count . '}'; |
||
| 1286 | $subject_query['params']['subject_like_' . $count++] = empty($modSettings['search_match_words']) ? '%' . $subjectWord . '%' : $subjectWord; |
||
| 1287 | $prev_join = $numTables; |
||
| 1288 | } |
||
| 1289 | } |
||
| 1290 | |||
| 1291 | if (!empty($userQuery)) |
||
| 1292 | { |
||
| 1293 | if ($subject_query['from'] != '{db_prefix}messages AS m') |
||
| 1294 | { |
||
| 1295 | $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)'; |
||
| 1296 | } |
||
| 1297 | $subject_query['where'][] = '{raw:user_query}'; |
||
| 1298 | $subject_query['params']['user_query'] = $userQuery; |
||
| 1299 | } |
||
| 1300 | View Code Duplication | if (!empty($search_params['topic'])) |
|
| 1301 | { |
||
| 1302 | $subject_query['where'][] = 't.id_topic = {int:topic}'; |
||
| 1303 | $subject_query['params']['topic'] = $search_params['topic']; |
||
| 1304 | } |
||
| 1305 | if (!empty($minMsgID)) |
||
| 1306 | { |
||
| 1307 | $subject_query['where'][] = 't.id_first_msg >= {int:min_msg_id}'; |
||
| 1308 | $subject_query['params']['min_msg_id'] = $minMsgID; |
||
| 1309 | } |
||
| 1310 | if (!empty($maxMsgID)) |
||
| 1311 | { |
||
| 1312 | $subject_query['where'][] = 't.id_last_msg <= {int:max_msg_id}'; |
||
| 1313 | $subject_query['params']['max_msg_id'] = $maxMsgID; |
||
| 1314 | } |
||
| 1315 | if (!empty($boardQuery)) |
||
| 1316 | { |
||
| 1317 | $subject_query['where'][] = 't.id_board {raw:board_query}'; |
||
| 1318 | $subject_query['params']['board_query'] = $boardQuery; |
||
| 1319 | } |
||
| 1320 | if (!empty($excludedPhrases)) |
||
| 1321 | { |
||
| 1322 | if ($subject_query['from'] != '{db_prefix}messages AS m') |
||
| 1323 | { |
||
| 1324 | $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)'; |
||
| 1325 | } |
||
| 1326 | $count = 0; |
||
| 1327 | foreach ($excludedPhrases as $phrase) |
||
| 1328 | { |
||
| 1329 | $subject_query['where'][] = 'm.subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:exclude_phrase_' . $count . '}'; |
||
| 1330 | $subject_query['where'][] = 'm.body NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:exclude_phrase_' . $count . '}'; |
||
| 1331 | $subject_query['params']['exclude_phrase_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\[\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . '[[:>:]]'; |
||
| 1332 | } |
||
| 1333 | } |
||
| 1334 | call_integration_hook('integrate_subject_search_query', array(&$subject_query)); |
||
| 1335 | |||
| 1336 | // Nothing to search for? |
||
| 1337 | if (empty($subject_query['where'])) |
||
| 1338 | continue; |
||
| 1339 | |||
| 1340 | $ignoreRequest = $smcFunc['db_search_query']('insert_log_search_topics', ($smcFunc['db_support_ignore'] ? ( ' |
||
| 1341 | INSERT IGNORE INTO {db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics |
||
| 1342 | (' . ($createTemporary ? '' : 'id_search, ') . 'id_topic)') : '') . ' |
||
| 1343 | SELECT ' . ($createTemporary ? '' : $_SESSION['search_cache']['id_search'] . ', ') . 't.id_topic |
||
| 1344 | FROM ' . $subject_query['from'] . (empty($subject_query['inner_join']) ? '' : ' |
||
| 1345 | INNER JOIN ' . implode(' |
||
| 1346 | INNER JOIN ', $subject_query['inner_join'])) . (empty($subject_query['left_join']) ? '' : ' |
||
| 1347 | LEFT JOIN ' . implode(' |
||
| 1348 | LEFT JOIN ', $subject_query['left_join'])) . ' |
||
| 1349 | WHERE ' . implode(' |
||
| 1350 | AND ', $subject_query['where']) . (empty($modSettings['search_max_results']) ? '' : ' |
||
| 1351 | LIMIT ' . ($modSettings['search_max_results'] - $numSubjectResults)), |
||
| 1352 | $subject_query['params'] |
||
| 1353 | ); |
||
| 1354 | // Don't do INSERT IGNORE? Manually fix this up! |
||
| 1355 | View Code Duplication | if (!$smcFunc['db_support_ignore']) |
|
| 1356 | { |
||
| 1357 | while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) |
||
| 1358 | { |
||
| 1359 | $ind = $createTemporary ? 0 : 1; |
||
| 1360 | // No duplicates! |
||
| 1361 | if (isset($inserts[$row[$ind]])) |
||
| 1362 | continue; |
||
| 1363 | |||
| 1364 | $inserts[$row[$ind]] = $row; |
||
| 1365 | } |
||
| 1366 | $smcFunc['db_free_result']($ignoreRequest); |
||
| 1367 | $numSubjectResults = count($inserts); |
||
| 1368 | } |
||
| 1369 | else |
||
| 1370 | $numSubjectResults += $smcFunc['db_affected_rows'](); |
||
| 1371 | |||
| 1372 | if (!empty($modSettings['search_max_results']) && $numSubjectResults >= $modSettings['search_max_results']) |
||
| 1373 | break; |
||
| 1374 | } |
||
| 1375 | |||
| 1376 | // Got some non-MySQL data to plonk in? |
||
| 1377 | View Code Duplication | if (!empty($inserts)) |
|
| 1378 | { |
||
| 1379 | $smcFunc['db_insert']('', |
||
| 1380 | ('{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics'), |
||
| 1381 | $createTemporary ? array('id_topic' => 'int') : array('id_search' => 'int', 'id_topic' => 'int'), |
||
| 1382 | $inserts, |
||
| 1383 | $createTemporary ? array('id_topic') : array('id_search', 'id_topic') |
||
| 1384 | ); |
||
| 1385 | } |
||
| 1386 | |||
| 1387 | if ($numSubjectResults !== 0) |
||
| 1388 | { |
||
| 1389 | $main_query['weights']['subject']['search'] = 'CASE WHEN MAX(lst.id_topic) IS NULL THEN 0 ELSE 1 END'; |
||
| 1390 | $main_query['left_join'][] = '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics AS lst ON (' . ($createTemporary ? '' : 'lst.id_search = {int:id_search} AND ') . 'lst.id_topic = t.id_topic)'; |
||
| 1391 | if (!$createTemporary) |
||
| 1392 | $main_query['parameters']['id_search'] = $_SESSION['search_cache']['id_search']; |
||
| 1393 | } |
||
| 1394 | } |
||
| 1395 | |||
| 1396 | $indexedResults = 0; |
||
| 1397 | // We building an index? |
||
| 1398 | if ($searchAPI->supportsMethod('indexedWordQuery', $query_params)) |
||
| 1399 | { |
||
| 1400 | $inserts = array(); |
||
| 1401 | $smcFunc['db_search_query']('drop_tmp_log_search_messages', ' |
||
| 1402 | DROP TABLE IF EXISTS {db_prefix}tmp_log_search_messages', |
||
| 1403 | array( |
||
| 1404 | 'db_error_skip' => true, |
||
| 1405 | ) |
||
| 1406 | ); |
||
| 1407 | |||
| 1408 | $createTemporary = $smcFunc['db_search_query']('create_tmp_log_search_messages', ' |
||
| 1409 | CREATE TEMPORARY TABLE {db_prefix}tmp_log_search_messages ( |
||
| 1410 | id_msg int(10) unsigned NOT NULL default {string:string_zero}, |
||
| 1411 | PRIMARY KEY (id_msg) |
||
| 1412 | ) ENGINE=MEMORY', |
||
| 1413 | array( |
||
| 1414 | 'string_zero' => '0', |
||
| 1415 | 'db_error_skip' => true, |
||
| 1416 | ) |
||
| 1417 | ) !== false; |
||
| 1418 | |||
| 1419 | // Clear, all clear! |
||
| 1420 | if (!$createTemporary) |
||
| 1421 | $smcFunc['db_search_query']('delete_log_search_messages', ' |
||
| 1422 | DELETE FROM {db_prefix}log_search_messages |
||
| 1423 | WHERE id_search = {int:id_search}', |
||
| 1424 | array( |
||
| 1425 | 'id_search' => $_SESSION['search_cache']['id_search'], |
||
| 1426 | ) |
||
| 1427 | ); |
||
| 1428 | |||
| 1429 | foreach ($searchWords as $orIndex => $words) |
||
| 1430 | { |
||
| 1431 | // Search for this word, assuming we have some words! |
||
| 1432 | if (!empty($words['indexed_words'])) |
||
| 1433 | { |
||
| 1434 | // Variables required for the search. |
||
| 1435 | $search_data = array( |
||
| 1436 | 'insert_into' => ($createTemporary ? 'tmp_' : '') . 'log_search_messages', |
||
| 1437 | 'no_regexp' => $no_regexp, |
||
| 1438 | 'max_results' => $maxMessageResults, |
||
| 1439 | 'indexed_results' => $indexedResults, |
||
| 1440 | 'params' => array( |
||
| 1441 | 'id_search' => !$createTemporary ? $_SESSION['search_cache']['id_search'] : 0, |
||
| 1442 | 'excluded_words' => $excludedWords, |
||
| 1443 | 'user_query' => !empty($userQuery) ? $userQuery : '', |
||
| 1444 | 'board_query' => !empty($boardQuery) ? $boardQuery : '', |
||
| 1445 | 'topic' => !empty($search_params['topic']) ? $search_params['topic'] : 0, |
||
| 1446 | 'min_msg_id' => !empty($minMsgID) ? $minMsgID : 0, |
||
| 1447 | 'max_msg_id' => !empty($maxMsgID) ? $maxMsgID : 0, |
||
| 1448 | 'excluded_phrases' => !empty($excludedPhrases) ? $excludedPhrases : array(), |
||
| 1449 | 'excluded_index_words' => !empty($excludedIndexWords) ? $excludedIndexWords : array(), |
||
| 1450 | 'excluded_subject_words' => !empty($excludedSubjectWords) ? $excludedSubjectWords : array(), |
||
| 1451 | ), |
||
| 1452 | ); |
||
| 1453 | |||
| 1454 | $ignoreRequest = $searchAPI->indexedWordQuery($words, $search_data); |
||
| 1455 | |||
| 1456 | if (!$smcFunc['db_support_ignore']) |
||
| 1457 | { |
||
| 1458 | View Code Duplication | while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) |
|
| 1459 | { |
||
| 1460 | // No duplicates! |
||
| 1461 | if (isset($inserts[$row[0]])) |
||
| 1462 | continue; |
||
| 1463 | |||
| 1464 | $inserts[$row[0]] = $row; |
||
| 1465 | } |
||
| 1466 | $smcFunc['db_free_result']($ignoreRequest); |
||
| 1467 | $indexedResults = count($inserts); |
||
| 1468 | } |
||
| 1469 | else |
||
| 1470 | $indexedResults += $smcFunc['db_affected_rows'](); |
||
| 1471 | |||
| 1472 | if (!empty($maxMessageResults) && $indexedResults >= $maxMessageResults) |
||
| 1473 | break; |
||
| 1474 | } |
||
| 1475 | } |
||
| 1476 | |||
| 1477 | // More non-MySQL stuff needed? |
||
| 1478 | View Code Duplication | if (!empty($inserts)) |
|
| 1479 | { |
||
| 1480 | $smcFunc['db_insert']('', |
||
| 1481 | '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_messages', |
||
| 1482 | $createTemporary ? array('id_msg' => 'int') : array('id_msg' => 'int', 'id_search' => 'int'), |
||
| 1483 | $inserts, |
||
| 1484 | $createTemporary ? array('id_msg') : array('id_msg', 'id_search') |
||
| 1485 | ); |
||
| 1486 | } |
||
| 1487 | |||
| 1488 | if (empty($indexedResults) && empty($numSubjectResults) && !empty($modSettings['search_force_index'])) |
||
| 1489 | { |
||
| 1490 | $context['search_errors']['query_not_specific_enough'] = true; |
||
| 1491 | $_REQUEST['params'] = $context['params']; |
||
| 1492 | return PlushSearch1(); |
||
| 1493 | } |
||
| 1494 | elseif (!empty($indexedResults)) |
||
| 1495 | { |
||
| 1496 | $main_query['inner_join'][] = '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_messages AS lsm ON (lsm.id_msg = m.id_msg)'; |
||
| 1497 | if (!$createTemporary) |
||
| 1498 | { |
||
| 1499 | $main_query['where'][] = 'lsm.id_search = {int:id_search}'; |
||
| 1500 | $main_query['parameters']['id_search'] = $_SESSION['search_cache']['id_search']; |
||
| 1501 | } |
||
| 1502 | } |
||
| 1503 | } |
||
| 1504 | |||
| 1505 | // Not using an index? All conditions have to be carried over. |
||
| 1506 | else |
||
| 1507 | { |
||
| 1508 | $orWhere = array(); |
||
| 1509 | $count = 0; |
||
| 1510 | foreach ($searchWords as $orIndex => $words) |
||
| 1511 | { |
||
| 1512 | $where = array(); |
||
| 1513 | foreach ($words['all_words'] as $regularWord) |
||
| 1514 | { |
||
| 1515 | $where[] = 'm.body' . (in_array($regularWord, $excludedWords) ? ' NOT' : '') . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:all_word_body_' . $count . '}'; |
||
| 1516 | if (in_array($regularWord, $excludedWords)) |
||
| 1517 | $where[] = 'm.subject NOT' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:all_word_body_' . $count . '}'; |
||
| 1518 | $main_query['parameters']['all_word_body_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($regularWord, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\[\]$.+*?|{}()])/'), array('[$1]'), $regularWord), '\\\'') . '[[:>:]]'; |
||
| 1519 | } |
||
| 1520 | View Code Duplication | if (!empty($where)) |
|
| 1521 | $orWhere[] = count($where) > 1 ? '(' . implode(' AND ', $where) . ')' : $where[0]; |
||
| 1522 | } |
||
| 1523 | View Code Duplication | if (!empty($orWhere)) |
|
| 1524 | $main_query['where'][] = count($orWhere) > 1 ? '(' . implode(' OR ', $orWhere) . ')' : $orWhere[0]; |
||
| 1525 | |||
| 1526 | if (!empty($userQuery)) |
||
| 1527 | { |
||
| 1528 | $main_query['where'][] = '{raw:user_query}'; |
||
| 1529 | $main_query['parameters']['user_query'] = $userQuery; |
||
| 1530 | } |
||
| 1531 | View Code Duplication | if (!empty($search_params['topic'])) |
|
| 1532 | { |
||
| 1533 | $main_query['where'][] = 'm.id_topic = {int:topic}'; |
||
| 1534 | $main_query['parameters']['topic'] = $search_params['topic']; |
||
| 1535 | } |
||
| 1536 | if (!empty($minMsgID)) |
||
| 1537 | { |
||
| 1538 | $main_query['where'][] = 'm.id_msg >= {int:min_msg_id}'; |
||
| 1539 | $main_query['parameters']['min_msg_id'] = $minMsgID; |
||
| 1540 | } |
||
| 1541 | if (!empty($maxMsgID)) |
||
| 1542 | { |
||
| 1543 | $main_query['where'][] = 'm.id_msg <= {int:max_msg_id}'; |
||
| 1544 | $main_query['parameters']['max_msg_id'] = $maxMsgID; |
||
| 1545 | } |
||
| 1546 | if (!empty($boardQuery)) |
||
| 1547 | { |
||
| 1548 | $main_query['where'][] = 'm.id_board {raw:board_query}'; |
||
| 1549 | $main_query['parameters']['board_query'] = $boardQuery; |
||
| 1550 | } |
||
| 1551 | } |
||
| 1552 | call_integration_hook('integrate_main_search_query', array(&$main_query)); |
||
| 1553 | |||
| 1554 | // Did we either get some indexed results, or otherwise did not do an indexed query? |
||
| 1555 | if (!empty($indexedResults) || !$searchAPI->supportsMethod('indexedWordQuery', $query_params)) |
||
| 1556 | { |
||
| 1557 | $relevance = '1000 * ('; |
||
| 1558 | $new_weight_total = 0; |
||
| 1559 | foreach ($main_query['weights'] as $type => $value) |
||
| 1560 | { |
||
| 1561 | $relevance .= $weight[$type]; |
||
| 1562 | if (!empty($value['search'])) |
||
| 1563 | $relevance .= ' * ' . $value['search']; |
||
| 1564 | $relevance .= ' + '; |
||
| 1565 | $new_weight_total += $weight[$type]; |
||
| 1566 | } |
||
| 1567 | $main_query['select']['relevance'] = substr($relevance, 0, -3) . ') / ' . $new_weight_total . ' AS relevance'; |
||
| 1568 | |||
| 1569 | $ignoreRequest = $smcFunc['db_search_query']('insert_log_search_results_no_index', ($smcFunc['db_support_ignore'] ? ( ' |
||
| 1570 | INSERT IGNORE INTO ' . '{db_prefix}log_search_results |
||
| 1571 | (' . implode(', ', array_keys($main_query['select'])) . ')') : '') . ' |
||
| 1572 | SELECT |
||
| 1573 | ' . implode(', |
||
| 1574 | ', $main_query['select']) . ' |
||
| 1575 | FROM ' . $main_query['from'] . (empty($main_query['inner_join']) ? '' : ' |
||
| 1576 | INNER JOIN ' . implode(' |
||
| 1577 | INNER JOIN ', $main_query['inner_join'])) . (empty($main_query['left_join']) ? '' : ' |
||
| 1578 | LEFT JOIN ' . implode(' |
||
| 1579 | LEFT JOIN ', $main_query['left_join'])) . (!empty($main_query['where']) ? ' |
||
| 1580 | WHERE ' : '') . implode(' |
||
| 1581 | AND ', $main_query['where']) . (empty($main_query['group_by']) ? '' : ' |
||
| 1582 | GROUP BY ' . implode(', ', $main_query['group_by'])) . (empty($modSettings['search_max_results']) ? '' : ' |
||
| 1583 | LIMIT ' . $modSettings['search_max_results']), |
||
| 1584 | $main_query['parameters'] |
||
| 1585 | ); |
||
| 1586 | |||
| 1587 | // We love to handle non-good databases that don't support our ignore! |
||
| 1588 | if (!$smcFunc['db_support_ignore']) |
||
| 1589 | { |
||
| 1590 | $inserts = array(); |
||
| 1591 | while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) |
||
| 1592 | { |
||
| 1593 | // No duplicates! |
||
| 1594 | if (isset($inserts[$row[2]])) |
||
| 1595 | continue; |
||
| 1596 | |||
| 1597 | foreach ($row as $key => $value) |
||
| 1598 | $inserts[$row[2]][] = (int) $row[$key]; |
||
| 1599 | } |
||
| 1600 | $smcFunc['db_free_result']($ignoreRequest); |
||
| 1601 | |||
| 1602 | // Now put them in! |
||
| 1603 | if (!empty($inserts)) |
||
| 1604 | { |
||
| 1605 | $query_columns = array(); |
||
| 1606 | foreach ($main_query['select'] as $k => $v) |
||
| 1607 | $query_columns[$k] = 'int'; |
||
| 1608 | |||
| 1609 | $smcFunc['db_insert']('', |
||
| 1610 | '{db_prefix}log_search_results', |
||
| 1611 | $query_columns, |
||
| 1612 | $inserts, |
||
| 1613 | array('id_search', 'id_topic') |
||
| 1614 | ); |
||
| 1615 | } |
||
| 1616 | $_SESSION['search_cache']['num_results'] += count($inserts); |
||
| 1617 | } |
||
| 1618 | else |
||
| 1619 | $_SESSION['search_cache']['num_results'] = $smcFunc['db_affected_rows'](); |
||
| 1620 | } |
||
| 1621 | |||
| 1622 | // Insert subject-only matches. |
||
| 1623 | if ($_SESSION['search_cache']['num_results'] < $modSettings['search_max_results'] && $numSubjectResults !== 0) |
||
| 1624 | { |
||
| 1625 | $relevance = '1000 * ('; |
||
| 1626 | View Code Duplication | foreach ($weight_factors as $type => $value) |
|
| 1627 | if (isset($value['results'])) |
||
| 1628 | { |
||
| 1629 | $relevance .= $weight[$type]; |
||
| 1630 | if (!empty($value['results'])) |
||
| 1631 | $relevance .= ' * ' . $value['results']; |
||
| 1632 | $relevance .= ' + '; |
||
| 1633 | } |
||
| 1634 | $relevance = substr($relevance, 0, -3) . ') / ' . $weight_total . ' AS relevance'; |
||
| 1635 | |||
| 1636 | $usedIDs = array_flip(empty($inserts) ? array() : array_keys($inserts)); |
||
| 1637 | $ignoreRequest = $smcFunc['db_search_query']('insert_log_search_results_sub_only', ($smcFunc['db_support_ignore'] ? ( ' |
||
| 1638 | INSERT IGNORE INTO {db_prefix}log_search_results |
||
| 1639 | (id_search, id_topic, relevance, id_msg, num_matches)') : '') . ' |
||
| 1640 | SELECT |
||
| 1641 | {int:id_search}, |
||
| 1642 | t.id_topic, |
||
| 1643 | ' . $relevance . ', |
||
| 1644 | t.id_first_msg, |
||
| 1645 | 1 |
||
| 1646 | FROM {db_prefix}topics AS t |
||
| 1647 | INNER JOIN {db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics AS lst ON (lst.id_topic = t.id_topic)' |
||
|
0 ignored issues
–
show
The variable
$createTemporary does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 1648 | . ($createTemporary ? '' : ' WHERE lst.id_search = {int:id_search}') |
||
| 1649 | . (empty($modSettings['search_max_results']) ? '' : ' |
||
| 1650 | LIMIT ' . ($modSettings['search_max_results'] - $_SESSION['search_cache']['num_results'])), |
||
| 1651 | array( |
||
| 1652 | 'id_search' => $_SESSION['search_cache']['id_search'], |
||
| 1653 | 'min_msg' => $minMsg, |
||
| 1654 | 'recent_message' => $recentMsg, |
||
| 1655 | 'huge_topic_posts' => $humungousTopicPosts, |
||
| 1656 | ) |
||
| 1657 | ); |
||
| 1658 | // Once again need to do the inserts if the database don't support ignore! |
||
| 1659 | if (!$smcFunc['db_support_ignore']) |
||
| 1660 | { |
||
| 1661 | $inserts = array(); |
||
| 1662 | View Code Duplication | while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) |
|
| 1663 | { |
||
| 1664 | // No duplicates! |
||
| 1665 | if (isset($usedIDs[$row[1]])) |
||
| 1666 | continue; |
||
| 1667 | |||
| 1668 | $usedIDs[$row[1]] = true; |
||
| 1669 | $inserts[] = $row; |
||
| 1670 | } |
||
| 1671 | $smcFunc['db_free_result']($ignoreRequest); |
||
| 1672 | |||
| 1673 | // Now put them in! |
||
| 1674 | View Code Duplication | if (!empty($inserts)) |
|
| 1675 | { |
||
| 1676 | $smcFunc['db_insert']('', |
||
| 1677 | '{db_prefix}log_search_results', |
||
| 1678 | array('id_search' => 'int', 'id_topic' => 'int', 'relevance' => 'float', 'id_msg' => 'int', 'num_matches' => 'int'), |
||
| 1679 | $inserts, |
||
| 1680 | array('id_search', 'id_topic') |
||
| 1681 | ); |
||
| 1682 | } |
||
| 1683 | $_SESSION['search_cache']['num_results'] += count($inserts); |
||
| 1684 | } |
||
| 1685 | else |
||
| 1686 | $_SESSION['search_cache']['num_results'] += $smcFunc['db_affected_rows'](); |
||
| 1687 | } |
||
| 1688 | elseif ($_SESSION['search_cache']['num_results'] == -1) |
||
| 1689 | $_SESSION['search_cache']['num_results'] = 0; |
||
| 1690 | } |
||
| 1691 | } |
||
| 1692 | |||
| 1693 | // *** Retrieve the results to be shown on the page |
||
| 1694 | $participants = array(); |
||
| 1695 | $request = $smcFunc['db_search_query']('', ' |
||
| 1696 | SELECT ' . (empty($search_params['topic']) ? 'lsr.id_topic' : $search_params['topic'] . ' AS id_topic') . ', lsr.id_msg, lsr.relevance, lsr.num_matches |
||
| 1697 | FROM {db_prefix}log_search_results AS lsr' . ($search_params['sort'] == 'num_replies' ? ' |
||
| 1698 | INNER JOIN {db_prefix}topics AS t ON (t.id_topic = lsr.id_topic)' : '') . ' |
||
| 1699 | WHERE lsr.id_search = {int:id_search} |
||
| 1700 | ORDER BY {raw:sort} {raw:sort_dir} |
||
| 1701 | LIMIT {int:start}, {int:max}', |
||
| 1702 | array( |
||
| 1703 | 'id_search' => $_SESSION['search_cache']['id_search'], |
||
| 1704 | 'sort' => $search_params['sort'], |
||
| 1705 | 'sort_dir' => $search_params['sort_dir'], |
||
| 1706 | 'start' => $_REQUEST['start'], |
||
| 1707 | 'max' => $modSettings['search_results_per_page'], |
||
| 1708 | ) |
||
| 1709 | ); |
||
| 1710 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1711 | { |
||
| 1712 | $context['topics'][$row['id_msg']] = array( |
||
| 1713 | 'relevance' => round($row['relevance'] / 10, 1) . '%', |
||
| 1714 | 'num_matches' => $row['num_matches'], |
||
| 1715 | 'matches' => array(), |
||
| 1716 | ); |
||
| 1717 | // By default they didn't participate in the topic! |
||
| 1718 | $participants[$row['id_topic']] = false; |
||
| 1719 | } |
||
| 1720 | $smcFunc['db_free_result']($request); |
||
| 1721 | |||
| 1722 | $num_results = $_SESSION['search_cache']['num_results']; |
||
| 1723 | } |
||
| 1724 | |||
| 1725 | if (!empty($context['topics'])) |
||
| 1726 | { |
||
| 1727 | // Create an array for the permissions. |
||
| 1728 | $boards_can = boardsAllowedTo(array('post_reply_own', 'post_reply_any'), true, false); |
||
| 1729 | |||
| 1730 | // How's about some quick moderation? |
||
| 1731 | if (!empty($options['display_quick_mod'])) |
||
| 1732 | { |
||
| 1733 | $boards_can = array_merge($boards_can, boardsAllowedTo(array('lock_any', 'lock_own', 'make_sticky', 'move_any', 'move_own', 'remove_any', 'remove_own', 'merge_any'), true, false)); |
||
| 1734 | |||
| 1735 | $context['can_lock'] = in_array(0, $boards_can['lock_any']); |
||
| 1736 | $context['can_sticky'] = in_array(0, $boards_can['make_sticky']); |
||
| 1737 | $context['can_move'] = in_array(0, $boards_can['move_any']); |
||
| 1738 | $context['can_remove'] = in_array(0, $boards_can['remove_any']); |
||
| 1739 | $context['can_merge'] = in_array(0, $boards_can['merge_any']); |
||
| 1740 | } |
||
| 1741 | |||
| 1742 | // What messages are we using? |
||
| 1743 | $msg_list = array_keys($context['topics']); |
||
| 1744 | |||
| 1745 | // Load the posters... |
||
| 1746 | $request = $smcFunc['db_query']('', ' |
||
| 1747 | SELECT id_member |
||
| 1748 | FROM {db_prefix}messages |
||
| 1749 | WHERE id_member != {int:no_member} |
||
| 1750 | AND id_msg IN ({array_int:message_list}) |
||
| 1751 | LIMIT {int:limit}', |
||
| 1752 | array( |
||
| 1753 | 'message_list' => $msg_list, |
||
| 1754 | 'no_member' => 0, |
||
| 1755 | 'limit' => count($context['topics']), |
||
| 1756 | ) |
||
| 1757 | ); |
||
| 1758 | $posters = array(); |
||
| 1759 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1760 | $posters[] = $row['id_member']; |
||
| 1761 | $smcFunc['db_free_result']($request); |
||
| 1762 | |||
| 1763 | call_integration_hook('integrate_search_message_list', array(&$msg_list, &$posters)); |
||
| 1764 | |||
| 1765 | if (!empty($posters)) |
||
| 1766 | loadMemberData(array_unique($posters)); |
||
| 1767 | |||
| 1768 | // Get the messages out for the callback - select enough that it can be made to look just like Display. |
||
| 1769 | $messages_request = $smcFunc['db_query']('', ' |
||
| 1770 | SELECT |
||
| 1771 | m.id_msg, m.subject, m.poster_name, m.poster_email, m.poster_time, m.id_member, |
||
| 1772 | m.icon, m.poster_ip, m.body, m.smileys_enabled, m.modified_time, m.modified_name, |
||
| 1773 | first_m.id_msg AS first_msg, first_m.subject AS first_subject, first_m.icon AS first_icon, first_m.poster_time AS first_poster_time, |
||
| 1774 | first_mem.id_member AS first_member_id, COALESCE(first_mem.real_name, first_m.poster_name) AS first_member_name, |
||
| 1775 | last_m.id_msg AS last_msg, last_m.poster_time AS last_poster_time, last_mem.id_member AS last_member_id, |
||
| 1776 | COALESCE(last_mem.real_name, last_m.poster_name) AS last_member_name, last_m.icon AS last_icon, last_m.subject AS last_subject, |
||
| 1777 | t.id_topic, t.is_sticky, t.locked, t.id_poll, t.num_replies, t.num_views, |
||
| 1778 | b.id_board, b.name AS board_name, c.id_cat, c.name AS cat_name |
||
| 1779 | FROM {db_prefix}messages AS m |
||
| 1780 | INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) |
||
| 1781 | INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
||
| 1782 | INNER JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat) |
||
| 1783 | INNER JOIN {db_prefix}messages AS first_m ON (first_m.id_msg = t.id_first_msg) |
||
| 1784 | INNER JOIN {db_prefix}messages AS last_m ON (last_m.id_msg = t.id_last_msg) |
||
| 1785 | LEFT JOIN {db_prefix}members AS first_mem ON (first_mem.id_member = first_m.id_member) |
||
| 1786 | LEFT JOIN {db_prefix}members AS last_mem ON (last_mem.id_member = first_m.id_member) |
||
| 1787 | WHERE m.id_msg IN ({array_int:message_list})' . ($modSettings['postmod_active'] ? ' |
||
| 1788 | AND m.approved = {int:is_approved}' : '') . ' |
||
| 1789 | ORDER BY FIND_IN_SET(m.id_msg, {string:message_list_in_set}) |
||
| 1790 | LIMIT {int:limit}', |
||
| 1791 | array( |
||
| 1792 | 'message_list' => $msg_list, |
||
| 1793 | 'is_approved' => 1, |
||
| 1794 | 'message_list_in_set' => implode(',', $msg_list), |
||
| 1795 | 'limit' => count($context['topics']), |
||
| 1796 | ) |
||
| 1797 | ); |
||
| 1798 | |||
| 1799 | // If there are no results that means the things in the cache got deleted, so pretend we have no topics anymore. |
||
| 1800 | if ($smcFunc['db_num_rows']($messages_request) == 0) |
||
| 1801 | $context['topics'] = array(); |
||
| 1802 | |||
| 1803 | // If we want to know who participated in what then load this now. |
||
| 1804 | if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest']) |
||
| 1805 | { |
||
| 1806 | $result = $smcFunc['db_query']('', ' |
||
| 1807 | SELECT id_topic |
||
| 1808 | FROM {db_prefix}messages |
||
| 1809 | WHERE id_topic IN ({array_int:topic_list}) |
||
| 1810 | AND id_member = {int:current_member} |
||
| 1811 | GROUP BY id_topic |
||
| 1812 | LIMIT {int:limit}', |
||
| 1813 | array( |
||
| 1814 | 'current_member' => $user_info['id'], |
||
| 1815 | 'topic_list' => array_keys($participants), |
||
| 1816 | 'limit' => count($participants), |
||
| 1817 | ) |
||
| 1818 | ); |
||
| 1819 | while ($row = $smcFunc['db_fetch_assoc']($result)) |
||
| 1820 | $participants[$row['id_topic']] = true; |
||
| 1821 | $smcFunc['db_free_result']($result); |
||
| 1822 | } |
||
| 1823 | } |
||
| 1824 | |||
| 1825 | // Now that we know how many results to expect we can start calculating the page numbers. |
||
| 1826 | $context['page_index'] = constructPageIndex($scripturl . '?action=search2;params=' . $context['params'], $_REQUEST['start'], $num_results, $modSettings['search_results_per_page'], false); |
||
| 1827 | |||
| 1828 | // Consider the search complete! |
||
| 1829 | if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) |
||
| 1830 | cache_put_data('search_start:' . ($user_info['is_guest'] ? $user_info['ip'] : $user_info['id']), null, 90); |
||
| 1831 | |||
| 1832 | $context['key_words'] = &$searchArray; |
||
| 1833 | |||
| 1834 | // Setup the default topic icons... for checking they exist and the like! |
||
| 1835 | $context['icon_sources'] = array(); |
||
| 1836 | foreach ($context['stable_icons'] as $icon) |
||
| 1837 | $context['icon_sources'][$icon] = 'images_url'; |
||
| 1838 | |||
| 1839 | $context['sub_template'] = 'results'; |
||
| 1840 | $context['page_title'] = $txt['search_results']; |
||
| 1841 | $context['get_topics'] = 'prepareSearchContext'; |
||
| 1842 | $context['can_restore_perm'] = allowedTo('move_any') && !empty($modSettings['recycle_enable']); |
||
| 1843 | $context['can_restore'] = false; // We won't know until we handle the context later whether we can actually restore... |
||
| 1844 | |||
| 1845 | $context['jump_to'] = array( |
||
| 1846 | 'label' => addslashes(un_htmlspecialchars($txt['jump_to'])), |
||
| 1847 | 'board_name' => addslashes(un_htmlspecialchars($txt['select_destination'])), |
||
| 1848 | ); |
||
| 1849 | } |
||
| 1850 | |||
| 1851 | /** |
||
| 1852 | * Callback to return messages - saves memory. |
||
| 1853 | * |
||
| 1854 | * What it does: |
||
| 1855 | * - callback function for the results sub template. |
||
| 1856 | * - loads the necessary contextual data to show a search result. |
||
| 1857 | * |
||
| 1858 | * @param bool $reset Whether to reset the counter |
||
| 1859 | * @return array An array of contextual info related to this search |
||
| 1860 | */ |
||
| 1861 | function prepareSearchContext($reset = false) |
||
| 1862 | { |
||
| 1863 | global $txt, $modSettings, $scripturl, $user_info; |
||
| 1864 | global $memberContext, $context, $settings, $options, $messages_request; |
||
| 1865 | global $boards_can, $participants, $smcFunc; |
||
| 1866 | static $recycle_board = null; |
||
| 1867 | |||
| 1868 | if ($recycle_board === null) |
||
| 1869 | $recycle_board = !empty($modSettings['recycle_enable']) && !empty($modSettings['recycle_board']) ? (int) $modSettings['recycle_board'] : 0; |
||
| 1870 | |||
| 1871 | // Remember which message this is. (ie. reply #83) |
||
| 1872 | static $counter = null; |
||
| 1873 | if ($counter == null || $reset) |
||
| 1874 | $counter = $_REQUEST['start'] + 1; |
||
| 1875 | |||
| 1876 | // If the query returned false, bail. |
||
| 1877 | if ($messages_request == false) |
||
| 1878 | return false; |
||
| 1879 | |||
| 1880 | // Start from the beginning... |
||
| 1881 | if ($reset) |
||
| 1882 | return @$smcFunc['db_data_seek']($messages_request, 0); |
||
| 1883 | |||
| 1884 | // Attempt to get the next message. |
||
| 1885 | $message = $smcFunc['db_fetch_assoc']($messages_request); |
||
| 1886 | if (!$message) |
||
| 1887 | return false; |
||
| 1888 | |||
| 1889 | // Can't have an empty subject can we? |
||
| 1890 | $message['subject'] = $message['subject'] != '' ? $message['subject'] : $txt['no_subject']; |
||
| 1891 | |||
| 1892 | $message['first_subject'] = $message['first_subject'] != '' ? $message['first_subject'] : $txt['no_subject']; |
||
| 1893 | $message['last_subject'] = $message['last_subject'] != '' ? $message['last_subject'] : $txt['no_subject']; |
||
| 1894 | |||
| 1895 | // If it couldn't load, or the user was a guest.... someday may be done with a guest table. |
||
| 1896 | if (!loadMemberContext($message['id_member'])) |
||
| 1897 | { |
||
| 1898 | // Notice this information isn't used anywhere else.... *cough guest table cough*. |
||
| 1899 | $memberContext[$message['id_member']]['name'] = $message['poster_name']; |
||
| 1900 | $memberContext[$message['id_member']]['id'] = 0; |
||
| 1901 | $memberContext[$message['id_member']]['group'] = $txt['guest_title']; |
||
| 1902 | $memberContext[$message['id_member']]['link'] = $message['poster_name']; |
||
| 1903 | $memberContext[$message['id_member']]['email'] = $message['poster_email']; |
||
| 1904 | } |
||
| 1905 | $memberContext[$message['id_member']]['ip'] = inet_dtop($message['poster_ip']); |
||
| 1906 | |||
| 1907 | // Do the censor thang... |
||
| 1908 | censorText($message['body']); |
||
| 1909 | censorText($message['subject']); |
||
| 1910 | |||
| 1911 | censorText($message['first_subject']); |
||
| 1912 | censorText($message['last_subject']); |
||
| 1913 | |||
| 1914 | // Shorten this message if necessary. |
||
| 1915 | if ($context['compact']) |
||
| 1916 | { |
||
| 1917 | // Set the number of characters before and after the searched keyword. |
||
| 1918 | $charLimit = 50; |
||
| 1919 | |||
| 1920 | $message['body'] = strtr($message['body'], array("\n" => ' ', '<br>' => "\n")); |
||
| 1921 | $message['body'] = parse_bbc($message['body'], $message['smileys_enabled'], $message['id_msg']); |
||
| 1922 | $message['body'] = strip_tags(strtr($message['body'], array('</div>' => '<br>', '</li>' => '<br>')), '<br>'); |
||
| 1923 | |||
| 1924 | if ($smcFunc['strlen']($message['body']) > $charLimit) |
||
| 1925 | { |
||
| 1926 | if (empty($context['key_words'])) |
||
| 1927 | $message['body'] = $smcFunc['substr']($message['body'], 0, $charLimit) . '<strong>...</strong>'; |
||
| 1928 | else |
||
| 1929 | { |
||
| 1930 | $matchString = ''; |
||
| 1931 | $force_partial_word = false; |
||
| 1932 | foreach ($context['key_words'] as $keyword) |
||
| 1933 | { |
||
| 1934 | $keyword = un_htmlspecialchars($keyword); |
||
| 1935 | $keyword = preg_replace_callback('~(&#(\d{1,7}|x[0-9a-fA-F]{1,6});)~', 'entity_fix__callback', strtr($keyword, array('\\\'' => '\'', '&' => '&'))); |
||
| 1936 | |||
| 1937 | if (preg_match('~[\'\.,/@%&;:(){}\[\]_\-+\\\\]$~', $keyword) != 0 || preg_match('~^[\'\.,/@%&;:(){}\[\]_\-+\\\\]~', $keyword) != 0) |
||
| 1938 | $force_partial_word = true; |
||
| 1939 | $matchString .= strtr(preg_quote($keyword, '/'), array('\*' => '.+?')) . '|'; |
||
| 1940 | } |
||
| 1941 | $matchString = un_htmlspecialchars(substr($matchString, 0, -1)); |
||
| 1942 | |||
| 1943 | $message['body'] = un_htmlspecialchars(strtr($message['body'], array(' ' => ' ', '<br>' => "\n", '[' => '[', ']' => ']', ':' => ':', '@' => '@'))); |
||
| 1944 | |||
| 1945 | if (empty($modSettings['search_method']) || $force_partial_word) |
||
| 1946 | preg_match_all('/([^\s\W]{' . $charLimit . '}[\s\W]|[\s\W].{0,' . $charLimit . '}?|^)(' . $matchString . ')(.{0,' . $charLimit . '}[\s\W]|[^\s\W]{0,' . $charLimit . '})/is' . ($context['utf8'] ? 'u' : ''), $message['body'], $matches); |
||
| 1947 | else |
||
| 1948 | preg_match_all('/([^\s\W]{' . $charLimit . '}[\s\W]|[\s\W].{0,' . $charLimit . '}?[\s\W]|^)(' . $matchString . ')([\s\W].{0,' . $charLimit . '}[\s\W]|[\s\W][^\s\W]{0,' . $charLimit . '})/is' . ($context['utf8'] ? 'u' : ''), $message['body'], $matches); |
||
| 1949 | |||
| 1950 | $message['body'] = ''; |
||
| 1951 | foreach ($matches[0] as $index => $match) |
||
| 1952 | { |
||
| 1953 | $match = strtr($smcFunc['htmlspecialchars']($match, ENT_QUOTES), array("\n" => ' ')); |
||
| 1954 | $message['body'] .= '<strong>......</strong> ' . $match . ' <strong>......</strong>'; |
||
| 1955 | } |
||
| 1956 | } |
||
| 1957 | |||
| 1958 | // Re-fix the international characters. |
||
| 1959 | $message['body'] = preg_replace_callback('~(&#(\d{1,7}|x[0-9a-fA-F]{1,6});)~', 'entity_fix__callback', $message['body']); |
||
| 1960 | } |
||
| 1961 | } |
||
| 1962 | else |
||
| 1963 | { |
||
| 1964 | // Run BBC interpreter on the message. |
||
| 1965 | $message['body'] = parse_bbc($message['body'], $message['smileys_enabled'], $message['id_msg']); |
||
| 1966 | } |
||
| 1967 | |||
| 1968 | // Make sure we don't end up with a practically empty message body. |
||
| 1969 | $message['body'] = preg_replace('~^(?: )+$~', '', $message['body']); |
||
| 1970 | |||
| 1971 | if (!empty($recycle_board) && $message['id_board'] == $recycle_board) |
||
| 1972 | { |
||
| 1973 | $message['first_icon'] = 'recycled'; |
||
| 1974 | $message['last_icon'] = 'recycled'; |
||
| 1975 | $message['icon'] = 'recycled'; |
||
| 1976 | } |
||
| 1977 | |||
| 1978 | // Sadly, we need to check the icon ain't broke. |
||
| 1979 | if (!empty($modSettings['messageIconChecks_enable'])) |
||
| 1980 | { |
||
| 1981 | View Code Duplication | if (!isset($context['icon_sources'][$message['first_icon']])) |
|
| 1982 | $context['icon_sources'][$message['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['first_icon'] . '.png') ? 'images_url' : 'default_images_url'; |
||
| 1983 | View Code Duplication | if (!isset($context['icon_sources'][$message['last_icon']])) |
|
| 1984 | $context['icon_sources'][$message['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['last_icon'] . '.png') ? 'images_url' : 'default_images_url'; |
||
| 1985 | View Code Duplication | if (!isset($context['icon_sources'][$message['icon']])) |
|
| 1986 | $context['icon_sources'][$message['icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['icon'] . '.png') ? 'images_url' : 'default_images_url'; |
||
| 1987 | } |
||
| 1988 | else |
||
| 1989 | { |
||
| 1990 | View Code Duplication | if (!isset($context['icon_sources'][$message['first_icon']])) |
|
| 1991 | $context['icon_sources'][$message['first_icon']] = 'images_url'; |
||
| 1992 | View Code Duplication | if (!isset($context['icon_sources'][$message['last_icon']])) |
|
| 1993 | $context['icon_sources'][$message['last_icon']] = 'images_url'; |
||
| 1994 | View Code Duplication | if (!isset($context['icon_sources'][$message['icon']])) |
|
| 1995 | $context['icon_sources'][$message['icon']] = 'images_url'; |
||
| 1996 | } |
||
| 1997 | |||
| 1998 | // Do we have quote tag enabled? |
||
| 1999 | $quote_enabled = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC'])); |
||
| 2000 | |||
| 2001 | // Reference the main color class. |
||
| 2002 | $colorClass = 'windowbg'; |
||
| 2003 | |||
| 2004 | // Sticky topics should get a different color, too. |
||
| 2005 | if ($message['is_sticky']) |
||
| 2006 | $colorClass .= ' sticky'; |
||
| 2007 | |||
| 2008 | // Locked topics get special treatment as well. |
||
| 2009 | if ($message['locked']) |
||
| 2010 | $colorClass .= ' locked'; |
||
| 2011 | |||
| 2012 | $output = array_merge($context['topics'][$message['id_msg']], array( |
||
| 2013 | 'id' => $message['id_topic'], |
||
| 2014 | 'is_sticky' => !empty($message['is_sticky']), |
||
| 2015 | 'is_locked' => !empty($message['locked']), |
||
| 2016 | 'css_class' => $colorClass, |
||
| 2017 | 'is_poll' => $modSettings['pollMode'] == '1' && $message['id_poll'] > 0, |
||
| 2018 | 'posted_in' => !empty($participants[$message['id_topic']]), |
||
| 2019 | 'views' => $message['num_views'], |
||
| 2020 | 'replies' => $message['num_replies'], |
||
| 2021 | 'can_reply' => in_array($message['id_board'], $boards_can['post_reply_any']) || in_array(0, $boards_can['post_reply_any']), |
||
| 2022 | 'can_quote' => (in_array($message['id_board'], $boards_can['post_reply_any']) || in_array(0, $boards_can['post_reply_any'])) && $quote_enabled, |
||
| 2023 | 'first_post' => array( |
||
| 2024 | 'id' => $message['first_msg'], |
||
| 2025 | 'time' => timeformat($message['first_poster_time']), |
||
| 2026 | 'timestamp' => forum_time(true, $message['first_poster_time']), |
||
| 2027 | 'subject' => $message['first_subject'], |
||
| 2028 | 'href' => $scripturl . '?topic=' . $message['id_topic'] . '.0', |
||
| 2029 | 'link' => '<a href="' . $scripturl . '?topic=' . $message['id_topic'] . '.0">' . $message['first_subject'] . '</a>', |
||
| 2030 | 'icon' => $message['first_icon'], |
||
| 2031 | 'icon_url' => $settings[$context['icon_sources'][$message['first_icon']]] . '/post/' . $message['first_icon'] . '.png', |
||
| 2032 | 'member' => array( |
||
| 2033 | 'id' => $message['first_member_id'], |
||
| 2034 | 'name' => $message['first_member_name'], |
||
| 2035 | 'href' => !empty($message['first_member_id']) ? $scripturl . '?action=profile;u=' . $message['first_member_id'] : '', |
||
| 2036 | 'link' => !empty($message['first_member_id']) ? '<a href="' . $scripturl . '?action=profile;u=' . $message['first_member_id'] . '" title="' . $txt['profile_of'] . ' ' . $message['first_member_name'] . '">' . $message['first_member_name'] . '</a>' : $message['first_member_name'] |
||
| 2037 | ) |
||
| 2038 | ), |
||
| 2039 | 'last_post' => array( |
||
| 2040 | 'id' => $message['last_msg'], |
||
| 2041 | 'time' => timeformat($message['last_poster_time']), |
||
| 2042 | 'timestamp' => forum_time(true, $message['last_poster_time']), |
||
| 2043 | 'subject' => $message['last_subject'], |
||
| 2044 | 'href' => $scripturl . '?topic=' . $message['id_topic'] . ($message['num_replies'] == 0 ? '.0' : '.msg' . $message['last_msg']) . '#msg' . $message['last_msg'], |
||
| 2045 | 'link' => '<a href="' . $scripturl . '?topic=' . $message['id_topic'] . ($message['num_replies'] == 0 ? '.0' : '.msg' . $message['last_msg']) . '#msg' . $message['last_msg'] . '">' . $message['last_subject'] . '</a>', |
||
| 2046 | 'icon' => $message['last_icon'], |
||
| 2047 | 'icon_url' => $settings[$context['icon_sources'][$message['last_icon']]] . '/post/' . $message['last_icon'] . '.png', |
||
| 2048 | 'member' => array( |
||
| 2049 | 'id' => $message['last_member_id'], |
||
| 2050 | 'name' => $message['last_member_name'], |
||
| 2051 | 'href' => !empty($message['last_member_id']) ? $scripturl . '?action=profile;u=' . $message['last_member_id'] : '', |
||
| 2052 | 'link' => !empty($message['last_member_id']) ? '<a href="' . $scripturl . '?action=profile;u=' . $message['last_member_id'] . '" title="' . $txt['profile_of'] . ' ' . $message['last_member_name'] . '">' . $message['last_member_name'] . '</a>' : $message['last_member_name'] |
||
| 2053 | ) |
||
| 2054 | ), |
||
| 2055 | 'board' => array( |
||
| 2056 | 'id' => $message['id_board'], |
||
| 2057 | 'name' => $message['board_name'], |
||
| 2058 | 'href' => $scripturl . '?board=' . $message['id_board'] . '.0', |
||
| 2059 | 'link' => '<a href="' . $scripturl . '?board=' . $message['id_board'] . '.0">' . $message['board_name'] . '</a>' |
||
| 2060 | ), |
||
| 2061 | 'category' => array( |
||
| 2062 | 'id' => $message['id_cat'], |
||
| 2063 | 'name' => $message['cat_name'], |
||
| 2064 | 'href' => $scripturl . '#c' . $message['id_cat'], |
||
| 2065 | 'link' => '<a href="' . $scripturl . '#c' . $message['id_cat'] . '">' . $message['cat_name'] . '</a>' |
||
| 2066 | ) |
||
| 2067 | )); |
||
| 2068 | |||
| 2069 | $body_highlighted = $message['body']; |
||
| 2070 | $subject_highlighted = $message['subject']; |
||
| 2071 | |||
| 2072 | if (!empty($options['display_quick_mod'])) |
||
| 2073 | { |
||
| 2074 | $started = $output['first_post']['member']['id'] == $user_info['id']; |
||
| 2075 | |||
| 2076 | $output['quick_mod'] = array( |
||
| 2077 | 'lock' => in_array(0, $boards_can['lock_any']) || in_array($output['board']['id'], $boards_can['lock_any']) || ($started && (in_array(0, $boards_can['lock_own']) || in_array($output['board']['id'], $boards_can['lock_own']))), |
||
| 2078 | 'sticky' => (in_array(0, $boards_can['make_sticky']) || in_array($output['board']['id'], $boards_can['make_sticky'])), |
||
| 2079 | 'move' => in_array(0, $boards_can['move_any']) || in_array($output['board']['id'], $boards_can['move_any']) || ($started && (in_array(0, $boards_can['move_own']) || in_array($output['board']['id'], $boards_can['move_own']))), |
||
| 2080 | 'remove' => in_array(0, $boards_can['remove_any']) || in_array($output['board']['id'], $boards_can['remove_any']) || ($started && (in_array(0, $boards_can['remove_own']) || in_array($output['board']['id'], $boards_can['remove_own']))), |
||
| 2081 | 'restore' => $context['can_restore_perm'] && ($modSettings['recycle_board'] == $output['board']['id']), |
||
| 2082 | ); |
||
| 2083 | |||
| 2084 | $context['can_lock'] |= $output['quick_mod']['lock']; |
||
| 2085 | $context['can_sticky'] |= $output['quick_mod']['sticky']; |
||
| 2086 | $context['can_move'] |= $output['quick_mod']['move']; |
||
| 2087 | $context['can_remove'] |= $output['quick_mod']['remove']; |
||
| 2088 | $context['can_merge'] |= in_array($output['board']['id'], $boards_can['merge_any']); |
||
| 2089 | $context['can_restore'] |= $output['quick_mod']['restore']; |
||
| 2090 | $context['can_markread'] = $context['user']['is_logged']; |
||
| 2091 | |||
| 2092 | $context['qmod_actions'] = array('remove', 'lock', 'sticky', 'move', 'merge', 'restore', 'markread'); |
||
| 2093 | call_integration_hook('integrate_quick_mod_actions_search'); |
||
| 2094 | } |
||
| 2095 | |||
| 2096 | foreach ($context['key_words'] as $query) |
||
| 2097 | { |
||
| 2098 | // Fix the international characters in the keyword too. |
||
| 2099 | $query = un_htmlspecialchars($query); |
||
| 2100 | $query = trim($query, "\*+"); |
||
| 2101 | $query = strtr($smcFunc['htmlspecialchars']($query), array('\\\'' => '\'')); |
||
| 2102 | |||
| 2103 | $body_highlighted = preg_replace_callback('/((<[^>]*)|' . preg_quote(strtr($query, array('\'' => ''')), '/') . ')/i' . ($context['utf8'] ? 'u' : ''), function ($m) |
||
| 2104 | { |
||
| 2105 | return isset($m[2]) && "$m[2]" == "$m[1]" ? stripslashes("$m[1]") : "<strong class=\"highlight\">$m[1]</strong>"; |
||
| 2106 | }, $body_highlighted); |
||
| 2107 | $subject_highlighted = preg_replace('/(' . preg_quote($query, '/') . ')/i' . ($context['utf8'] ? 'u' : ''), '<strong class="highlight">$1</strong>', $subject_highlighted); |
||
| 2108 | } |
||
| 2109 | |||
| 2110 | $output['matches'][] = array( |
||
| 2111 | 'id' => $message['id_msg'], |
||
| 2112 | 'attachment' => array(), |
||
| 2113 | 'member' => &$memberContext[$message['id_member']], |
||
| 2114 | 'icon' => $message['icon'], |
||
| 2115 | 'icon_url' => $settings[$context['icon_sources'][$message['icon']]] . '/post/' . $message['icon'] . '.png', |
||
| 2116 | 'subject' => $message['subject'], |
||
| 2117 | 'subject_highlighted' => $subject_highlighted, |
||
| 2118 | 'time' => timeformat($message['poster_time']), |
||
| 2119 | 'timestamp' => forum_time(true, $message['poster_time']), |
||
| 2120 | 'counter' => $counter, |
||
| 2121 | 'modified' => array( |
||
| 2122 | 'time' => timeformat($message['modified_time']), |
||
| 2123 | 'timestamp' => forum_time(true, $message['modified_time']), |
||
| 2124 | 'name' => $message['modified_name'] |
||
| 2125 | ), |
||
| 2126 | 'body' => $message['body'], |
||
| 2127 | 'body_highlighted' => $body_highlighted, |
||
| 2128 | 'start' => 'msg' . $message['id_msg'] |
||
| 2129 | ); |
||
| 2130 | $counter++; |
||
| 2131 | |||
| 2132 | call_integration_hook('integrate_search_message_context', array(&$output, &$message, $counter)); |
||
| 2133 | |||
| 2134 | return $output; |
||
| 2135 | } |
||
| 2136 | |||
| 2137 | /** |
||
| 2138 | * Creates a search API and returns the object. |
||
| 2139 | * |
||
| 2140 | * @return search_api_interface An instance of the search API interface |
||
| 2141 | */ |
||
| 2142 | function findSearchAPI() |
||
| 2143 | { |
||
| 2144 | global $sourcedir, $modSettings, $search_versions, $searchAPI, $txt; |
||
| 2145 | |||
| 2146 | require_once($sourcedir . '/Subs-Package.php'); |
||
| 2147 | require_once($sourcedir . '/Class-SearchAPI.php'); |
||
| 2148 | |||
| 2149 | // Search has a special database set. |
||
| 2150 | db_extend('search'); |
||
| 2151 | |||
| 2152 | // Load up the search API we are going to use. |
||
| 2153 | $modSettings['search_index'] = empty($modSettings['search_index']) ? 'standard' : $modSettings['search_index']; |
||
| 2154 | if (!file_exists($sourcedir . '/SearchAPI-' . ucwords($modSettings['search_index']) . '.php')) |
||
| 2155 | fatal_lang_error('search_api_missing'); |
||
| 2156 | require_once($sourcedir . '/SearchAPI-' . ucwords($modSettings['search_index']) . '.php'); |
||
| 2157 | |||
| 2158 | // Create an instance of the search API and check it is valid for this version of SMF. |
||
| 2159 | $search_class_name = $modSettings['search_index'] . '_search'; |
||
| 2160 | $searchAPI = new $search_class_name(); |
||
| 2161 | |||
| 2162 | // An invalid Search API. |
||
| 2163 | if (!$searchAPI || !($searchAPI instanceof search_api_interface) || ($searchAPI->supportsMethod('isValid') && !$searchAPI->isValid()) || !matchPackageVersion($search_versions['forum_version'], $searchAPI->min_smf_version . '-' . $searchAPI->version_compatible)) |
||
|
0 ignored issues
–
show
Accessing
min_smf_version on the interface search_api_interface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
Loading history...
Accessing
version_compatible on the interface search_api_interface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
Loading history...
|
|||
| 2164 | { |
||
| 2165 | // Log the error. |
||
| 2166 | loadLanguage('Errors'); |
||
| 2167 | log_error(sprintf($txt['search_api_not_compatible'], 'SearchAPI-' . ucwords($modSettings['search_index']) . '.php'), 'critical'); |
||
| 2168 | |||
| 2169 | require_once($sourcedir . '/SearchAPI-Standard.php'); |
||
| 2170 | $searchAPI = new standard_search(); |
||
| 2171 | } |
||
| 2172 | |||
| 2173 | return $searchAPI; |
||
| 2174 | } |
||
| 2175 | |||
| 2176 | /** |
||
| 2177 | * This function compares the length of two strings plus a little. |
||
| 2178 | * What it does: |
||
| 2179 | * - callback function for usort used to sort the fulltext results. |
||
| 2180 | * - passes sorting duty to the current API. |
||
| 2181 | * |
||
| 2182 | * @param string $a |
||
| 2183 | * @param string $b |
||
| 2184 | * @return int |
||
| 2185 | */ |
||
| 2186 | function searchSort($a, $b) |
||
| 2187 | { |
||
| 2188 | global $searchAPI; |
||
| 2189 | |||
| 2190 | return $searchAPI->searchSort($a, $b); |
||
| 2191 | } |
||
| 2192 | |||
| 2193 | ?> |
If you suppress an error, we recommend checking for the error condition explicitly: