Fixed couple bugs in query, and improved logic of querylib.
[moodle.git] / search / query.php
CommitLineData
682d4032 1<?php
2
a25a3912 3 /* The query page - accepts a user-entered query string and returns results.
4 *
5 * Queries are boolean-aware, e.g.:
6 *
7 * '+' term required
8 * '-' term must not be present
9 * '' (no modifier) term's presence increases rank, but isn't required
10 * 'field:' search this field
11 *
12 * Examples:
13 *
14 * 'earthquake +author:michael'
15 * Searches for documents written by 'michael' that contain 'earthquake'
16 *
17 * 'earthquake +doctype:wiki'
18 * Search all wiki pages for 'earthquake'
19 *
20 * '+author:helen +author:foster'
21 * All articles written by Helen Foster
22 *
23 * */
6e780562 24
b585dc5f 25 require_once('../config.php');
91ad9557 26 require_once("$CFG->dirroot/search/lib.php");
682d4032 27
b585dc5f 28 //check for php5, but don't die yet (see line 52)
29 if ($check = search_check_php5()) {
791a4cec 30 require_once("$CFG->dirroot/search/querylib.php");
682d4032 31
791a4cec 32 $page_number = optional_param('page', -1, PARAM_INT);
33 $pages = ($page_number == -1) ? false : true;
34 $advanced = (optional_param('a', '0', PARAM_INT) == '1') ? true : false;
6e780562 35 $query_string = optional_param('query_string', '', PARAM_CLEAN);
36
37 if ($pages && isset($_SESSION['search_advanced_query'])) {
791a4cec 38 //if both are set, then we are busy browsing through the result pages of an advanced query
6e780562 39 $adv = unserialize($_SESSION['search_advanced_query']);
40 } else if ($advanced) {
791a4cec 41 //otherwise we are dealing with a new advanced query
6e780562 42 unset($_SESSION['search_advanced_query']);
43 session_unregister('search_advanced_query');
0d46c846 44
45 //chars to strip from strings (whitespace)
46 $chars = " \t\n\r\0\x0B,-+";
6e780562 47
791a4cec 48 //retrieve advanced query variables
6e780562 49 $adv->mustappear = trim(optional_param('mustappear', '', PARAM_CLEAN), $chars);
50 $adv->notappear = trim(optional_param('notappear', '', PARAM_CLEAN), $chars);
51 $adv->canappear = trim(optional_param('canappear', '', PARAM_CLEAN), $chars);
52 $adv->module = optional_param('module', '', PARAM_CLEAN);
53 $adv->title = trim(optional_param('title', '', PARAM_CLEAN), $chars);
54 $adv->author = trim(optional_param('author', '', PARAM_CLEAN), $chars);
55 } //else
56
57 if ($advanced) {
791a4cec 58 //parse the advanced variables into a query string
59 //TODO: move out to external query class (QueryParse?)
60
6e780562 61 $query_string = '';
62
791a4cec 63 //get all available module types
6e780562 64 $module_types = array_merge(array('All'), array_values(search_get_document_types()));
65 $adv->module = in_array($adv->module, $module_types) ? $adv->module : 'All';
66
791a4cec 67 //convert '1 2' into '+1 +2' for required words field
6e780562 68 if (strlen(trim($adv->mustappear)) > 0) {
69 $query_string = ' +'.implode(' +', preg_split("/[\s,;]+/", $adv->mustappear));
70 } //if
71
791a4cec 72 //convert '1 2' into '-1 -2' for not wanted words field
6e780562 73 if (strlen(trim($adv->notappear)) > 0) {
74 $query_string .= ' -'.implode(' -', preg_split("/[\s,;]+/", $adv->notappear));
75 } //if
76
791a4cec 77 //this field is left untouched, apart from whitespace being stripped
6e780562 78 if (strlen(trim($adv->canappear)) > 0) {
79 $query_string .= ' '.implode(' ', preg_split("/[\s,;]+/", $adv->canappear));
80 } //if
81
791a4cec 82 //add module restriction
6e780562 83 if ($adv->module != 'All') {
84 $query_string .= ' +doctype:'.$adv->module;
85 } //if
86
791a4cec 87 //create title search string
6e780562 88 if (strlen(trim($adv->title)) > 0) {
89 $query_string .= ' +title:'.implode(' +title:', preg_split("/[\s,;]+/", $adv->title));
90 } //if
91
791a4cec 92 //create author search string
6e780562 93 if (strlen(trim($adv->author)) > 0) {
94 $query_string .= ' +author:'.implode(' +author:', preg_split("/[\s,;]+/", $adv->author));
95 } //if
96
791a4cec 97 //save our options if the query is valid
6e780562 98 if (!empty($query_string)) {
99 $_SESSION['search_advanced_query'] = serialize($adv);
100 } //if
101 } //if
102
791a4cec 103 //normalise page number
a25a3912 104 if ($page_number < 1) {
105 $page_number = 1;
791a4cec 106 } //if
682d4032 107
791a4cec 108 //run the query against the index
0d46c846 109 $sq = new SearchQuery($query_string, $page_number, 10, false);
91ad9557 110 } //if
111
682d4032 112 if (!$site = get_site()) {
113 redirect("index.php");
114 } //if
a25a3912 115
682d4032 116 $strsearch = "Search"; //get_string();
117 $strquery = "Enter your search query"; //get_string();
118
119 print_header("$site->shortname: $strsearch: $strquery", "$site->fullname",
120 "<a href=\"index.php\">$strsearch</a> -> $strquery");
121
122 //keep things pretty, even if php5 isn't available
123 if (!$check) {
124 print_heading(search_check_php5(true));
125 print_footer();
126 exit(0);
127 } //if
128
129 print_simple_box_start('center', '100%', '', 20);
130 print_heading($strquery);
131
132 print_simple_box_start('center', '', '', 20);
6e780562 133
134 $vars = get_object_vars($adv);
135
136 foreach ($vars as $key => $value) {
137 $adv->$key = stripslashes(htmlentities($value));
138 } //foreach
abb4ea20 139
682d4032 140?>
141
142<form name="query" method="get" action="query.php">
6e780562 143 <?php if (!$advanced) { ?>
144 <input type="text" name="query_string" length="50" value="<?php print stripslashes(htmlentities($query_string)) ?>"/>
145 &nbsp;<input type="submit" value="Search"/>&nbsp;&nbsp;
146 <a href="query.php?a=1">Advanced search</a>
147 <a href="stats.php">Statistics</a>
148 <?php } else {
149 print_simple_box_start('center', '', 'white', 10);
150 ?>
151 <input type="hidden" name="a" value="<?php print $advanced; ?>"/>
152
153 <table border="0" cellpadding="3" cellspacing="3">
154
155 <tr>
156 <td width="240">These words must appear:</td>
157 <td><input type="text" name="mustappear" length="50" value="<?php print $adv->mustappear; ?>"/></td>
158 </tr>
159
160 <tr>
161 <td>These words must not appear:</td>
162 <td><input type="text" name="notappear" length="50" value="<?php print $adv->notappear; ?>"/></td>
163 </tr>
164
165 <tr>
166 <td>These words help improve rank:</td>
167 <td><input type="text" name="canappear" length="50" value="<?php print $adv->canappear; ?>"/></td>
168 </tr>
169
170 <tr>
171 <td>Which modules to search?:</td>
172 <td>
173 <select name="module">
174 <?php foreach($module_types as $mod) {
175 if ($mod == $adv->module) {
176 print "<option value='$mod' selected>$mod</option>\n";
177 } else {
178 print "<option value='$mod'>$mod</option>\n";
179 } //else
180 } ?>
181 </select>
182 </td>
183 </tr>
184
185 <tr>
186 <td>Words in title:</td>
187 <td><input type="text" name="title" length="50" value="<?php print $adv->title; ?>"/></td>
188 </tr>
189
190 <tr>
191 <td>Author name:</td>
192 <td><input type="text" name="author" length="50" value="<?php print $adv->author; ?>"/></td>
193 </tr>
194
195 <tr>
196 <td colspan="3" align="center"><br><input type="submit" value="Search"/></td>
197 </tr>
198
199 <tr>
200 <td colspan="3" align="center">
201 <table border="0" cellpadding="0" cellspacing="0">
202 <tr>
203 <td><a href="query.php">Normal search</a>&nbsp;</td>
204 <td>&nbsp;<a href="stats.php">Statistics</a></td>
205 </tr>
206 </table>
207 </td>
208 </tr>
209 </table>
210 <?php
211 print_simple_box_end();
212 } //if
213 ?>
682d4032 214</form>
215
216<br>
217
682d4032 218<?php
6e780562 219
220 print '<div align="center">';
b585dc5f 221 print 'Searching: ';
91ad9557 222
b585dc5f 223 if ($sq->is_valid_index()) {
791a4cec 224 //use cached variable to show up-to-date index size (takes deletions into account)
225 print $CFG->search_index_size;
91ad9557 226 } else {
b585dc5f 227 print "0";
91ad9557 228 } //else
229
230 print ' documents.';
231
b585dc5f 232 if (!$sq->is_valid_index() and isadmin()) {
91ad9557 233 print "<br><br>Admin: There appears to be no index, click <a href='indexersplash.php'>here</a> to create one.";
234 } //if
682d4032 235
6e780562 236 print '</div>';
237
682d4032 238 print_simple_box_end();
239
b585dc5f 240 if ($sq->is_valid()) {
682d4032 241 print_simple_box_start('center', '50%', 'white', 10);
242
b585dc5f 243 search_stopwatch();
244 $hit_count = $sq->count();
682d4032 245
246 print "<br>";
247
a25a3912 248 print $hit_count." results returned for '".stripslashes($query_string)."'.";
249 print "<br>";
250
6e780562 251 if ($hit_count > 0) {
252 $page_links = $sq->page_numbers();
b585dc5f 253 $hits = $sq->results();
6e780562 254
255 if ($advanced) {
791a4cec 256 //if in advanced mode, search options are saved in the session, so
257 //we can remove the query string var from the page links, and replace
258 //it with a=1 (Advanced = on) instead
259 $page_links = preg_replace("/query_string=[^&]+/", 'a=1', $page_links);
6e780562 260 } //if
a25a3912 261
262 print "<ol>";
682d4032 263
b585dc5f 264 foreach ($hits as $listing) {
265 print "<li value='".($listing->number+1)."'><a href='".$listing->url."'>$listing->title</a><br>\n"
a25a3912 266 ."<em>".search_shorten_url($listing->url, 70)."</em><br>\n"
267 ."Type: ".$listing->doctype.", score: ".round($listing->score, 3).", author: ".$listing->author."<br>\n"
268 ."<br></li>\n";
269 } //for
270
271 print "</ol>";
91ad9557 272 print $page_links;
273 } //if
682d4032 274
275 print_simple_box_end();
682d4032 276?>
277
278<div align="center">
279 It took <?php search_stopwatch(); ?> to fetch these results.
280</div>
281
282<?php
b585dc5f 283 } //if (sq is valid)
682d4032 284
285 print_simple_box_end();
286 print_footer();
287?>