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