Fixed pagination in query page (lines were too long, distorting table),
[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 27)
29   if ($check = search_check_php5()) {  
30     require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
31     
32     $query_string = optional_param('query_string', '', PARAM_CLEAN);
33     $page_number  = optional_param('page', 1, PARAM_INT);
34     
35     if ($page_number < 1) {
36       $page_number = 1;
37     } //if
38         
39     $index_path = "$CFG->dataroot/search";
40     $no_index = false; //optimism!
41     $results_per_page = 10;
42     
43     try {
44       $index = new Zend_Search_Lucene($index_path, false);
45     } catch(Exception $e) {
46       //print $e;
47       $no_index = true;
48     } //catch
49   } //if
50   
51   
52   //Result document class that contains all the display information we need
53   class ResultDocument {
54     public  $url,
55             $title,
56             $score,
57             $doctype,
58             $author;
59   } //ResultDocument  
61   //generates an HTML string of links to result pages
62   function page_numbers($query, $hits, $page=1, $results_per_page=20) {
63     //total result pages
64     $pages = ceil($hits/$results_per_page);
65     
66     $ret = "<div align='center'>";    
67     
68     //Back is disabled if we're on page 1
69     if ($page > 1) {
70       $ret .= "<a href='query.php?query_string=$query&page=".($page-1)."'>< Back</a>&nbsp;";
71     } else {
72       $ret .= "< Back&nbsp;";
73     } //else
74     
75     //don't <a href> the current page
76     for ($i = 1; $i <= $pages; $i++) {
77       if ($page == $i) {
78         $ret .= "[$i]&nbsp;";
79       } else {
80         $ret .= "<a href='query.php?query_string=$query&page=$i'>$i</a>&nbsp;";
81       } //else
82     } //for
83     
84     //Next disabled if we're on the last page
85     if ($page < $pages) {      
86       $ret .= "<a href='query.php?query_string=$query&page=".($page+1)."'>Next ></a>&nbsp;";
87     } else {
88       $ret .= "Next >&nbsp;";
89     } //else
90     
91     $ret .= "</div>";    
92     
93     //shorten really long page lists, to stop table distorting width-ways
94     if (strlen($ret) > 70) {
95       $start = 4;
96       $end = $page - 5;     
97       $ret = preg_replace("/<a\D+\d+\D+>$start<\/a>.*?<a\D+\d+\D+>$end<\/a>/", '...', $ret);
99       $start = $page + 5;
100       $end = $pages - 3;      
101       $ret = preg_replace("/<a\D+\d+\D+>$start<\/a>.*?<a\D+\d+\D+>$end<\/a>/", '...', $ret);
102     } //if
103     
104     return $ret;
105   } //page_numbers
106   
107   //calculates whether a user is allowed to see this result
108   function can_display(&$user, $course_id, $group_id) {
109     return true;
110   } //can_display
111   
112   //caches the results of the last query, deletes the previous one also
113   function cache($id=false, &$object=false) {
114     //see if there was a previous query
115     $last_term = (isset($_SESSION['search_last_term'])) ? $_SESSION['search_last_term'] : false;
116     
117     //if this query is different from the last, clear out the last one
118     if ($id != false and $last_term != $id) {
119       unset($_SESSION[$last_term]);
120       session_unregister($last_term);
121     } //if
122     
123     //store the new query if id and object are passed in
124     if ($object and $id) {
125       $_SESSION['search_last_term'] = $id;
126       $_SESSION[$id] = $object;
127       return true;
128     //otherwise return the stored results
129     } else if ($id and isset($_SESSION[$id])) {
130       return $_SESSION[$id];
131     } //else
132   } //cache
133   
134   
135   if (!$site = get_site()) {
136     redirect("index.php");
137   } //if
138     
139   $strsearch = "Search"; //get_string();
140   $strquery  = "Enter your search query"; //get_string();
142   print_header("$site->shortname: $strsearch: $strquery", "$site->fullname", 
143                "<a href=\"index.php\">$strsearch</a> -> $strquery");
144   
145   //keep things pretty, even if php5 isn't available
146   if (!$check) {
147     print_heading(search_check_php5(true));
148     print_footer();
149     exit(0);
150   } //if
151   
152   print_simple_box_start('center', '100%', '', 20);
153   print_heading($strquery);
154   
155   print_simple_box_start('center', '', '', 20);
156   
157 ?>
159 <form name="query" method="get" action="query.php">
160   <input type="text" name="query_string" length="50" value="<?php print stripslashes(htmlentities($query_string)) ?>"/>
161   &nbsp;<input type="submit" value="Search"/>&nbsp;&nbsp;<a href="query.php?advanced=yes">Advanced search</a>
162   <a href="stats.php">Statistics</a>
163 </form>
165 <br>
167 <div align="center">
168 <?php
169   echo 'Searching: ';
170   
171   if ($no_index) {
172     print "0";
173   } else {
174     print $index->count();
175   } //else
176   
177   print ' documents.';
178   
179   if ($no_index and isadmin()) {
180     print "<br><br>Admin: There appears to be no index, click <a href='indexersplash.php'>here</a> to create one.";
181   } //if
182 ?>
183 </div>
185 <?php  
186   print_simple_box_end();
187   
188   if (!empty($query_string) and !$no_index) {
189     print_simple_box_start('center', '50%', 'white', 10);
190     
191     search_stopwatch();
192     
193     //if the cache is empty
194     if (!($hits = cache($query_string))) {
195       $resultdocs = array();
196       $resultdoc  = new ResultDocument;
197       
198       //generate a new result-set      
199       $hits = $index->find(strtolower($query_string));
200       
201       foreach ($hits as $hit) {
202         //check permissions on each result
203         if (can_display($USER, $hit->course_id, $hit->group_id)) {
204           $resultdoc->url     = $hit->url;
205           $resultdoc->title   = $hit->title;
206           $resultdoc->score   = $hit->score;
207           $resultdoc->doctype = $hit->doctype;
208           $resultdoc->author  = $hit->author;
209           
210           //and store it if it passes the test
211           $resultdocs[] = clone($resultdoc);
212         } //if
213       } //foreach
214       
215       //cache the results so we don't have to compute this on every page-load
216       cache($query_string, $resultdocs);
217       
218       //print "Using new results.";
219     } else {
220       //There was something in the cache, so we're using that to save time
221       //print "Using cached results.";
222     } //else
223             
224     $hit_count = count($hits);    
225     
226     print "<br>";
228     print $hit_count." results returned for '".stripslashes($query_string)."'.";
229     print "<br>";
230       
231     if ($hit_count > 0) {
232       if ($hit_count < $results_per_page) {
233         $page_number = 1;
234       } else if ($page_number > ceil($hit_count/$results_per_page)) {
235         $page_number = $hit_count/$results_per_page;
236       } //if
237     
238       $start = ($page_number - 1)*$results_per_page;
239       $end = $start + $results_per_page;
241       $page_links = page_numbers($query_string, $hit_count, $page_number, $results_per_page);
242         
243       print "<ol>";
244         
245       for ($i = $start; $i < $end; $i++) {
246         if ($i >= $hit_count) {
247           break;
248         } //if
249       
250         $listing = $hits[$i];
251             
252         print "<li value='".($i+1)."'><a href='".$listing->url."'>$listing->title</a><br>\n"
253              ."<em>".search_shorten_url($listing->url, 70)."</em><br>\n"        
254              ."Type: ".$listing->doctype.", score: ".round($listing->score, 3).", author: ".$listing->author."<br>\n"            
255              ."<br></li>\n";
256       } //for
257       
258       print "</ol>";
259       print $page_links;
260     } //if        
261     
262     print_simple_box_end();
263   } //if
264   
265   if (!empty($query_string) and !$no_index) {
266 ?>
268 <div align="center">
269   It took <?php search_stopwatch(); ?> to fetch these results.
270 </div>
272 <?php
273   } //if
274   
275   print_simple_box_end();
276   print_footer();
277 ?>