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 | */ |
32487831 |
33 | |
3319ef85 |
34 | /** |
35 | * includes and requires |
36 | */ |
37 | require_once('../config.php'); |
38 | require_once("$CFG->dirroot/search/lib.php"); |
eef868d1 |
39 | |
eef868d1 |
40 | |
3319ef85 |
41 | if ($CFG->forcelogin) { |
42 | require_login(); |
43 | } |
32487831 |
44 | |
3319ef85 |
45 | if (empty($CFG->enableglobalsearch)) { |
32487831 |
46 | print_error('globalsearchdisabled', 'search'); |
3319ef85 |
47 | } |
32487831 |
48 | |
3319ef85 |
49 | $adv = new Object(); |
32487831 |
50 | |
3319ef85 |
51 | /// check for php5, but don't die yet (see line 52) |
eef868d1 |
52 | |
e3c7f155 |
53 | require_once("{$CFG->dirroot}/search/querylib.php"); |
32487831 |
54 | |
e3c7f155 |
55 | $page_number = optional_param('page', -1, PARAM_INT); |
56 | $pages = ($page_number == -1) ? false : true; |
57 | $advanced = (optional_param('a', '0', PARAM_INT) == '1') ? true : false; |
58 | $query_string = optional_param('query_string', '', PARAM_CLEAN); |
32487831 |
59 | |
e3c7f155 |
60 | /** |
32487831 |
61 | * discard harmfull searches |
e3c7f155 |
62 | */ |
63 | if (preg_match("/^[\*\?]+$/", $query_string)){ |
64 | $query_string = ''; |
65 | $error = get_string('fullwildcardquery','search'); |
66 | } |
32487831 |
67 | |
68 | |
e3c7f155 |
69 | if ($pages && isset($_SESSION['search_advanced_query'])) { |
70 | // if both are set, then we are busy browsing through the result pages of an advanced query |
71 | $adv = unserialize($_SESSION['search_advanced_query']); |
72 | } elseif ($advanced) { |
73 | // otherwise we are dealing with a new advanced query |
74 | unset($_SESSION['search_advanced_query']); |
75 | session_unregister('search_advanced_query'); |
32487831 |
76 | |
e3c7f155 |
77 | // chars to strip from strings (whitespace) |
78 | $chars = " \t\n\r\0\x0B,-+"; |
32487831 |
79 | |
e3c7f155 |
80 | // retrieve advanced query variables |
81 | $adv->mustappear = trim(optional_param('mustappear', '', PARAM_CLEAN), $chars); |
82 | $adv->notappear = trim(optional_param('notappear', '', PARAM_CLEAN), $chars); |
83 | $adv->canappear = trim(optional_param('canappear', '', PARAM_CLEAN), $chars); |
84 | $adv->module = optional_param('module', '', PARAM_CLEAN); |
85 | $adv->title = trim(optional_param('title', '', PARAM_CLEAN), $chars); |
86 | $adv->author = trim(optional_param('author', '', PARAM_CLEAN), $chars); |
32487831 |
87 | } |
88 | |
e3c7f155 |
89 | if ($advanced) { |
90 | //parse the advanced variables into a query string |
91 | //TODO: move out to external query class (QueryParse?) |
32487831 |
92 | |
e3c7f155 |
93 | $query_string = ''; |
32487831 |
94 | |
3efa38a4 |
95 | // get all available module types adding third party modules |
e3c7f155 |
96 | $module_types = array_merge(array('all'), array_values(search_get_document_types())); |
3efa38a4 |
97 | $module_types = array_merge($module_types, array_values(search_get_document_types('X_SEARCH_TYPE'))); |
e3c7f155 |
98 | $adv->module = in_array($adv->module, $module_types) ? $adv->module : 'all'; |
32487831 |
99 | |
e3c7f155 |
100 | // convert '1 2' into '+1 +2' for required words field |
101 | if (strlen(trim($adv->mustappear)) > 0) { |
102 | $query_string = ' +'.implode(' +', preg_split("/[\s,;]+/", $adv->mustappear)); |
32487831 |
103 | } |
104 | |
e3c7f155 |
105 | // convert '1 2' into '-1 -2' for not wanted words field |
106 | if (strlen(trim($adv->notappear)) > 0) { |
107 | $query_string .= ' -'.implode(' -', preg_split("/[\s,;]+/", $adv->notappear)); |
32487831 |
108 | } |
109 | |
e3c7f155 |
110 | // this field is left untouched, apart from whitespace being stripped |
111 | if (strlen(trim($adv->canappear)) > 0) { |
112 | $query_string .= ' '.implode(' ', preg_split("/[\s,;]+/", $adv->canappear)); |
32487831 |
113 | } |
114 | |
e3c7f155 |
115 | // add module restriction |
116 | $doctypestr = get_string('doctype', 'search'); |
117 | $titlestr = get_string('title', 'search'); |
118 | $authorstr = get_string('author', 'search'); |
119 | if ($adv->module != 'all') { |
120 | $query_string .= " +{$doctypestr}:".$adv->module; |
32487831 |
121 | } |
122 | |
e3c7f155 |
123 | // create title search string |
124 | if (strlen(trim($adv->title)) > 0) { |
125 | $query_string .= " +{$titlestr}:".implode(" +{$titlestr}:", preg_split("/[\s,;]+/", $adv->title)); |
32487831 |
126 | } |
127 | |
e3c7f155 |
128 | // create author search string |
129 | if (strlen(trim($adv->author)) > 0) { |
130 | $query_string .= " +{$authorstr}:".implode(" +{$authorstr}:", preg_split("/[\s,;]+/", $adv->author)); |
32487831 |
131 | } |
132 | |
e3c7f155 |
133 | // save our options if the query is valid |
134 | if (!empty($query_string)) { |
135 | $_SESSION['search_advanced_query'] = serialize($adv); |
32487831 |
136 | } |
137 | } |
138 | |
e3c7f155 |
139 | // normalise page number |
140 | if ($page_number < 1) { |
141 | $page_number = 1; |
32487831 |
142 | } |
143 | |
3efa38a4 |
144 | //run the query against the index ensuring internal coding works in UTF-8 |
e3c7f155 |
145 | Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8()); |
146 | $sq = new SearchQuery($query_string, $page_number, 10, false); |
32487831 |
147 | |
3319ef85 |
148 | if (!$site = get_site()) { |
149 | redirect("index.php"); |
32487831 |
150 | } |
151 | |
3319ef85 |
152 | $strsearch = get_string('search', 'search'); |
153 | $strquery = get_string('enteryoursearchquery', 'search'); |
32487831 |
154 | |
adddd26d |
155 | // if ($CFG->version < 2007032200){ NOT RELIABLE |
156 | if (!function_exists('build_navigation')){ |
3319ef85 |
157 | print_header("$site->shortname: $strsearch: $strquery", "$site->fullname", |
158 | "<a href=\"index.php\">$strsearch</a> -> $strquery"); |
159 | } else { |
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, " ", navmenu($site)); |
165 | } |
32487831 |
166 | |
e3c7f155 |
167 | if (!empty($error)){ |
168 | notice ($error); |
169 | } |
32487831 |
170 | |
2f338ab5 |
171 | print_box_start(); |
3319ef85 |
172 | print_heading($strquery); |
32487831 |
173 | |
3319ef85 |
174 | print_box_start(); |
32487831 |
175 | |
3319ef85 |
176 | $vars = get_object_vars($adv); |
32487831 |
177 | |
3319ef85 |
178 | if (isset($vars)) { |
179 | foreach ($vars as $key => $value) { |
180 | // htmlentities breaks non-ascii chars |
decf9db1 |
181 | $adv->key = $value; |
182 | //$adv->$key = htmlentities($value); |
32487831 |
183 | } |
3319ef85 |
184 | } |
185 | ?> |
3319ef85 |
186 | <form id="query" method="get" action="query.php"> |
32487831 |
187 | <?php |
188 | if (!$advanced) { |
3319ef85 |
189 | ?> |
decf9db1 |
190 | <input type="text" name="query_string" length="50" value="<?php p($query_string) ?>" /> |
3319ef85 |
191 | <input type="submit" value="<?php print_string('search', 'search') ?>" /> |
192 | <a href="query.php?a=1"><?php print_string('advancedsearch', 'search') ?></a> | |
193 | <a href="stats.php"><?php print_string('statistics', 'search') ?></a> |
32487831 |
194 | <?php |
195 | } |
e3c7f155 |
196 | else { |
3319ef85 |
197 | print_box_start(); |
198 | ?> |
199 | <input type="hidden" name="a" value="<?php print $advanced; ?>"/> |
32487831 |
200 | |
3319ef85 |
201 | <table border="0" cellpadding="3" cellspacing="3"> |
32487831 |
202 | |
3319ef85 |
203 | <tr> |
204 | <td width="240"><?php print_string('thesewordsmustappear', 'search') ?>:</td> |
205 | <td><input type="text" name="mustappear" length="50" value="<?php print $adv->mustappear; ?>" /></td> |
206 | </tr> |
32487831 |
207 | |
3319ef85 |
208 | <tr> |
209 | <td><?php print_string('thesewordsmustnotappear', 'search') ?>:</td> |
210 | <td><input type="text" name="notappear" length="50" value="<?php print $adv->notappear; ?>" /></td> |
211 | </tr> |
32487831 |
212 | |
3319ef85 |
213 | <tr> |
214 | <td><?php print_string('thesewordshelpimproverank', 'search') ?>:</td> |
215 | <td><input type="text" name="canappear" length="50" value="<?php print $adv->canappear; ?>" /></td> |
216 | </tr> |
32487831 |
217 | |
3319ef85 |
218 | <tr> |
219 | <td><?php print_string('whichmodulestosearch?', 'search') ?>:</td> |
220 | <td> |
221 | <select name="module"> |
32487831 |
222 | <?php |
3319ef85 |
223 | foreach($module_types as $mod) { |
224 | if ($mod == $adv->module) { |
225 | if ($mod != 'all'){ |
226 | print "<option value='$mod' selected=\"selected\">".get_string('modulenameplural', $mod)."</option>\n"; |
227 | } |
228 | else{ |
229 | print "<option value='$mod' selected=\"selected\">".get_string('all', 'search')."</option>\n"; |
230 | } |
32487831 |
231 | } |
3319ef85 |
232 | else { |
233 | if ($mod != 'all'){ |
234 | print "<option value='$mod'>".get_string('modulenameplural', $mod)."</option>\n"; |
235 | } |
236 | else{ |
237 | print "<option value='$mod'>".get_string('all', 'search')."</option>\n"; |
238 | } |
32487831 |
239 | } |
240 | } |
3319ef85 |
241 | ?> |
242 | </select> |
243 | </td> |
244 | </tr> |
32487831 |
245 | |
3319ef85 |
246 | <tr> |
247 | <td><?php print_string('wordsintitle', 'search') ?>:</td> |
248 | <td><input type="text" name="title" length="50" value="<?php print $adv->title; ?>" /></td> |
249 | </tr> |
32487831 |
250 | |
3319ef85 |
251 | <tr> |
252 | <td><?php print_string('authorname', 'search') ?>:</td> |
253 | <td><input type="text" name="author" length="50" value="<?php print $adv->author; ?>" /></td> |
254 | </tr> |
32487831 |
255 | |
3319ef85 |
256 | <tr> |
257 | <td colspan="3" align="center"><br /><input type="submit" value="<?php print_string('search', 'search') ?>" /></td> |
258 | </tr> |
32487831 |
259 | |
3319ef85 |
260 | <tr> |
261 | <td colspan="3" align="center"> |
262 | <table border="0" cellpadding="0" cellspacing="0"> |
263 | <tr> |
264 | <td><a href="query.php"><?php print_string('normalsearch', 'search') ?></a> |</td> |
265 | <td> <a href="stats.php"><?php print_string('statistics', 'search') ?></a></td> |
266 | </tr> |
267 | </table> |
268 | </td> |
269 | </tr> |
6e780562 |
270 | </table> |
3319ef85 |
271 | <?php |
272 | print_box_end(); |
32487831 |
273 | } |
3319ef85 |
274 | ?> |
275 | </form> |
276 | <br/> |
85db96c5 |
277 | <div class="mdl-align"> |
3319ef85 |
278 | <?php |
279 | print_string('searching', 'search') . ': '; |
32487831 |
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; |
32487831 |
284 | } |
e3c7f155 |
285 | else { |
3319ef85 |
286 | print "0"; |
32487831 |
287 | } |
288 | |
3319ef85 |
289 | print ' '; |
290 | print_string('documents', 'search'); |
291 | print '.'; |
32487831 |
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"; |
32487831 |
295 | } |
296 | |
3319ef85 |
297 | ?> |
298 | </div> |
299 | <?php |
300 | print_box_end(); |
32487831 |
301 | |
3efa38a4 |
302 | /// prints all the results in a box |
303 | |
3319ef85 |
304 | if ($sq->is_valid()) { |
305 | print_box_start(); |
32487831 |
306 | |
3319ef85 |
307 | search_stopwatch(); |
308 | $hit_count = $sq->count(); |
32487831 |
309 | |
3319ef85 |
310 | print "<br />"; |
32487831 |
311 | |
decf9db1 |
312 | print $hit_count.' '.get_string('resultsreturnedfor', 'search') . " '".s($query_string)."'."; |
3319ef85 |
313 | print "<br />"; |
32487831 |
314 | |
3319ef85 |
315 | if ($hit_count > 0) { |
316 | $page_links = $sq->page_numbers(); |
317 | $hits = $sq->results(); |
32487831 |
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); |
32487831 |
324 | } |
325 | |
3319ef85 |
326 | print "<ol>"; |
32487831 |
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 | |
3319ef85 |
334 | foreach ($hits as $listing) { |
3efa38a4 |
335 | |
336 | $iconpath = $CFG->modpixpath.'/'.$listing->doctype.'/icon.gif'; |
32487831 |
337 | $coursename = get_field('course', 'fullname', 'id', $listing->courseid); |
3efa38a4 |
338 | $courseword = mb_convert_case(get_string('course', 'moodle'), MB_CASE_LOWER, 'UTF-8'); |
3319ef85 |
339 | $title_post_processing_function = $listing->doctype.'_link_post_processing'; |
3efa38a4 |
340 | $searchable_instance = $searchables[$listing->doctype]; |
341 | if ($searchable_instance->location == 'internal'){ |
342 | require_once "{$CFG->dirroot}/search/documents/{$listing->doctype}_document.php"; |
343 | } else { |
344 | require_once "{$CFG->dirroot}/{$searchable_instance->location}/{$listing->doctype}/search_document.php"; |
345 | } |
3319ef85 |
346 | if (function_exists($title_post_processing_function)) { |
347 | $listing->title = $title_post_processing_function($listing->title); |
348 | } |
32487831 |
349 | |
3efa38a4 |
350 | echo "<li value='".($listing->number+1)."'><a href='" |
351 | .str_replace('DEFAULT_POPUP_SETTINGS', DEFAULT_POPUP_SETTINGS ,$listing->url) |
352 | ."'><img align=\"top\" src=\"".$iconpath |
353 | ."\" class=\"activityicon\" alt=\"\"/> $listing->title</a><strong> (".$courseword.": '".$coursename."')</strong><br />\n"; |
354 | // print "<li value='".($listing->number+1)."'><a href='".str_replace('DEFAULT_POPUP_SETTINGS', DEFAULT_POPUP_SETTINGS ,$listing->url)."'>$listing->title</a><br />\n" |
355 | // ."<em>".search_shorten_url($listing->url, 70)."</em><br />\n" |
356 | // ."{$typestr}: ".$listing->doctype.", {$scorestr}: ".round($listing->score, 3); |
b93b987d |
357 | if (!empty($listing->author)){ |
3efa38a4 |
358 | echo ", {$authorstr}: ".$listing->author."\n" |
b93b987d |
359 | ."</li>\n"; |
360 | } |
32487831 |
361 | } |
3efa38a4 |
362 | echo "</ol>"; |
363 | echo $page_links; |
32487831 |
364 | } |
3319ef85 |
365 | print_box_end(); |
366 | ?> |
85db96c5 |
367 | <div class="mdl-align"> |
368 | <?php |
3319ef85 |
369 | print_string('ittook', 'search'); |
32487831 |
370 | search_stopwatch(); |
3319ef85 |
371 | print_string('tofetchtheseresults', 'search'); |
372 | ?>. |
373 | </div> |
32487831 |
374 | |
3319ef85 |
375 | <?php |
376 | } |
2f338ab5 |
377 | print_box_end(); |
3319ef85 |
378 | print_footer(); |
32487831 |
379 | ?> |