improve scoring to store to presubmitted localhost, fix style and
[ViQa-Kissu.git] / search.php
blob394aa3ffcb9509b5ee4d939158d063b5f1adbb7c
1 <?php
2 require 'inc/functions.php';
4 if (!$config['search']['enable']) {
5 die(_("Post search is disabled"));
8 $queries_per_minutes = $config['search']['queries_per_minutes'];
9 $queries_per_minutes_all = $config['search']['queries_per_minutes_all'];
10 $search_limit = $config['search']['search_limit'];
12 if (isset($config['search']['boards'])) {
13 $boards = $config['search']['boards'];
14 } else {
15 $boards = listBoards(TRUE);
18 $body = Element('search_form.html', Array('boards' => $boards, 'board' => isset($_GET['board']) ? $_GET['board'] : false, 'search' => isset($_GET['search']) ? str_replace('"', '&quot;', utf8tohtml($_GET['search'])) : false));
20 if(isset($_GET['search']) && !empty($_GET['search']) && isset($_GET['board']) && in_array($_GET['board'], $boards)) {
21 $phrase = $_GET['search'];
22 $_body = '';
24 $query = prepare("SELECT COUNT(*) FROM ``search_queries`` WHERE `ip` = :ip AND `time` > :time");
25 $query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
26 $query->bindValue(':time', time() - ($queries_per_minutes[1] * 60));
27 $query->execute() or error(db_error($query));
28 if($query->fetchColumn() > $queries_per_minutes[0])
29 error(_('Wait a while before searching again, please.'));
31 $query = prepare("SELECT COUNT(*) FROM ``search_queries`` WHERE `time` > :time");
32 $query->bindValue(':time', time() - ($queries_per_minutes_all[1] * 60));
33 $query->execute() or error(db_error($query));
34 if($query->fetchColumn() > $queries_per_minutes_all[0])
35 error(_('Wait a while before searching again, please.'));
38 $query = prepare("INSERT INTO ``search_queries`` VALUES (:ip, :time, :query)");
39 $query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
40 $query->bindValue(':time', time());
41 $query->bindValue(':query', $phrase);
42 $query->execute() or error(db_error($query));
44 _syslog(LOG_NOTICE, 'Searched /' . $_GET['board'] . '/ for "' . $phrase . '"');
46 // Cleanup search queries table
47 $query = prepare("DELETE FROM ``search_queries`` WHERE `time` <= :time");
48 $query->bindValue(':time', time() - ($queries_per_minutes_all[1] * 60));
49 $query->execute() or error(db_error($query));
51 openBoard($_GET['board']);
53 $filters = Array();
55 function search_filters($m) {
56 global $filters;
57 $name = $m[2];
58 $value = isset($m[4]) ? $m[4] : $m[3];
60 if(!in_array($name, array('id', 'thread', 'subject', 'name'))) {
61 // unknown filter
62 return $m[0];
65 $filters[$name] = $value;
67 return $m[1];
70 $phrase = trim(preg_replace_callback('/(^|\s)(\w+):("(.*)?"|[^\s]*)/', 'search_filters', $phrase));
72 if(!preg_match('/[^*^\s]/', $phrase) && empty($filters)) {
73 _syslog(LOG_WARNING, 'Query too broad.');
74 $body .= '<p class="unimportant" style="text-align:center">(Query too broad.)</p>';
75 echo Element('page.html', Array(
76 'config'=>$config,
77 'title'=>'Search',
78 'body'=>$body,
79 ));
80 exit;
83 // Escape escape character
84 $phrase = str_replace('!', '!!', $phrase);
86 // Remove SQL wildcard
87 $phrase = str_replace('%', '!%', $phrase);
89 // Use asterisk as wildcard to suit convention
90 $phrase = str_replace('*', '%', $phrase);
92 // Remove `, it's used by table prefix magic
93 $phrase = str_replace('`', '!`', $phrase);
95 $like = '';
96 $match = Array();
98 // Find exact phrases
99 if(preg_match_all('/"(.+?)"/', $phrase, $m)) {
100 foreach($m[1] as &$quote) {
101 $phrase = str_replace("\"{$quote}\"", '', $phrase);
102 $match[] = $pdo->quote($quote);
106 $words = explode(' ', $phrase);
107 foreach($words as &$word) {
108 if(empty($word))
109 continue;
110 $match[] = $pdo->quote($word);
113 $like = '';
114 foreach($match as &$phrase) {
115 if(!empty($like))
116 $like .= ' AND ';
117 $phrase = preg_replace('/^\'(.+)\'$/', '\'%$1%\'', $phrase);
118 $like .= '`body` LIKE ' . $phrase . ' ESCAPE \'!\'';
121 foreach($filters as $name => $value) {
122 if(!empty($like))
123 $like .= ' AND ';
124 $like .= '`' . $name . '` = '. $pdo->quote($value);
127 $like = str_replace('%', '%%', $like);
129 $query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE " . $like . " ORDER BY `time` DESC LIMIT :limit", $board['uri']));
130 $query->bindValue(':limit', $search_limit, PDO::PARAM_INT);
131 $query->execute() or error(db_error($query));
133 if($query->rowCount() == $search_limit) {
134 _syslog(LOG_WARNING, 'Query too broad.');
135 $body .= '<p class="unimportant" style="text-align:center">('._('Query too broad.').')</p>';
136 echo Element('page.html', Array(
137 'config'=>$config,
138 'title'=>'Search',
139 'body'=>$body,
141 exit;
144 $temp = '';
145 while($post = $query->fetch()) {
146 if(!$post['thread']) {
147 $po = new Thread($post);
148 } else {
149 $po = new Post($post);
151 $temp .= $po->build(true) . '<hr/>';
154 if(!empty($temp))
155 $_body .= '<fieldset><legend>' .
156 sprintf(ngettext('%d result in', '%d results in', $query->rowCount()),
157 $query->rowCount()) . ' <a href="/' .
158 sprintf($config['board_path'], $board['uri']) . $config['file_index'] .
159 '">' .
160 sprintf($config['board_abbreviation'], $board['uri']) . ' - ' . $board['title'] .
161 '</a></legend>' . $temp . '</fieldset>';
163 $body .= '<hr/>';
164 if(!empty($_body))
165 $body .= $_body;
166 else
167 $body .= '<p style="text-align:center" class="unimportant">('._('No results.').')</p>';
170 echo Element('page.html', Array(
171 'config'=>$config,
172 'title'=>_('Search'),
173 'body'=>'' . $body