General updates, see README.txt.
[moodle.git] / search / indexer.php
1 <?php
2   /* The indexer logic -
3    * Look through each installed module's search document class file (/search/documents)
4    * for necessary search functions, and if they're present add the content to the index.
5    * Repeat this for blocks.
6    *
7    * Because the iterator/retrieval functions are now stored in /search/documents/mod_document.php,
8    * /mod/mod/lib.php doesn't have to be modified - and thus the search module becomes quite
9    * self-sufficient. URL's are now stored in the index, stopping us from needing to require
10    * the class files to generate a results page.
11    *
12    * Along with the index data, each document's summary gets stored in the database
13    * and synchronised to the index (flat file) via the primary key ('id') which is mapped
14    * to the 'db_id' field in the index
15    * */
17   //this'll take some time, set up the environment
18   @set_time_limit(0);
19   @ob_implicit_flush(true);
20   @ob_end_flush();  
22   require_once('../config.php');
23   require_once("$CFG->dirroot/search/lib.php");  
25   //only administrators can index the moodle installation, because access to all pages is required   
26   require_login();
28   if (!isadmin()) {
29     error("You need to be an admin user to use this page.", "$CFG->wwwroot/login/index.php");
30   } //if
31   
32   //confirmation flag to prevent accidental reindexing (indexersplash.php is the correct entry point)
33   $sure = strtolower(optional_param('areyousure', '', PARAM_ALPHA));
34   
35   if ($sure != 'yes') {
36     mtrace("<pre>Sorry, you need to confirm indexing via <a href='indexersplash.php'>indexersplash.php</a>"
37           .". (<a href='index.php'>Back to query page</a>).</pre>");
38           
39     exit(0);
40   } //if  
41   
42   //check for php5 (lib.php)
43   if (!search_check_php5()) {
44     $phpversion = phpversion();
45     mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version $phpversion)");
46     exit(0);
47   } //if
48     
49   //php5 found, continue including php5-only files
50   require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
51     
52   mtrace('<pre>Server Time: '.date('r',time())."\n");
54   if ($CFG->search_indexer_busy == '1') {
55     //means indexing was not finished previously
56     mtrace("Warning: Indexing was not successfully completed last time, restarting.\n");
57   } //if
59   //turn on busy flag
60   set_config('search_indexer_busy', '1');
61   
62   //paths
63   $index_path = SEARCH_INDEX_PATH;
64   $index_db_file = "$CFG->dirroot/search/db/$CFG->dbtype.sql";  
65   
66   //setup directory in data root
67   if (!file_exists($index_path)) {
68     mtrace("Data directory ($index_path) does not exist, attempting to create.");
69     if (!mkdir($index_path)) {
70       search_pexit("Error creating data directory at: $index_path. Please correct.");
71     } else {
72       mtrace("Directory successfully created.");
73     } //else
74   } else {
75     mtrace("Using $index_path as data directory.");
76   } //else
77   
78   $index = new Zend_Search_Lucene($index_path, true);
79   
80   //create the database tables
81   $tables = $db->MetaTables();
82     
83   if (in_array($CFG->prefix.'search_documents', $tables)) {
84     //delete_records('search_documents');    
85     //temporary measure - db doesn't have update scripts and I realised that cvs 1.1 db
86     //is incompatible with cvs 1.2! Must fix ASAP.    
87     execute_sql('drop table '.$CFG->prefix.'search_documents', false);
88     
89     ob_start(); //turn output buffering on - to hide modify_database() output
90     modify_database($index_db_file, '', false);
91     ob_end_clean(); //chuck the buffer and resume normal operation
92   } else {        
93     ob_start(); //turn output buffering on - to hide modify_database() output
94     modify_database($index_db_file, '', false);
95     ob_end_clean(); //chuck the buffer and resume normal operation
96   } //else
98   //begin timer
99   search_stopwatch();
100   mtrace("Starting activity modules\n");
101   
102   //the presence of the required search functions -
103   // * mod_iterator
104   // * mod_get_content_for_index
105   //are the sole basis for including a module in the index at the moment.
106   
107   if ($mods = get_records_select('modules' /*'index this module?' where statement*/)) {
108     foreach ($mods as $mod) {
109       if ($mod->name == 'forum') continue;
110       $class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';              
111       
112       if (file_exists($class_file)) {
113         include_once($class_file);
114         
115         $iter_function = $mod->name.'_iterator';
116         $index_function = $mod->name.'_get_content_for_index';
117                 
118         $counter = 0;
119         $doc = new stdClass;
120                 
121         if (function_exists($index_function) && function_exists($iter_function)) {
122           mtrace("Processing module function $index_function ...");
123                      
124           foreach ($iter_function() as $i) {
125             $documents = $index_function($i);
126             
127             //begin transaction
128             
129             foreach($documents as $document) {
130               $counter++;
131                             
132               //object to insert into db                            
133               $doc->doctype   = $document->doctype;
134               $doc->title     = search_escape_string($document->title);
135               $doc->url       = search_escape_string($document->url);              
136               $doc->update    = time();                            
137               $doc->courseid  = $document->course_id;              
138               $doc->groupid   = $document->group_id;              
139               
140               //insert summary into db
141               $id = insert_record('search_documents', $doc);
142               
143               //synchronise db with index
144               $document->addField(Zend_Search_Lucene_Field::Keyword('db_id', $id));
145               
146               //add document to index
147               $index->addDocument($document);                  
148                             
149               //commit every x new documents, and print a status message                            
150               if (($counter%2000) == 0) {
151                 $index->commit();
152                 mtrace(".. $counter");
153               } //if
154             } //foreach
156             //end transaction
157             
158           } //foreach
159                   
160           //commit left over documents, and finish up  
161           $index->commit();
162           
163           mtrace("-- $counter documents indexed");
164           mtrace("done.\n");          
165         } //if
166       } //if
167     } //foreach
168   } //if
169   
170   //finished modules
171   mtrace('Finished activity modules');
172   search_stopwatch();
173   
174   //now blocks...
175   //
176   
177   mtrace(".<br><a href='index.php'>Back to query page</a>.");
178   mtrace('</pre>');
179   
180   //finished, turn busy flag off
181   set_config("search_indexer_busy", "0");
182   
183   //mark the time we last updated
184   set_config("search_indexer_run_date", time());
186 ?>