1 | <?php |
||
2 | |||
3 | /** |
||
4 | * Utility class for search functionality. |
||
5 | * |
||
6 | * @package ElkArte Forum |
||
7 | * @copyright ElkArte Forum contributors |
||
8 | * @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file) |
||
9 | * |
||
10 | * This file contains code covered by: |
||
11 | * copyright: 2011 Simple Machines (http://www.simplemachines.org) |
||
12 | * |
||
13 | * @version 2.0 dev |
||
14 | * |
||
15 | */ |
||
16 | |||
17 | namespace ElkArte\Search; |
||
18 | |||
19 | use ElkArte\Database\QueryInterface; |
||
20 | use ElkArte\Exceptions\Exception; |
||
21 | use ElkArte\Helper\DataValidator; |
||
22 | use ElkArte\Helper\HttpReq; |
||
23 | use ElkArte\Helper\Util; |
||
24 | use ElkArte\Helper\ValuesContainer; |
||
25 | use ElkArte\User; |
||
26 | |||
27 | /** |
||
28 | * Actually do the searches |
||
29 | */ |
||
30 | class SearchParams extends ValuesContainer |
||
31 | { |
||
32 | /** @var string the db query for members */ |
||
33 | public $_userQuery = ''; |
||
34 | |||
35 | /** @var string The db query for brd's */ |
||
36 | public $_boardQuery = ''; |
||
37 | |||
38 | /** @var int Needed to calculate relevance */ |
||
39 | public $_minMsg = 0; |
||
40 | |||
41 | /** @var int The minimum message id we will search, needed to calculate relevance */ |
||
42 | public $_minMsgID = 0; |
||
43 | |||
44 | /** @var int The maximum message ID we will search, needed to calculate relevance */ |
||
45 | public $_maxMsgID = 0; |
||
46 | |||
47 | /** @var int Message "age" via ID, given bounds, needed to calculate relevance */ |
||
48 | public $_recentMsg = 0; |
||
49 | |||
50 | /** @var int[] */ |
||
51 | public $_memberlist = []; |
||
52 | |||
53 | /** @var QueryInterface|null */ |
||
54 | protected $_db; |
||
55 | |||
56 | /** @var HttpReq HttpReq instance */ |
||
57 | protected $_req; |
||
58 | |||
59 | /** |
||
60 | * $_search_params will carry all settings that differ from the default search parameters. |
||
61 | * That way, the URLs involved in a search page will be kept as short as possible. |
||
62 | * |
||
63 | * @var mixed |
||
64 | */ |
||
65 | protected $_search_params = []; |
||
66 | |||
67 | /** |
||
68 | * Constructor |
||
69 | * |
||
70 | * @param string $_search_string The string containing encoded search params |
||
71 | * @package Search |
||
72 | */ |
||
73 | public function __construct(protected $_search_string) |
||
74 | { |
||
75 | $this->_db = database(); |
||
76 | $this->prepare(); |
||
77 | $this->data = &$this->_search_params; |
||
78 | $this->_req = HttpReq::instance(); |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * Extract search params from a string |
||
83 | */ |
||
84 | protected function prepare() |
||
85 | { |
||
86 | // Due to IE's 2083 character limit, we have to compress long search strings |
||
87 | $temp_params = base64_decode(str_replace(['-', '_', '.'], ['+', '/', '='], $this->_search_string)); |
||
88 | |||
89 | // Test for gzuncompress failing, our ErrorException will die on any E_WARNING with no |
||
90 | // Exception, so turn it off/on for this check. |
||
91 | set_error_handler(static function () { /* ignore errors */ }); |
||
92 | try |
||
93 | { |
||
94 | $check = gzuncompress($temp_params); |
||
95 | } |
||
96 | catch (\Exception) |
||
97 | { |
||
98 | $check = $temp_params; |
||
99 | 2 | } |
|
100 | finally |
||
101 | 2 | { |
|
102 | 2 | restore_error_handler(); |
|
103 | 2 | } |
|
104 | 2 | ||
105 | 2 | $this->_search_params = json_decode($check, true); |
|
106 | } |
||
107 | |||
108 | /** |
||
109 | * Encodes search params ($this->_search_params) in an URL-compatible way |
||
110 | 2 | * |
|
111 | * @param array $search build param index with specific search term (did you mean?) |
||
112 | * |
||
113 | 2 | * @return string - the encoded string to be appended to the URL |
|
114 | */ |
||
115 | public function compileURL($search = []) |
||
116 | 2 | { |
|
117 | 2 | $temp_params = $this->_search_params; |
|
118 | |||
119 | 2 | if (!empty($search)) |
|
120 | { |
||
121 | 2 | $temp_params['search'] = implode(' ', $search); |
|
122 | 2 | } |
|
123 | |||
124 | // *** Encode all search params |
||
125 | 2 | // All search params have been checked, let's compile them to a single string. |
|
126 | $encoded = json_encode($temp_params); |
||
127 | |||
128 | // Due to some potential browser/server limitations, attempt to compress |
||
129 | 2 | // old IE's 2083 character limit, we have to compress long search |
|
130 | set_error_handler(static function () { /* ignore errors */ }); |
||
131 | try |
||
132 | { |
||
133 | $compressed = gzcompress($encoded); |
||
134 | } |
||
135 | catch (\Exception) |
||
136 | { |
||
137 | $compressed = $encoded; |
||
138 | 2 | } |
|
139 | finally |
||
140 | 2 | { |
|
141 | 2 | restore_error_handler(); |
|
142 | } |
||
143 | 2 | ||
144 | return str_replace(['+', '/', '='], ['-', '_', '.'], base64_encode($compressed)); |
||
145 | } |
||
146 | |||
147 | /** |
||
148 | * Merge search params extracted with SearchParams::prepare |
||
149 | * with those present in the $param array (usually $_REQUEST['params']) |
||
150 | 2 | * |
|
151 | * @param array $params - An array of search parameters |
||
152 | 2 | * @param int $recentPercentage - A coefficient to calculate the lowest message id to start search from |
|
153 | * @param int $maxMembersToSearch - The maximum number of members to consider when multiple are found |
||
154 | */ |
||
155 | 2 | public function merge($params, $recentPercentage, $maxMembersToSearch) |
|
156 | { |
||
157 | 2 | global $modSettings; |
|
158 | |||
159 | // Determine the search settings from the form or get params |
||
160 | 2 | $this->cleanParams($params); |
|
161 | $this->setAdvanced($params); |
||
162 | $this->setSearchType($params); |
||
163 | 2 | $this->setMinMaxAge($params); |
|
164 | $this->setTopic($params); |
||
165 | $this->setUser($params); |
||
166 | 2 | ||
167 | // If there's no specific user, then don't mention it in the main query. |
||
168 | if (empty($this->_search_params['userspec'])) |
||
169 | { |
||
170 | $this->_userQuery = ''; |
||
171 | } |
||
172 | 2 | else |
|
173 | { |
||
174 | $this->buildUserQuery($maxMembersToSearch); |
||
175 | } |
||
176 | |||
177 | // Ensure that boards are an array of integers (or nothing). |
||
178 | $query_boards = $this->setBoards($params); |
||
179 | 2 | ||
180 | // What boards are we searching in, all, selected, limited due to a topic? |
||
181 | $this->_search_params['brd'] = $this->setTopicBoardLimit($query_boards); |
||
182 | $this->_boardQuery = $this->setBoardQuery(); |
||
183 | |||
184 | $this->_search_params['show_complete'] = !empty($this->_search_params['show_complete']) || !empty($params['show_complete']); |
||
185 | $this->_search_params['subject_only'] = !empty($this->_search_params['subject_only']) || !empty($params['subject_only']); |
||
186 | |||
187 | // Get the sorting parameters right. Default to sort by relevance descending. |
||
188 | $this->setSortAndDirection($params); |
||
189 | |||
190 | // Determine some values needed to calculate the relevance. |
||
191 | $this->_minMsg = (int) ceil((1 - $recentPercentage) * $modSettings['maxMsgID']); |
||
192 | $this->_recentMsg = $modSettings['maxMsgID'] - $this->_minMsg; |
||
193 | |||
194 | 2 | // *** Parse the search query |
|
195 | call_integration_hook('integrate_search_params', [&$this->_search_params]); |
||
196 | 2 | ||
197 | // What are we searching for? |
||
198 | $this->_search_params['search'] = $this->setSearchTerm(); |
||
199 | 2 | } |
|
200 | |||
201 | 2 | /** |
|
202 | * Cast the passed params to what we demand they be |
||
203 | * |
||
204 | * @param mixed $params |
||
205 | 2 | */ |
|
206 | public function cleanParams(&$params) |
||
207 | { |
||
208 | $validator = new DataValidator(); |
||
209 | |||
210 | // Convert dates to days between now and ... |
||
211 | 2 | $params['minage'] = $this->daysBetween($params['minage'] ?? null, 0); |
|
212 | $params['maxage'] = $this->daysBetween($params['maxage'] ?? null, 9999); |
||
213 | |||
214 | $validator->sanitation_rules([ |
||
215 | 'advanced' => 'intval', |
||
216 | 'searchtype' => 'intval', |
||
217 | 2 | 'minage' => 'intval', |
|
218 | 'maxage' => 'intval', |
||
219 | 'search_selection' => 'intval', |
||
220 | 'topic' => 'intval', |
||
221 | 'sd_topic' => 'intval', |
||
222 | 'userspec' => 'trim', |
||
223 | 2 | 'brd' => 'intval', |
|
224 | 'sort' => 'trim', |
||
225 | 'show_complete' => 'boolval', |
||
226 | 'sd_brd' => 'intval' |
||
227 | ]); |
||
228 | 2 | $validator->input_processing([ |
|
229 | 'brd' => 'array', |
||
230 | 'sd_brd' => 'array' |
||
231 | ]); |
||
232 | $validator->validate($params); |
||
233 | 2 | ||
234 | $params = array_replace((array) $params, $validator->validation_data()); |
||
235 | } |
||
236 | |||
237 | /** |
||
238 | * Sets if using the advanced search mode |
||
239 | * |
||
240 | * @param mixed $params |
||
241 | */ |
||
242 | public function setAdvanced($params) |
||
243 | { |
||
244 | // Store whether simple search was used (needed if the user wants to do another query). |
||
245 | if (!isset($this->_search_params['advanced'])) |
||
246 | { |
||
247 | $this->_search_params['advanced'] = empty($params['advanced']) ? 0 : 1; |
||
248 | } |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * Set the search type to all or any |
||
253 | * |
||
254 | * @param mixed $params |
||
255 | */ |
||
256 | public function setSearchType($params) |
||
257 | { |
||
258 | 2 | // 1 => 'allwords' (default, don't set as param) / 2 => 'anywords'. |
|
259 | if (!empty($this->_search_params['searchtype']) || (!empty($params['searchtype']) && $params['searchtype'] === 2)) |
||
260 | { |
||
261 | $this->_search_params['searchtype'] = 2; |
||
262 | } |
||
263 | } |
||
264 | 2 | ||
265 | /** |
||
266 | 2 | * Sets the timeline to search in, if any, for messages |
|
267 | * |
||
268 | * @param mixed $params |
||
269 | */ |
||
270 | public function setMinMaxAge($params) |
||
271 | { |
||
272 | // Minimum age of messages. Default to zero (don't set param in that case). |
||
273 | if (!empty($this->_search_params['minage']) || (!empty($params['minage']) && $params['minage'] > 0)) |
||
274 | { |
||
275 | $this->_search_params['minage'] = empty($this->_search_params['minage']) ? $params['minage'] : $this->_search_params['minage']; |
||
276 | } |
||
277 | |||
278 | // Maximum age of messages. Default to infinite (9999 days: param not set). |
||
279 | if (!empty($this->_search_params['maxage']) || (!empty($params['maxage']) && $params['maxage'] < 9999)) |
||
280 | { |
||
281 | $this->_search_params['maxage'] = empty($this->_search_params['maxage']) ? $params['maxage'] : $this->_search_params['maxage']; |
||
282 | } |
||
283 | |||
284 | if (!empty($this->_search_params['minage']) || !empty($this->_search_params['maxage'])) |
||
285 | { |
||
286 | $this->getMinMaxLimits(); |
||
287 | } |
||
288 | } |
||
289 | |||
290 | /** |
||
291 | * Determines and sets the min and max message ID based on timelines of min/max |
||
292 | */ |
||
293 | private function getMinMaxLimits() |
||
294 | { |
||
295 | global $modSettings, $context; |
||
296 | |||
297 | $request = $this->_db->query('', ' |
||
0 ignored issues
–
show
|
|||
298 | SELECT ' . |
||
299 | (empty($this->_search_params['maxage']) ? '0, ' : 'COALESCE(MIN(id_msg), -1), ') . (empty($this->_search_params['minage']) ? '0' : 'COALESCE(MAX(id_msg), -1)') . ' |
||
300 | FROM {db_prefix}messages |
||
301 | WHERE 1=1' . ($modSettings['postmod_active'] ? ' |
||
302 | AND approved = {int:is_approved_true}' : '') . (empty($this->_search_params['minage']) ? '' : ' |
||
303 | AND poster_time <= {int:timestamp_minimum_age}') . (empty($this->_search_params['maxage']) ? '' : ' |
||
304 | AND poster_time >= {int:timestamp_maximum_age}'), |
||
305 | [ |
||
306 | 'timestamp_minimum_age' => empty($this->_search_params['minage']) ? 0 : time() - 86400 * $this->_search_params['minage'], |
||
307 | 'timestamp_maximum_age' => empty($this->_search_params['maxage']) ? 0 : time() - 86400 * $this->_search_params['maxage'], |
||
308 | 'is_approved_true' => 1, |
||
309 | ] |
||
310 | ); |
||
311 | [$this->_minMsgID, $this->_maxMsgID] = $request->fetch_row(); |
||
312 | $this->_minMsgID = (int) $this->_minMsgID; |
||
313 | $this->_maxMsgID = (int) $this->_maxMsgID; |
||
314 | if ($this->_minMsgID < 0 || $this->_maxMsgID < 0) |
||
315 | { |
||
316 | $context['search_errors']['no_messages_in_time_frame'] = true; |
||
317 | } |
||
318 | } |
||
319 | |||
320 | /** |
||
321 | * Set the topic to search in, if any |
||
322 | * |
||
323 | * @param mixed $params |
||
324 | */ |
||
325 | public function setTopic($params) |
||
326 | { |
||
327 | // Searching a specific topic? |
||
328 | if (!empty($params['topic']) || (!empty($params['search_selection']) && $params['search_selection'] === 'topic')) |
||
329 | { |
||
330 | $this->_search_params['topic'] = empty($params['search_selection']) ? (int) $params['topic'] : ($params['sd_topic'] ?? ''); |
||
331 | $this->_search_params['show_complete'] = true; |
||
332 | } |
||
333 | } |
||
334 | |||
335 | /** |
||
336 | * Set the search by user value, if any |
||
337 | * |
||
338 | * @param mixed $params |
||
339 | */ |
||
340 | public function setUser($params) |
||
341 | { |
||
342 | // Default the user name to a wildcard matching every user (*). |
||
343 | 2 | if (!empty($this->_search_params['userspec']) || (!empty($params['userspec']) && $params['userspec'] !== '*')) |
|
344 | { |
||
345 | $this->_search_params['userspec'] = $this->_search_params['userspec'] ?? $params['userspec']; |
||
346 | } |
||
347 | 2 | } |
|
348 | |||
349 | /** |
||
350 | * So you want to search for items based on a specific user, or group of users or wildcard users? |
||
351 | 2 | * |
|
352 | * Will use real_name first and if nothing found, backup to member_name |
||
353 | * |
||
354 | * @param int $maxMembersToSearch |
||
355 | 2 | */ |
|
356 | public function buildUserQuery($maxMembersToSearch) |
||
357 | { |
||
358 | $userString = strtr(Util::htmlspecialchars($this->_search_params['userspec'], ENT_QUOTES), ['"' => '"']); |
||
359 | 2 | $userString = strtr($userString, ['%' => '\%', '_' => '\_', '*' => '%', '?' => '_']); |
|
360 | |||
361 | preg_match_all('~"([^"]+)"~', $userString, $matches); |
||
362 | $possible_users = array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $userString))); |
||
363 | $possible_users = array_map('trim', $possible_users); |
||
364 | $possible_users = array_filter($possible_users); |
||
365 | 2 | ||
366 | // Create a list of database-escaped search names. |
||
367 | $realNameMatches = []; |
||
368 | foreach ($possible_users as $possible_user) |
||
369 | 2 | { |
|
370 | $realNameMatches[] = $this->_db->quote( |
||
371 | '{string:possible_user}', |
||
372 | [ |
||
373 | 'possible_user' => $possible_user |
||
374 | ] |
||
375 | ); |
||
376 | } |
||
377 | |||
378 | // Retrieve a list of possible members. |
||
379 | $request = $this->_db->query('', ' |
||
380 | SELECT |
||
381 | id_member |
||
382 | FROM {db_prefix}members |
||
383 | WHERE {raw:match_possible_users}', |
||
384 | [ |
||
385 | 'match_possible_users' => 'real_name LIKE ' . implode(' OR real_name LIKE ', $realNameMatches), |
||
386 | ] |
||
387 | ); |
||
388 | |||
389 | // Simply do nothing if there're too many members matching the criteria. |
||
390 | if ($request->num_rows() > $maxMembersToSearch) |
||
391 | { |
||
392 | $this->_userQuery = ''; |
||
393 | } |
||
394 | // Nothing? lets try the poster name instead since that is what they go by |
||
395 | elseif ($request->num_rows() === 0) |
||
396 | 2 | { |
|
397 | $this->_userQuery = $this->_db->quote( |
||
398 | 'm.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})', |
||
399 | [ |
||
400 | 'id_member_guest' => 0, |
||
401 | 'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', $realNameMatches), |
||
402 | 2 | ] |
|
403 | 2 | ); |
|
404 | } |
||
405 | // We have some users! |
||
406 | 2 | else |
|
407 | { |
||
408 | while (($row = $request->fetch_assoc())) |
||
409 | { |
||
410 | $this->_memberlist[] = $row['id_member']; |
||
411 | } |
||
412 | 2 | ||
413 | $this->_userQuery = $this->_db->quote( |
||
414 | 2 | '(m.id_member IN ({array_int:matched_members}) OR (m.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})))', |
|
415 | [ |
||
416 | 2 | 'matched_members' => $this->_memberlist, |
|
417 | 'id_member_guest' => 0, |
||
418 | 'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', $realNameMatches), |
||
419 | ] |
||
420 | 2 | ); |
|
421 | 2 | } |
|
422 | |||
423 | 2 | $request->free_result(); |
|
424 | } |
||
425 | 2 | ||
426 | /** |
||
427 | * Figures what boards we have been requested to search in. Does not check |
||
428 | * permissions at this point. |
||
429 | * |
||
430 | * @param $params |
||
431 | * @return int[] |
||
432 | */ |
||
433 | 2 | public function setBoards($params) |
|
434 | { |
||
435 | if (!empty($this->_search_params['brd']) && is_array($this->_search_params['brd'])) |
||
436 | { |
||
437 | return $this->_search_params['brd']; |
||
438 | } |
||
439 | |||
440 | if (!empty($params['brd']) && is_array($params['brd'])) |
||
441 | 2 | { |
|
442 | 2 | return $params['brd']; |
|
443 | } |
||
444 | |||
445 | if (!empty($params['search_selection']) && $params['search_selection'] === 'board' && !empty($params['sd_brd']) && is_array($params['sd_brd'])) |
||
446 | 2 | { |
|
447 | return $params['sd_brd']; |
||
448 | } |
||
449 | |||
450 | return []; |
||
451 | } |
||
452 | 2 | ||
453 | /** |
||
454 | 2 | * Determines what boards you can or should be searching |
|
455 | * |
||
456 | * @param $query_boards |
||
457 | * @return int[] array of boards to search in |
||
458 | * @throws Exception topic_gone |
||
459 | 2 | */ |
|
460 | public function setTopicBoardLimit($query_boards) |
||
461 | 2 | { |
|
462 | global $modSettings, $context; |
||
463 | |||
464 | // Searching by topic means the board is set as well. |
||
465 | if (!empty($this->_search_params['topic'])) |
||
466 | { |
||
467 | 2 | $request = $this->_db->query('', ' |
|
468 | SELECT |
||
469 | b.id_board |
||
470 | 2 | FROM {db_prefix}topics AS t |
|
471 | 2 | INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) |
|
472 | WHERE t.id_topic = {int:search_topic_id} |
||
473 | AND {query_see_board}' . ($modSettings['postmod_active'] ? ' |
||
474 | 2 | AND t.approved = {int:is_approved_true}' : '') . ' |
|
475 | LIMIT 1', |
||
476 | [ |
||
477 | 2 | 'search_topic_id' => $this->_search_params['topic'], |
|
478 | 'is_approved_true' => 1, |
||
479 | 2 | ] |
|
480 | ); |
||
481 | 2 | if ($request->num_rows() === 0) |
|
482 | { |
||
483 | throw new Exception('topic_gone', false); |
||
484 | } |
||
485 | |||
486 | $this->_search_params['brd'] = []; |
||
487 | $brd = (int) $request->fetch_row()[0]; |
||
488 | |||
489 | $request->free_result(); |
||
490 | |||
491 | return [$brd]; |
||
492 | 2 | } |
|
493 | |||
494 | // Select all boards you've selected AND are allowed to see. |
||
495 | if (User::$info->is_admin && (!empty($this->_search_params['advanced']) || !empty($query_boards))) |
||
0 ignored issues
–
show
The property
is_admin does not exist on ElkArte\Helper\ValuesContainer . Since you implemented __get , consider adding a @property annotation.
![]() |
|||
496 | { |
||
497 | return $query_boards; |
||
498 | } |
||
499 | |||
500 | require_once(SUBSDIR . '/Boards.subs.php'); |
||
501 | $brd = array_keys(fetchBoardsInfo([ |
||
502 | 'boards' => $query_boards], [ |
||
503 | 'include_recycle' => false, |
||
504 | 'include_redirects' => false, |
||
505 | 'wanna_see_board' => empty($this->_search_params['advanced']) |
||
506 | ] |
||
507 | )); |
||
508 | |||
509 | // This error should pro'bly only happen for hackers. |
||
510 | if (empty($brd)) |
||
511 | { |
||
512 | $context['search_errors']['no_boards_selected'] = true; |
||
513 | $brd = []; |
||
514 | } |
||
515 | |||
516 | return $brd; |
||
517 | } |
||
518 | |||
519 | /** |
||
520 | * Builds the query for the boards we are searching in. |
||
521 | * |
||
522 | * @return string |
||
523 | */ |
||
524 | public function setBoardQuery() |
||
525 | { |
||
526 | if (count($this->_search_params['brd']) !== 0) |
||
527 | { |
||
528 | array_map('intval', $this->_search_params['brd']); |
||
529 | |||
530 | // If we've selected all boards, this parameter can be left empty. |
||
531 | require_once(SUBSDIR . '/Boards.subs.php'); |
||
532 | $num_boards = countBoards(); |
||
533 | |||
534 | if (count($this->_search_params['brd']) === $num_boards) |
||
535 | { |
||
536 | return $this->_boardQuery = ''; |
||
537 | } |
||
538 | |||
539 | if (count($this->_search_params['brd']) === $num_boards - 1 |
||
540 | && !empty($modSettings['recycle_board']) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
541 | && !in_array((int) $modSettings['recycle_board'], $this->_search_params['brd'], true)) |
||
542 | { |
||
543 | return $this->_boardQuery = '!= ' . $modSettings['recycle_board']; |
||
544 | } |
||
545 | |||
546 | return $this->_boardQuery = 'IN (' . implode(', ', $this->_search_params['brd']) . ')'; |
||
547 | } |
||
548 | |||
549 | return ''; |
||
550 | } |
||
551 | |||
552 | /** |
||
553 | * Sets the sort column and direction |
||
554 | * |
||
555 | * @event integrate_search_sort_columns |
||
556 | * @param mixed $params |
||
557 | */ |
||
558 | public function setSortAndDirection($params) |
||
559 | { |
||
560 | $sort_columns = ['relevance', 'num_replies', 'id_msg',]; |
||
561 | |||
562 | // Allow integration to add additional sort columns |
||
563 | call_integration_hook('integrate_search_sort_columns', [&$sort_columns]); |
||
564 | |||
565 | if (empty($this->_search_params['sort']) && !empty($params['sort'])) |
||
566 | { |
||
567 | [$this->_search_params['sort'], $this->_search_params['sort_dir']] = array_pad(explode('|', $params['sort']), 2, ''); |
||
568 | } |
||
569 | |||
570 | $this->_search_params['sort'] = !empty($this->_search_params['sort']) && in_array($this->_search_params['sort'], $sort_columns, true) ? $this->_search_params['sort'] : 'relevance'; |
||
571 | |||
572 | if (!empty($this->_search_params['topic']) && $this->_search_params['sort'] === 'num_replies') |
||
573 | { |
||
574 | $this->_search_params['sort'] = 'id_msg'; |
||
575 | } |
||
576 | |||
577 | // Sorting direction: descending unless stated otherwise. |
||
578 | $this->_search_params['sort_dir'] = !empty($this->_search_params['sort_dir']) && $this->_search_params['sort_dir'] === 'asc' ? 'asc' : 'desc'; |
||
579 | } |
||
580 | |||
581 | /** |
||
582 | * Set the search term from wherever we can find it! |
||
583 | * |
||
584 | * @return string |
||
585 | */ |
||
586 | public function setSearchTerm() |
||
587 | { |
||
588 | if (!empty($this->_search_params['search'])) |
||
589 | { |
||
590 | return $this->_search_params['search']; |
||
591 | } |
||
592 | |||
593 | return $this->_req->getRequest('search', 'un_htmlspecialchars', ''); |
||
594 | } |
||
595 | |||
596 | /** |
||
597 | * Return the current set of search details |
||
598 | * |
||
599 | * @return string[] |
||
600 | */ |
||
601 | public function get() |
||
602 | { |
||
603 | return $this->_search_params; |
||
604 | } |
||
605 | |||
606 | /** |
||
607 | * Number of days between today/now and some date. |
||
608 | * |
||
609 | * @param string $date |
||
610 | * @param int $default |
||
611 | * @return int |
||
612 | */ |
||
613 | private function daysBetween($date, $default) |
||
614 | { |
||
615 | // Already a number, validate |
||
616 | if (is_numeric($date)) |
||
617 | { |
||
618 | return (max(min(0, $date), 9999)); |
||
619 | } |
||
620 | |||
621 | // Nothing, then full range |
||
622 | if (empty($date)) |
||
623 | { |
||
624 | return $default; |
||
625 | } |
||
626 | |||
627 | $startTimeStamp = time(); |
||
628 | $endTimeStamp = strtotime($date); |
||
629 | $timeDiff = $startTimeStamp - ($endTimeStamp !== false ? $endTimeStamp : $startTimeStamp); |
||
630 | |||
631 | // Can't search into the future |
||
632 | if ($timeDiff < 1) |
||
633 | { |
||
634 | $timeDiff = 0; |
||
635 | } |
||
636 | |||
637 | return $timeDiff / 86400; |
||
638 | } |
||
639 | } |
||
640 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.