MDL-19821 Converted print_box* to $OUTPUT->box*
[moodle.git] / search / query.php
CommitLineData
682d4032 1<?php
3319ef85 2 /**
3 * Global Search Engine for Moodle
4 *
5 * @package search
6 * @category core
7 * @subpackage search_engine
8 * @author Michael Champanis (mchampan) [cynnical@gmail.com], Valery Fremaux [valery.fremaux@club-internet.fr] > 1.8
9 * @date 2008/03/31
10 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
11 *
12 * The query page - accepts a user-entered query string and returns results.
13 *
14 * Queries are boolean-aware, e.g.:
15 *
16 * '+' term required
17 * '-' term must not be present
18 * '' (no modifier) term's presence increases rank, but isn't required
19 * 'field:' search this field
20 *
21 * Examples:
22 *
23 * 'earthquake +author:michael'
24 * Searches for documents written by 'michael' that contain 'earthquake'
25 *
26 * 'earthquake +doctype:wiki'
27 * Search all wiki pages for 'earthquake'
28 *
29 * '+author:helen +author:foster'
30 * All articles written by Helen Foster
31 *
32 */
964a5e92 33
3319ef85 34 /**
35 * includes and requires
36 */
37 require_once('../config.php');
964a5e92 38 require_once($CFG->dirroot.'/search/lib.php');
eef868d1 39
3319ef85 40 if ($CFG->forcelogin) {
41 require_login();
42 }
964a5e92 43
3319ef85 44 if (empty($CFG->enableglobalsearch)) {
32487831 45 print_error('globalsearchdisabled', 'search');
3319ef85 46 }
964a5e92 47
3319ef85 48 $adv = new Object();
964a5e92 49
3319ef85 50/// check for php5, but don't die yet (see line 52)
eef868d1 51
964a5e92 52 require_once($CFG->dirroot.'/search/querylib.php');
32487831 53
964a5e92 54 $page_number = optional_param('page', -1, PARAM_INT);
55 $pages = ($page_number == -1) ? false : true;
56 $advanced = (optional_param('a', '0', PARAM_INT) == '1') ? true : false;
57 $query_string = stripslashes(optional_param('query_string', '', PARAM_CLEAN));
32487831 58
964a5e92 59/// discard harmfull searches
32487831 60
964a5e92 61 if (!isset($CFG->block_search_utf8dir)){
62 set_config('block_search_utf8dir', 1);
63 }
64
65/// discard harmfull searches
32487831 66
964a5e92 67 if (preg_match("/^[\*\?]+$/", $query_string)){
68 $query_string = '';
69 $error = get_string('fullwildcardquery','search');
70 }
71
72
73 if ($pages && isset($_SESSION['search_advanced_query'])) {
74 // if both are set, then we are busy browsing through the result pages of an advanced query
75 $adv = unserialize($_SESSION['search_advanced_query']);
76 } elseif ($advanced) {
77 // otherwise we are dealing with a new advanced query
78 unset($_SESSION['search_advanced_query']);
79 session_unregister('search_advanced_query');
80
81 // chars to strip from strings (whitespace)
82 $chars = " \t\n\r\0\x0B,-+";
83
84 // retrieve advanced query variables
85 $adv->mustappear = trim(optional_param('mustappear', '', PARAM_CLEAN), $chars);
86 $adv->notappear = trim(optional_param('notappear', '', PARAM_CLEAN), $chars);
87 $adv->canappear = trim(optional_param('canappear', '', PARAM_CLEAN), $chars);
88 $adv->module = optional_param('module', '', PARAM_CLEAN);
89 $adv->title = trim(optional_param('title', '', PARAM_CLEAN), $chars);
90 $adv->author = trim(optional_param('author', '', PARAM_CLEAN), $chars);
91 }
92
93 if ($advanced) {
94 //parse the advanced variables into a query string
95 //TODO: move out to external query class (QueryParse?)
96
97 $query_string = '';
98
99 // get all available module types adding third party modules
100 $module_types = array_merge(array('all'), array_values(search_get_document_types()));
101 $module_types = array_merge($module_types, array_values(search_get_document_types('X_SEARCH_TYPE')));
102 $adv->module = in_array($adv->module, $module_types) ? $adv->module : 'all';
103
104 // convert '1 2' into '+1 +2' for required words field
105 if (strlen(trim($adv->mustappear)) > 0) {
106 $query_string = ' +'.implode(' +', preg_split("/[\s,;]+/", $adv->mustappear));
107 }
108
109 // convert '1 2' into '-1 -2' for not wanted words field
110 if (strlen(trim($adv->notappear)) > 0) {
111 $query_string .= ' -'.implode(' -', preg_split("/[\s,;]+/", $adv->notappear));
112 }
113
114 // this field is left untouched, apart from whitespace being stripped
115 if (strlen(trim($adv->canappear)) > 0) {
116 $query_string .= ' '.implode(' ', preg_split("/[\s,;]+/", $adv->canappear));
117 }
118
119 // add module restriction
4021d539 120 $doctypestr = 'doctype';
121 $titlestr = 'title';
122 $authorstr = 'author';
964a5e92 123 if ($adv->module != 'all') {
124 $query_string .= " +{$doctypestr}:".$adv->module;
125 }
126
127 // create title search string
128 if (strlen(trim($adv->title)) > 0) {
129 $query_string .= " +{$titlestr}:".implode(" +{$titlestr}:", preg_split("/[\s,;]+/", $adv->title));
130 }
131
132 // create author search string
133 if (strlen(trim($adv->author)) > 0) {
134 $query_string .= " +{$authorstr}:".implode(" +{$authorstr}:", preg_split("/[\s,;]+/", $adv->author));
135 }
136
137 // save our options if the query is valid
138 if (!empty($query_string)) {
139 $_SESSION['search_advanced_query'] = serialize($adv);
140 }
141 }
142
143 // normalise page number
144 if ($page_number < 1) {
145 $page_number = 1;
146 }
147
148 //run the query against the index ensuring internal coding works in UTF-8
149 Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive());
150 $sq = new SearchQuery($query_string, $page_number, 10, false);
151
3319ef85 152 if (!$site = get_site()) {
153 redirect("index.php");
964a5e92 154 }
155
3319ef85 156 $strsearch = get_string('search', 'search');
157 $strquery = get_string('enteryoursearchquery', 'search');
964a5e92 158
159 // print the header
160 $navlinks[] = array('name' => $strsearch, 'link' => "index.php", 'type' => 'misc');
161 $navlinks[] = array('name' => $strquery, 'link' => null, 'type' => 'misc');
162 $navigation = build_navigation($navlinks);
163 $site = get_site();
164 print_header("$strsearch", "$site->fullname" , $navigation, '', '', true, '&nbsp;', navmenu($site));
165
e3c7f155 166 if (!empty($error)){
167 notice ($error);
168 }
964a5e92 169
2f338ab5 170 print_box_start();
f7a1496e 171 echo $OUTPUT->heading($strquery);
964a5e92 172
3319ef85 173 print_box_start();
964a5e92 174
3319ef85 175 $vars = get_object_vars($adv);
964a5e92 176
3319ef85 177 if (isset($vars)) {
178 foreach ($vars as $key => $value) {
964a5e92 179 // htmlentities breaks non-ascii chars ??
180 $adv->key = stripslashes($value);
181 //$adv->$key = stripslashes(htmlentities($value));
182 }
3319ef85 183 }
184 ?>
3319ef85 185 <form id="query" method="get" action="query.php">
964a5e92 186 <?php
187 if (!$advanced) {
3319ef85 188 ?>
964a5e92 189 <input type="text" name="query_string" length="50" value="<?php p($query_string) ?>" />&nbsp;
190 <input type="submit" value="<?php print_string('search', 'search') ?>" /> &nbsp;
3319ef85 191 <a href="query.php?a=1"><?php print_string('advancedsearch', 'search') ?></a> |
192 <a href="stats.php"><?php print_string('statistics', 'search') ?></a>
964a5e92 193 <?php
194 }
e3c7f155 195 else {
3319ef85 196 print_box_start();
197 ?>
198 <input type="hidden" name="a" value="<?php print $advanced; ?>"/>
964a5e92 199
3319ef85 200 <table border="0" cellpadding="3" cellspacing="3">
964a5e92 201
3319ef85 202 <tr>
203 <td width="240"><?php print_string('thesewordsmustappear', 'search') ?>:</td>
204 <td><input type="text" name="mustappear" length="50" value="<?php print $adv->mustappear; ?>" /></td>
205 </tr>
964a5e92 206
3319ef85 207 <tr>
208 <td><?php print_string('thesewordsmustnotappear', 'search') ?>:</td>
209 <td><input type="text" name="notappear" length="50" value="<?php print $adv->notappear; ?>" /></td>
210 </tr>
964a5e92 211
3319ef85 212 <tr>
213 <td><?php print_string('thesewordshelpimproverank', 'search') ?>:</td>
214 <td><input type="text" name="canappear" length="50" value="<?php print $adv->canappear; ?>" /></td>
215 </tr>
964a5e92 216
3319ef85 217 <tr>
218 <td><?php print_string('whichmodulestosearch?', 'search') ?>:</td>
219 <td>
220 <select name="module">
964a5e92 221 <?php
3319ef85 222 foreach($module_types as $mod) {
223 if ($mod == $adv->module) {
224 if ($mod != 'all'){
225 print "<option value='$mod' selected=\"selected\">".get_string('modulenameplural', $mod)."</option>\n";
226 }
227 else{
228 print "<option value='$mod' selected=\"selected\">".get_string('all', 'search')."</option>\n";
229 }
964a5e92 230 }
3319ef85 231 else {
232 if ($mod != 'all'){
233 print "<option value='$mod'>".get_string('modulenameplural', $mod)."</option>\n";
234 }
235 else{
236 print "<option value='$mod'>".get_string('all', 'search')."</option>\n";
237 }
964a5e92 238 }
239 }
3319ef85 240 ?>
241 </select>
242 </td>
243 </tr>
964a5e92 244
3319ef85 245 <tr>
246 <td><?php print_string('wordsintitle', 'search') ?>:</td>
247 <td><input type="text" name="title" length="50" value="<?php print $adv->title; ?>" /></td>
248 </tr>
964a5e92 249
3319ef85 250 <tr>
251 <td><?php print_string('authorname', 'search') ?>:</td>
252 <td><input type="text" name="author" length="50" value="<?php print $adv->author; ?>" /></td>
253 </tr>
964a5e92 254
3319ef85 255 <tr>
256 <td colspan="3" align="center"><br /><input type="submit" value="<?php print_string('search', 'search') ?>" /></td>
257 </tr>
964a5e92 258
3319ef85 259 <tr>
260 <td colspan="3" align="center">
261 <table border="0" cellpadding="0" cellspacing="0">
262 <tr>
263 <td><a href="query.php"><?php print_string('normalsearch', 'search') ?></a> |</td>
264 <td>&nbsp;<a href="stats.php"><?php print_string('statistics', 'search') ?></a></td>
265 </tr>
266 </table>
267 </td>
268 </tr>
6e780562 269 </table>
3319ef85 270 <?php
271 print_box_end();
964a5e92 272 }
3319ef85 273 ?>
274 </form>
275 <br/>
4021d539 276
277 <div align="center">
3319ef85 278 <?php
279 print_string('searching', 'search') . ': ';
964a5e92 280
3319ef85 281 if ($sq->is_valid_index()) {
282 //use cached variable to show up-to-date index size (takes deletions into account)
283 print $CFG->search_index_size;
964a5e92 284 }
e3c7f155 285 else {
3319ef85 286 print "0";
964a5e92 287 }
288
3319ef85 289 print ' ';
290 print_string('documents', 'search');
291 print '.';
964a5e92 292
e3c7f155 293 if (!$sq->is_valid_index() and has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))) {
3319ef85 294 print '<p>' . get_string('noindexmessage', 'search') . '<a href="indexersplash.php">' . get_string('createanindex', 'search')."</a></p>\n";
964a5e92 295 }
296
3319ef85 297 ?>
298 </div>
299 <?php
300 print_box_end();
964a5e92 301
3efa38a4 302/// prints all the results in a box
303
3319ef85 304 if ($sq->is_valid()) {
305 print_box_start();
964a5e92 306
3319ef85 307 search_stopwatch();
308 $hit_count = $sq->count();
964a5e92 309
3319ef85 310 print "<br />";
964a5e92 311
decf9db1 312 print $hit_count.' '.get_string('resultsreturnedfor', 'search') . " '".s($query_string)."'.";
3319ef85 313 print "<br />";
964a5e92 314
3319ef85 315 if ($hit_count > 0) {
316 $page_links = $sq->page_numbers();
317 $hits = $sq->results();
964a5e92 318
3319ef85 319 if ($advanced) {
320 // if in advanced mode, search options are saved in the session, so
321 // we can remove the query string var from the page links, and replace
322 // it with a=1 (Advanced = on) instead
323 $page_links = preg_replace("/query_string=[^&]+/", 'a=1', $page_links);
964a5e92 324 }
325
3319ef85 326 print "<ol>";
964a5e92 327
3319ef85 328 $typestr = get_string('type', 'search');
329 $scorestr = get_string('score', 'search');
330 $authorstr = get_string('author', 'search');
3efa38a4 331
332 $searchables = search_collect_searchables(false, false);
333
964a5e92 334 foreach ($hits as $listing) {
335
336 if ($listing->doctype == 'user'){ // A special handle for users
4021d539 337 $icon = print_user_picture ($listing->userid, 0, true, 0, true, false) ;
964a5e92 338 } else {
e63f88c9 339 $iconpath = $OUTPUT->mod_icon_url('icon', $listing->doctype);
964a5e92 340 $icon = "<img align=\"top\" src=\"".$iconpath."\" class=\"activityicon\" alt=\"\"/>";
341 }
342 $coursename = $DB->get_field('course', 'fullname', array('id' => $listing->courseid));
3efa38a4 343 $courseword = mb_convert_case(get_string('course', 'moodle'), MB_CASE_LOWER, 'UTF-8');
964a5e92 344 $course = ($listing->doctype != 'user') ? '<strong> ('.$courseword.': \''.$coursename.'\')</strong>' : '' ;
345
3319ef85 346 $title_post_processing_function = $listing->doctype.'_link_post_processing';
3efa38a4 347 $searchable_instance = $searchables[$listing->doctype];
348 if ($searchable_instance->location == 'internal'){
349 require_once "{$CFG->dirroot}/search/documents/{$listing->doctype}_document.php";
350 } else {
351 require_once "{$CFG->dirroot}/{$searchable_instance->location}/{$listing->doctype}/search_document.php";
352 }
3319ef85 353 if (function_exists($title_post_processing_function)) {
354 $listing->title = $title_post_processing_function($listing->title);
355 }
964a5e92 356
357 echo "<li value='".($listing->number + 1)."'><a href='"
3efa38a4 358 .str_replace('DEFAULT_POPUP_SETTINGS', DEFAULT_POPUP_SETTINGS ,$listing->url)
964a5e92 359 ."'>$icon $listing->title</a> $course<br />\n";
360 echo "{$typestr}: " . $listing->doctype . ", {$scorestr}: " . round($listing->score, 3);
361 if (!empty($listing->author) && !is_numeric($listing->author)){
3efa38a4 362 echo ", {$authorstr}: ".$listing->author."\n"
b93b987d 363 ."</li>\n";
364 }
964a5e92 365 }
3efa38a4 366 echo "</ol>";
367 echo $page_links;
964a5e92 368 }
3319ef85 369 print_box_end();
370 ?>
4021d539 371 <div align="center">
85db96c5 372 <?php
3319ef85 373 print_string('ittook', 'search');
964a5e92 374 search_stopwatch();
3319ef85 375 print_string('tofetchtheseresults', 'search');
376 ?>.
377 </div>
964a5e92 378
3319ef85 379 <?php
380 }
2f338ab5 381 print_box_end();
daa2cd33 382 echo $OUTPUT->footer();
f7a1496e 383?>