search.php: (untested) refactor, using SearchService
This commit is contained in:
parent
7e99708d0a
commit
75d51a500c
1 changed files with 46 additions and 160 deletions
206
search.php
206
search.php
|
@ -1,181 +1,67 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Vichan\Service\SearchService;
|
||||||
|
|
||||||
require 'inc/bootstrap.php';
|
require 'inc/bootstrap.php';
|
||||||
|
|
||||||
if (!$config['search']['enable']) {
|
if (!$config['search']['enable']) {
|
||||||
die(_("Post search is disabled"));
|
die(_("Post search is disabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
$queries_per_minutes = $config['search']['queries_per_minutes'];
|
$ctx = Vichan\build_context($config);
|
||||||
$queries_per_minutes_all = $config['search']['queries_per_minutes_all'];
|
$search_service = $ctx->get(SearchService::class);
|
||||||
$search_limit = $config['search']['search_limit'];
|
|
||||||
|
|
||||||
if (isset($config['search']['boards'])) {
|
if (isset($_GET['search']) && !empty($_GET['search'])) {
|
||||||
$boards = $config['search']['boards'];
|
$raw_search = $_GET['search'];
|
||||||
} else {
|
$ip = $_SERVER['REMOTE_ADDR'];
|
||||||
$boards = listBoards(TRUE);
|
$fallback_board = (isset($_GET['board']) && !empty($_GET['board'])) ? $_GET['board'] : null;
|
||||||
}
|
|
||||||
|
|
||||||
|
if ($search_service->checkFlood($ip, $raw_search)) {
|
||||||
|
error(_('Wait a while before searching again, please.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually do the search.
|
||||||
|
$parse_res = $search_service->parse($raw_search);
|
||||||
|
$filters = $search_service->reduceAndWeight($parse_res);
|
||||||
|
$search_res = $search_service->search($ip, $raw_search, $filters, $fallback_board);
|
||||||
|
|
||||||
|
|
||||||
|
// Needed to set a global variable further down the stack, plus the template.
|
||||||
|
$actual_board = $filter->board ?? $fallback_board;
|
||||||
|
|
||||||
if (isset($_GET['search']) && !empty($_GET['search']) && isset($_GET['board']) && in_array($_GET['board'], $boards)) {
|
|
||||||
$body = Element('search_form.html', [
|
$body = Element('search_form.html', [
|
||||||
'boards' => $boards,
|
'boards' => $search_service->getSearchableBoards(),
|
||||||
'board' => $_GET['board'],
|
'board' => $_GET['board'],
|
||||||
'search' => \str_replace('"', '"', utf8tohtml($_GET['search']))
|
'search' => \str_replace('"', '"', utf8tohtml($_GET['search']))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$phrase = $_GET['search'];
|
if (empty($search_res)) {
|
||||||
$_body = '';
|
$body .= '<hr/><p style="text-align:center" class="unimportant">(' . _('No results.') . ')</p>';
|
||||||
|
|
||||||
$query = prepare("SELECT COUNT(*) FROM ``search_queries`` WHERE `ip` = :ip AND `time` > :time");
|
|
||||||
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
|
||||||
$query->bindValue(':time', time() - ($queries_per_minutes[1] * 60));
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
if ($query->fetchColumn() > $queries_per_minutes[0])
|
|
||||||
error(_('Wait a while before searching again, please.'));
|
|
||||||
|
|
||||||
$query = prepare("SELECT COUNT(*) FROM ``search_queries`` WHERE `time` > :time");
|
|
||||||
$query->bindValue(':time', time() - ($queries_per_minutes_all[1] * 60));
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
if ($query->fetchColumn() > $queries_per_minutes_all[0])
|
|
||||||
error(_('Wait a while before searching again, please.'));
|
|
||||||
|
|
||||||
|
|
||||||
$query = prepare("INSERT INTO ``search_queries`` VALUES (:ip, :time, :query)");
|
|
||||||
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
|
||||||
$query->bindValue(':time', time());
|
|
||||||
$query->bindValue(':query', $phrase);
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
|
|
||||||
_syslog(LOG_NOTICE, 'Searched /' . $_GET['board'] . '/ for "' . $phrase . '"');
|
|
||||||
|
|
||||||
// Cleanup search queries table
|
|
||||||
$query = prepare("DELETE FROM ``search_queries`` WHERE `time` <= :time");
|
|
||||||
$query->bindValue(':time', time() - ($queries_per_minutes_all[1] * 60));
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
|
|
||||||
openBoard($_GET['board']);
|
|
||||||
|
|
||||||
$filters = Array();
|
|
||||||
|
|
||||||
function search_filters($m) {
|
|
||||||
global $filters;
|
|
||||||
$name = $m[2];
|
|
||||||
$value = isset($m[4]) ? $m[4] : $m[3];
|
|
||||||
|
|
||||||
if (!in_array($name, array('id', 'thread', 'subject', 'name'))) {
|
|
||||||
// unknown filter
|
|
||||||
return $m[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
$filters[$name] = $value;
|
|
||||||
|
|
||||||
return $m[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
$phrase = trim(preg_replace_callback('/(^|\s)(\w+):("(.*)?"|[^\s]*)/', 'search_filters', $phrase));
|
|
||||||
|
|
||||||
if (!preg_match('/[^*^\s]/', $phrase) && empty($filters)) {
|
|
||||||
_syslog(LOG_WARNING, 'Query too broad.');
|
|
||||||
$body .= '<p class="unimportant" style="text-align:center">(Query too broad.)</p>';
|
|
||||||
echo Element('page.html', Array(
|
|
||||||
'config'=>$config,
|
|
||||||
'title'=>'Search',
|
|
||||||
'body'=>$body,
|
|
||||||
));
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Escape escape character
|
|
||||||
$phrase = str_replace('!', '!!', $phrase);
|
|
||||||
|
|
||||||
// Remove SQL wildcard
|
|
||||||
$phrase = str_replace('%', '!%', $phrase);
|
|
||||||
|
|
||||||
// Use asterisk as wildcard to suit convention
|
|
||||||
$phrase = str_replace('*', '%', $phrase);
|
|
||||||
|
|
||||||
// Remove `, it's used by table prefix magic
|
|
||||||
$phrase = str_replace('`', '!`', $phrase);
|
|
||||||
|
|
||||||
$like = '';
|
|
||||||
$match = Array();
|
|
||||||
|
|
||||||
// Find exact phrases
|
|
||||||
if (preg_match_all('/"(.+?)"/', $phrase, $m)) {
|
|
||||||
foreach($m[1] as &$quote) {
|
|
||||||
$phrase = str_replace("\"{$quote}\"", '', $phrase);
|
|
||||||
$match[] = $pdo->quote($quote);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$words = explode(' ', $phrase);
|
|
||||||
foreach($words as &$word) {
|
|
||||||
if (empty($word)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$match[] = $pdo->quote($word);
|
|
||||||
}
|
|
||||||
|
|
||||||
$like = '';
|
|
||||||
foreach($match as &$phrase) {
|
|
||||||
if (!empty($like)) {
|
|
||||||
$like .= ' AND ';
|
|
||||||
}
|
|
||||||
$phrase = preg_replace('/^\'(.+)\'$/', '\'%$1%\'', $phrase);
|
|
||||||
$like .= '`body` LIKE ' . $phrase . ' ESCAPE \'!\'';
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($filters as $name => $value) {
|
|
||||||
if (!empty($like)) {
|
|
||||||
$like .= ' AND ';
|
|
||||||
}
|
|
||||||
$like .= '`' . $name . '` = '. $pdo->quote($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
$like = str_replace('%', '%%', $like);
|
|
||||||
|
|
||||||
$query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE " . $like . " ORDER BY `time` DESC LIMIT :limit", $board['uri']));
|
|
||||||
$query->bindValue(':limit', $search_limit, PDO::PARAM_INT);
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
|
|
||||||
if ($query->rowCount() == $search_limit) {
|
|
||||||
_syslog(LOG_WARNING, 'Query too broad.');
|
|
||||||
$body .= '<p class="unimportant" style="text-align:center">('._('Query too broad.').')</p>';
|
|
||||||
echo Element('page.html', Array(
|
|
||||||
'config'=>$config,
|
|
||||||
'title'=>'Search',
|
|
||||||
'body'=>$body,
|
|
||||||
));
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$temp = '';
|
|
||||||
while ($post = $query->fetch()) {
|
|
||||||
if (!$post['thread']) {
|
|
||||||
$po = new Thread($post);
|
|
||||||
} else {
|
|
||||||
$po = new Post($post);
|
|
||||||
}
|
|
||||||
$temp .= $po->build(true) . '<hr/>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($temp))
|
|
||||||
$_body .= '<fieldset><legend>' .
|
|
||||||
sprintf(ngettext('%d result in', '%d results in', $query->rowCount()),
|
|
||||||
$query->rowCount()) . ' <a href="/' .
|
|
||||||
sprintf($config['board_path'], $board['uri']) . $config['file_index'] .
|
|
||||||
'">' .
|
|
||||||
sprintf($config['board_abbreviation'], $board['uri']) . ' - ' . $board['title'] .
|
|
||||||
'</a></legend>' . $temp . '</fieldset>';
|
|
||||||
|
|
||||||
$body .= '<hr/>';
|
|
||||||
if (!empty($_body)) {
|
|
||||||
$body .= $_body;
|
|
||||||
} else {
|
} else {
|
||||||
$body .= '<p style="text-align:center" class="unimportant">('._('No results.').')</p>';
|
$body .= '<hr/>';
|
||||||
|
|
||||||
|
openBoard($actual_board);
|
||||||
|
|
||||||
|
$posts_html = '';
|
||||||
|
foreach ($search_res as $post) {
|
||||||
|
if (!$post['thread']) {
|
||||||
|
$po = new Thread($post);
|
||||||
|
} else {
|
||||||
|
$po = new Post($post);
|
||||||
|
}
|
||||||
|
$posts_html .= $po->build(true) . '<hr/>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$body .= '<fieldset><legend>' .
|
||||||
|
sprintf(ngettext('%d result in', '%d results in', \count($search_res)), \count($search_res)) . ' <a href="/' .
|
||||||
|
sprintf($config['board_path'], $board['uri']) . $config['file_index'] . '">' .
|
||||||
|
sprintf($config['board_abbreviation'], $board['uri']) . ' - ' . $board['title'] .
|
||||||
|
'</a></legend>' . $posts_html . '</fieldset>';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$body = Element('search_form.html', [
|
$body = Element('search_form.html', [
|
||||||
'boards' => $boards,
|
'boards' => $search_service->getSearchableBoards(),
|
||||||
'board' => false,
|
'board' => false,
|
||||||
'search' => false
|
'search' => false
|
||||||
]);
|
]);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue