3 * Global Search Engine for Moodle
7 * @subpackage search_engine
8 * @author Michael Champanis (mchampan) [cynnical@gmail.com], Valery Fremaux [valery.fremaux@club-internet.fr] > 1.8
10 * @version prepared for Moodle 2.0
11 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
15 * Look through each installed module's or block's search document class file (/search/documents)
16 * for necessary search functions, and if they're present add the content to the index.
17 * Repeat this for blocks.
19 * Because the iterator/retrieval functions are now stored in /search/documents/<mod>_document.php,
20 * /mod/mod/lib.php doesn't have to be modified - and thus the search module becomes quite
21 * self-sufficient. URL's are now stored in the index, stopping us from needing to require
22 * the class files to generate a results page.
24 * Along with the index data, each document's summary gets stored in the database
25 * and synchronised to the index (flat file) via the primary key ('id') which is mapped
26 * to the 'dbid' field in the index
31 * includes and requires
34 define('NO_OUTPUT_BUFFERING', true);
36 require_once('../config.php');
37 require_once($CFG->dirroot
.'/search/lib.php');
39 //this'll take some time, set up the environment
42 ini_set('include_path', $CFG->dirroot
.DIRECTORY_SEPARATOR
.'search'.PATH_SEPARATOR
.ini_get('include_path'));
44 /// only administrators can index the moodle installation, because access to all pages is required
48 if (empty($CFG->enableglobalsearch
)) {
49 print_error('globalsearchdisabled', 'search');
52 if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM
))) {
53 print_error('beadmin', 'search', get_login_url());
56 /// confirmation flag to prevent accidental reindexing (indexersplash.php is the correct entry point)
58 $sure = strtolower(optional_param('areyousure', '', PARAM_ALPHA
));
61 mtrace("<pre>Sorry, you need to confirm indexing via <a href='indexersplash.php'>indexersplash.php</a>"
62 .". (<a href='index.php'>Back to query page</a>).</pre>");
67 /// check for php5 (lib.php)
69 //php5 found, continue including php5-only files
70 //require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
71 require_once($CFG->dirroot
.'/search/indexlib.php');
73 mtrace('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /></head><body>');
74 mtrace('<pre>Server Time: '.date('r',time())."\n");
76 if (isset($CFG->search_indexer_busy
) && $CFG->search_indexer_busy
== '1') {
77 //means indexing was not finished previously
78 mtrace("Warning: Indexing was not successfully completed last time, restarting.\n");
83 set_config('search_indexer_busy', '1');
86 $index_path = SEARCH_INDEX_PATH
;
87 $index_db_file = "{$CFG->dirroot}/search/db/$CFG->dbtype.sql";
88 $dbcontrol = new IndexDBControl();
90 /// setup directory in data root
92 if (!file_exists($index_path)) {
93 mtrace("Data directory ($index_path) does not exist, attempting to create.");
94 if (!mkdir($index_path, $CFG->directorypermissions
)) {
95 search_pexit("Error creating data directory at: $index_path. Please correct.");
98 mtrace("Directory successfully created.");
102 mtrace("Using {$index_path} as data directory.");
105 Zend_Search_Lucene_Analysis_Analyzer
::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive());
106 $index = new Zend_Search_Lucene($index_path, true);
110 mtrace('Deleting old index entries.');
111 $DB->delete_records(SEARCH_DATABASE_TABLE
);
116 mtrace("Starting activity modules\n");
118 //the presence of the required search functions -
120 // * mod_get_content_for_index
121 //are the sole basis for including a module in the index at the moment.
123 $searchables = search_collect_searchables();
128 foreach ($searchables as $mod) {
130 //mark last update times for mods to now.
131 $indexdatestring = 'search_indexer_update_date_'.$mod->name
;
132 set_config($indexdatestring, time());
133 $indexdatestring = 'search_indexer_run_date_'.$mod->name
;
134 set_config($indexdatestring, time());
136 mtrace("starting indexing {$mod->name}\n");
138 $key = 'search_in_'.$mod->name
;
139 if (isset($CFG->$key) && !$CFG->$key) {
140 mtrace("module $key has been administratively disabled. Skipping...\n");
144 if ($mod->location
== 'internal'){
145 $class_file = $CFG->dirroot
.'/search/documents/'.$mod->name
.'_document.php';
147 $class_file = $CFG->dirroot
.'/'.$mod->location
.'/'.$mod->name
.'/search_document.php';
150 if (file_exists($class_file)) {
151 include_once($class_file);
153 //build function names
154 $iter_function = $mod->name
.'_iterator';
155 $index_function = $mod->name
.'_get_content_for_index';
157 if (function_exists($index_function) && function_exists($iter_function)) {
158 mtrace("Processing module function $index_function ...");
159 $sources = $iter_function();
161 foreach ($sources as $i) {
162 $documents = $index_function($i);
166 foreach($documents as $document) {
169 // temporary fix until MDL-24822 is resolved
170 if ($document->group_id
== -1 and $mod->name
='forum') {
171 $document->group_id
= 0;
173 //object to insert into db
174 $dbid = $dbcontrol->addDocument($document);
176 //synchronise db with index
177 $document->addField(Zend_Search_Lucene_Field
::Keyword('dbid', $dbid));
179 //add document to index
180 $index->addDocument($document);
182 //commit every x new documents, and print a status message
183 if (($counter %
2000) == 0) {
185 mtrace(".. $counter");
193 //commit left over documents, and finish up
196 mtrace("-- $counter documents indexed");
200 mtrace ("No search document found for plugin {$mod->name}. Ignoring.");
207 mtrace('Finished activity modules');
210 mtrace(".<br/><a href='index.php'>Back to query page</a>.");
213 /// finished, turn busy flag off
215 set_config('search_indexer_busy', '0');
217 /// mark the time we last updated
219 set_config('search_indexer_run_date', time());
221 /// and the index size
223 set_config('search_index_size', (int)$index->count());