global sync to HEAD for passing fixes

This commit is contained in:
diml
2008-04-07 21:24:49 +00:00
parent 3702d88a6e
commit 2e47bfb16b
32 changed files with 1662 additions and 1320 deletions
+12 -9
View File
@@ -1,14 +1,17 @@
<?php
/* This is the global search shortcut block - a single query can be entered, and
the user will be redirected to the query page where they can enter more
advanced queries, and view the results of their search. When searching from
this block, the broadest possible selection of documents is searched.
Author: Michael Champanis (mchampan)
Date: 2006 06 25
Todo: make strings -> get_string()
* the user will be redirected to the query page where they can enter more
* advanced queries, and view the results of their search. When searching from
* this block, the broadest possible selection of documents is searched.
*
*
* Todo: make strings -> get_string()
*
* @package search
* @subpackage search block
* @author: Michael Champanis (mchampan), reengineered by Valery Fremaux
* @date: 2006 06 25
*/
class block_search extends block_base {
@@ -16,7 +19,7 @@
function init() {
$this->title = get_string('blockname', 'block_search');
$this->cron = 1;
$this->version = 2007081100;
$this->version = 2008031500;
} //init
// only one instance of this block is required
+14
View File
@@ -55,6 +55,20 @@
} ?>"/><br/><br/>
</td>
</tr>
<tr>
<td valign="top" align="right">
<b><?php print_string('usemoodleroot', 'block_search') ?>:</b>
</td>
<td valign="top" align="left">
<?php
$usemoodleroot = (isset($CFG->block_search_usemoodleroot)) ? 'checked="checked"' : '' ;
$notusemoodleroot = (!isset($CFG->block_search_usemoodleroot)) ? 'checked="checked"' : '' ;
?>
<input id="block_search_usemoodleroot" type="radio" name="block_search_usemoodleroot" <?php echo $usemoodleroot ?> value="1"/> <?php print_string('yes') ?> -
<input id="block_search_usemoodleroot" type="radio" name="block_search_usemoodleroot" <?php echo $notusemoodleroot ?> value="0"/> <?php print_string('no') ?>
<br/><br/>
</td>
</tr>
<tr>
<td valign="top" align="right">
<b><?php print_string('configpdftotextcmd', 'block_search') ?>:</b>
+1 -1
View File
@@ -1,5 +1,5 @@
Cette distribution partielle contient une refonte du moteur de
recherche globalde Moodle.
recherche globale de Moodle.
Le moteur de recherche est capable d'indexer et de rechercher
des informations dans un grand nombre de contenus stockés
+131 -117
View File
@@ -1,9 +1,13 @@
<?php
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* review 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage search_engine
* @author Michael Champanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* Asynchronous adder for new indexable contents
*
@@ -11,134 +15,144 @@
* multiple arity to handle multiple document types modules
*/
/**
* includes and requires
*/
require_once('../config.php');
require_once("$CFG->dirroot/search/lib.php");
require_login();
/// checks global search activation
require_login();
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
if (!isadmin()) {
error(get_string('beadmin', 'search'), "$CFG->wwwroot/login/index.php");
}
/// check for php5 (lib.php)
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
if (!search_check_php5()) {
$phpversion = phpversion();
mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version ".phpversion().")");
exit(0);
}
require_once("$CFG->dirroot/search/indexlib.php");
$index = new Zend_Search_Lucene(SEARCH_INDEX_PATH);
$dbcontrol = new IndexDBControl();
$addition_count = 0;
$startindextime = time();
$indexdate = $CFG->search_indexer_run_date;
mtrace('Starting index update (additions)...');
mtrace('Index size before: '.$CFG->search_index_size."\n");
/// get all modules
if ($mods = get_records_select('modules')) {
/// append virtual modules onto array
if (!isadmin()) {
error(get_string('beadmin', 'search'), "$CFG->wwwroot/login/index.php");
}
//check for php5 (lib.php)
if (!search_check_php5()) {
$phpversion = phpversion();
mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version $phpversion)");
exit(0);
}
require_once("$CFG->dirroot/search/indexlib.php");
$index = new Zend_Search_Lucene(SEARCH_INDEX_PATH);
$dbcontrol = new IndexDBControl();
$addition_count = 0;
$startindextime = time();
$indexdate = $CFG->search_indexer_run_date;
mtrace('<pre>Starting index update (additions)...');
mtrace('Index size before: '.$CFG->search_index_size."\n");
//get all modules
if ($mods = get_records_select('modules')) {
//append virtual modules onto array
$mods = array_merge($mods, search_get_additional_modules());
foreach ($mods as $mod) {
//build include file and function names
$class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
$db_names_function = $mod->name.'_db_names';
$get_document_function = $mod->name.'_single_document';
$get_newrecords_function = $mod->name.'_new_records';
$additions = array();
if (file_exists($class_file)) {
require_once($class_file);
$mods = array_merge($mods, search_get_additional_modules());
foreach ($mods as $mod) {
//build include file and function names
$class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
$db_names_function = $mod->name.'_db_names';
$get_document_function = $mod->name.'_single_document';
$get_newrecords_function = $mod->name.'_new_records';
$additions = array();
//if both required functions exist
if (function_exists($db_names_function) and function_exists($get_document_function)) {
mtrace("Checking $mod->name module for additions.");
$valuesArray = $db_names_function();
if ($valuesArray){
foreach($valuesArray as $values){
$where = (isset($values[5])) ? 'AND ('.$values[5].')' : '';
$itemtypes = ($values[4] != '*') ? " AND itemtype = '{$values[4]}' " : '' ;
//select records in MODULE table, but not in SEARCH_DATABASE_TABLE
$table = SEARCH_DATABASE_TABLE;
$query = "
SELECT
docid,
itemtype
FROM
{$CFG->prefix}{$table}
WHERE
doctype = '{$mod->name}'
$itemtypes
";
$docIds = get_records_sql_menu($query);
$docIdList = ($docIds) ? implode("','", array_keys($docIds)) : '' ;
$query = "
SELECT id,
{$values[0]} as docid
FROM
{$CFG->prefix}{$values[1]}
WHERE
id NOT IN ('{$docIdList}') and
{$values[2]} > {$indexdate}
$where
";
$records = get_records_sql($query);
// foreach record, build a module specific search document using the get_document function
if (is_array($records)) {
foreach($records as $record) {
$add = $get_document_function($record->docid, $values[4]);
// some documents may not be indexable
if ($add)
$additions[] = $add;
if (file_exists($class_file)) {
require_once($class_file);
//if both required functions exist
if (function_exists($db_names_function) and function_exists($get_document_function)) {
mtrace("Checking $mod->name module for additions.");
$valuesArray = $db_names_function();
if ($valuesArray){
foreach($valuesArray as $values){
$where = (isset($values[5])) ? 'AND ('.$values[5].')' : '';
$itemtypes = ($values[4] != '*' && $values[4] != 'any') ? " AND itemtype = '{$values[4]}' " : '' ;
//select records in MODULE table, but not in SEARCH_DATABASE_TABLE
$table = SEARCH_DATABASE_TABLE;
$query = "
SELECT
docid,
itemtype
FROM
{$CFG->prefix}{$table}
WHERE
doctype = '{$mod->name}'
$itemtypes
";
$docIds = get_records_sql_menu($query);
$docIdList = ($docIds) ? implode("','", array_keys($docIds)) : '' ;
$query = "
SELECT id,
{$values[0]} as docid
FROM
{$CFG->prefix}{$values[1]}
WHERE
id NOT IN ('{$docIdList}') and
{$values[2]} > {$indexdate}
$where
";
$records = get_records_sql($query);
// foreach record, build a module specific search document using the get_document function
if (is_array($records)) {
foreach($records as $record) {
$add = $get_document_function($record->docid, $values[4]);
// some documents may not be indexable
if ($add)
$additions[] = $add;
}
}
}
}
// foreach document, add it to the index and database table
foreach ($additions as $add) {
++$addition_count;
// object to insert into db
$dbid = $dbcontrol->addDocument($add);
// synchronise db with index
$add->addField(Zend_Search_Lucene_Field::Keyword('dbid', $dbid));
mtrace(" Add: $add->title (database id = $add->dbid, moodle instance id = $add->docid)");
$index->addDocument($add);
}
}
else{
mtrace("No types to add.\n");
}
mtrace("Finished $mod->name.\n");
// foreach document, add it to the index and database table
foreach ($additions as $add) {
++$addition_count;
// object to insert into db
$dbid = $dbcontrol->addDocument($add);
// synchronise db with index
$add->addField(Zend_Search_Lucene_Field::Keyword('dbid', $dbid));
mtrace(" Add: $add->title (database id = $add->dbid, moodle instance id = $add->docid)");
$index->addDocument($add);
}
}
else{
mtrace("No types to add.\n");
}
mtrace("Finished $mod->name.\n");
}
}
}
}
}
/// commit changes
// commit changes
$index->commit();
$index->commit();
/// update index date and size
// update index date and size
set_config("search_indexer_run_date", $startindextime);
set_config("search_index_size", (int)$CFG->search_index_size + (int)$addition_count);
set_config("search_indexer_run_date", $startindextime);
set_config("search_index_size", (int)$CFG->search_index_size + (int)$addition_count);
/// print some additional info
// print some additional info
mtrace("Added $addition_count documents.");
mtrace('Index size after: '.$index->count().'</pre>');
mtrace("Added $addition_count documents.");
mtrace('Index size after: '.$index->count());
?>
+4 -1
View File
@@ -12,7 +12,10 @@
* adds documents created since the last index run
*/
require_once('../config.php');
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
}
require_once("$CFG->dirroot/search/lib.php");
if (!search_check_php5()) {
+4 -3
View File
@@ -4,6 +4,7 @@
* This is a special externalized code for cron handling in PHP5.
* Should never be called by a php 4.3.0 implementation.
*/
try{
// overrides php limits
$maxtimelimit = ini_get('max_execution_time');
@@ -11,15 +12,15 @@ try{
$maxmemoryamount = ini_get('memory_limit');
ini_set('memory_limit', '48M');
mtrace("<pre>Starting cron...\n");
mtrace("--DELETE----");
mtrace("\n--DELETE----");
require_once("$CFG->dirroot/search/delete.php");
mtrace("--UPDATE----");
require_once("$CFG->dirroot/search/update.php");
mtrace("--ADD-------");
require_once("$CFG->dirroot/search/add.php");
mtrace("------------");
mtrace("cron finished.</pre>");
//mtrace("cron finished.</pre>");
mtrace('done');
// set back normal values for php limits
ini_set('max_execution_time', $maxtimelimit);
+112 -102
View File
@@ -1,9 +1,13 @@
<?php
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* review 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage search_engine
* @author Michael Champanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* Asynchronous index cleaner
*
@@ -11,122 +15,128 @@
* multiple arity to handle multiple document types modules
*/
/**
* includes and requires
*/
require_once('../config.php');
require_once("$CFG->dirroot/search/lib.php");
require_login();
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
if (!isadmin()) {
error(get_string('beadmin', 'search'), "$CFG->wwwroot/login/index.php");
} //if
//check for php5 (lib.php)
if (!search_check_php5()) {
$phpversion = phpversion();
mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version $phpversion)");
exit(0);
}
require_once("$CFG->dirroot/search/indexlib.php");
$index = new Zend_Search_Lucene(SEARCH_INDEX_PATH);
$dbcontrol = new IndexDBControl();
$deletion_count = 0;
$startcleantime = time();
mtrace('<pre>Starting clean-up of removed records...');
mtrace('Index size before: '.$CFG->search_index_size."\n");
if ($mods = get_records_select('modules')) {
$mods = array_merge($mods, search_get_additional_modules());
require_login();
foreach ($mods as $mod) {
//build function names
$class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
$delete_function = $mod->name.'_delete';
$db_names_function = $mod->name.'_db_names';
$deletions = array();
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
if (!isadmin()) {
error(get_string('beadmin', 'search'), "$CFG->wwwroot/login/index.php");
} //if
//check for php5 (lib.php)
if (!search_check_php5()) {
$phpversion = phpversion();
mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version ".phpversion().")");
exit(0);
}
require_once("$CFG->dirroot/search/indexlib.php");
$index = new Zend_Search_Lucene(SEARCH_INDEX_PATH);
$dbcontrol = new IndexDBControl();
$deletion_count = 0;
$startcleantime = time();
mtrace('Starting clean-up of removed records...');
mtrace('Index size before: '.$CFG->search_index_size."\n");
if ($mods = get_records_select('modules')) {
$mods = array_merge($mods, search_get_additional_modules());
if (file_exists($class_file)) {
require_once($class_file);
foreach ($mods as $mod) {
//build function names
$class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
$delete_function = $mod->name.'_delete';
$db_names_function = $mod->name.'_db_names';
$deletions = array();
//if both required functions exist
if (function_exists($delete_function) and function_exists($db_names_function)) {
mtrace("Checking $mod->name module for deletions.");
$valuesArray = $db_names_function();
if ($valuesArray){
foreach($valuesArray as $values){
$where = (isset($values[5])) ? 'WHERE '.$values[5] : '';
$itemtypes = ($values[4] != '*') ? " itemtype = '{$values[4]}' AND " : '' ;
$query = "
SELECT
id,
{$values[0]}
FROM
{$CFG->prefix}{$values[1]}
$where
";
$docIds = get_records_sql($query);
$docIdList = ($docIds) ? implode("','", array_keys($docIds)) : '' ;
if (file_exists($class_file)) {
require_once($class_file);
//if both required functions exist
if (function_exists($delete_function) and function_exists($db_names_function)) {
mtrace("Checking $mod->name module for deletions.");
$valuesArray = $db_names_function();
if ($valuesArray){
foreach($valuesArray as $values){
$where = (isset($values[5])) ? 'WHERE '.$values[5] : '';
$itemtypes = ($values[4] != '*' && $values[4] != 'any') ? " itemtype = '{$values[4]}' AND " : '' ;
$query = "
SELECT
id,
{$values[0]}
FROM
{$CFG->prefix}{$values[1]}
$where
";
$docIds = get_records_sql($query);
$docIdList = ($docIds) ? implode("','", array_keys($docIds)) : '' ;
$table = SEARCH_DATABASE_TABLE;
$query = "
SELECT
id,
docid
FROM
{$CFG->prefix}{$table}
WHERE
doctype = '{$mod->name}' AND
$itemtypes
docid not in ('{$docIdList}')
";
$records = get_records_sql($query);
// build an array of all the deleted records
if (is_array($records)) {
foreach($records as $record) {
$deletions[] = $delete_function($record->docid, $values[4]);
}
}
}
$table = SEARCH_DATABASE_TABLE;
$query = "
SELECT
id,
docid
FROM
{$CFG->prefix}{$table}
WHERE
doctype = '{$mod->name}' AND
$itemtypes
docid not in ('{$docIdList}')
";
$records = get_records_sql($query);
// build an array of all the deleted records
if (is_array($records)) {
foreach($records as $record) {
$deletions[] = $delete_function($record->docid, $values[4]);
foreach ($deletions as $delete) {
// find the specific document in the index, using it's docid and doctype as keys
$doc = $index->find("+docid:{$delete->id} +doctype:$mod->name +itemtype:{$delete->itemtype}");
// get the record, should only be one
foreach ($doc as $thisdoc) {
++$deletion_count;
mtrace(" Delete: $thisdoc->title (database id = $thisdoc->dbid, index id = $thisdoc->id, moodle instance id = $thisdoc->docid)");
//remove it from index and database table
$dbcontrol->delDocument($thisdoc);
$index->delete($thisdoc->id);
}
}
}
foreach ($deletions as $delete) {
// find the specific document in the index, using it's docid and doctype as keys
$doc = $index->find("+docid:{$delete->id} +doctype:$mod->name +itemtype:{$delete->itemtype}");
// get the record, should only be one
foreach ($doc as $thisdoc) {
++$deletion_count;
mtrace(" Delete: $thisdoc->title (database id = $thisdoc->dbid, index id = $thisdoc->id, moodle instance id = $thisdoc->docid)");
//remove it from index and database table
$dbcontrol->delDocument($thisdoc);
$index->delete($thisdoc->id);
}
else{
mtrace("No types to delete.\n");
}
mtrace("Finished $mod->name.\n");
}
else{
mtrace("No types to delete.\n");
}
mtrace("Finished $mod->name.\n");
}
}
}
}
/// commit changes
//commit changes
$index->commit();
$index->commit();
/// update index date and index size
//update index date and index size
set_config("search_indexer_cleanup_date", $startcleantime);
set_config("search_index_size", (int)$CFG->search_index_size - (int)$deletion_count);
mtrace("Finished $deletion_count removals.");
mtrace('Index size after: '.$index->count().'</pre>');
set_config("search_indexer_cleanup_date", $startcleantime);
set_config("search_index_size", (int)$CFG->search_index_size - (int)$deletion_count);
mtrace("Finished $deletion_count removals.");
mtrace('Index size after: '.$index->count());
?>
+34 -27
View File
@@ -1,8 +1,13 @@
<?php
/**
* Global Search Engine for Moodle
* add-on 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* document handling for chat activity module
* This file contains the mapping between a chat history and it's indexable counterpart,
@@ -10,23 +15,22 @@
* Functions for iterating and retrieving the necessary records are now also included
* in this file, rather than mod/chat/lib.php
*
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package search
* @version 2007110400
**/
*/
/**
* includes and requires
*/
require_once("$CFG->dirroot/search/documents/document.php");
require_once("$CFG->dirroot/mod/chat/lib.php");
/*
/**
* a class for representing searchable information
*
**/
*/
class ChatTrackSearchDocument extends SearchDocument {
/**
* constructor
*
*/
public function __construct(&$chatsession, $chat_module_id, $course_id, $group_id, $context_id) {
// generic information; required
@@ -50,8 +54,8 @@ class ChatTrackSearchDocument extends SearchDocument {
// construct the parent class
parent::__construct($doc, $data, $course_id, $group_id, 0, PATH_FOR_SEARCH_TYPE_CHAT);
} //constructor
} //ChatTrackSearchDocument
}
}
/**
@@ -59,19 +63,23 @@ class ChatTrackSearchDocument extends SearchDocument {
* @param cm_id the chat course module
* @param start the start time of the session
* @param end th end time of the session
* @uses CFG
* @return a well formed link to session display
*/
function chat_make_link($cm_id, $start, $end) {
global $CFG;
return $CFG->wwwroot.'/mod/chat/report.php?id='.$cm_id.'&amp;start='.$start.'&amp;end='.$end;
} //chat_make_link
}
/**
* fetches all the records for a given session and assemble them as a unique track
* we revamped here the code of report.php for making sessions, but without any output.
* note that we should collect sessions "by groups" if groupmode() is SEPARATEGROUPS.
* @param chat_id the database
* @param int $chat_id the database
* @param int $fromtime
* @param int $totime
* @uses CFG
* @return an array of objects representing the chat sessions.
*/
function chat_get_session_tracks($chat_id, $fromtime = 0, $totime = 0) {
@@ -94,8 +102,7 @@ function chat_get_session_tracks($chat_id, $fromtime = 0, $totime = 0) {
foreach($messages as $aMessage){
$groupedMessages[$aMessage->groupid][] = $aMessage;
}
}
else{
} else {
$groupedMessages[-1] = &$messages;
}
$sessiongap = 5 * 60; // 5 minutes silence means a new session
@@ -122,9 +129,8 @@ function chat_get_session_tracks($chat_id, $fromtime = 0, $totime = 0) {
$tracks[count($tracks) - 1]->content .= ' '.$message->message;
$tracks[count($tracks) - 1]->sessionstart = $message->timestamp;
}
}
} else {
// we initiate a new session track (backwards)
else {
$track = new Object();
$track->sessionend = $message->timestamp;
$track->sessionstart = $message->timestamp;
@@ -140,7 +146,7 @@ function chat_get_session_tracks($chat_id, $fromtime = 0, $totime = 0) {
}
}
return $tracks;
} //chat_get_session_tracks
}
/**
* part of search engine API
@@ -149,7 +155,7 @@ function chat_get_session_tracks($chat_id, $fromtime = 0, $totime = 0) {
function chat_iterator() {
$chatrooms = get_records('chat');
return $chatrooms;
} //chat_iterator
}
/**
* part of search engine API
@@ -169,7 +175,7 @@ function chat_get_content_for_index(&$chat) {
foreach($sessionTracks as $aTrackId => $aTrack) {
foreach($aTrack->sessionusers as $aUserId){
$user = get_record('user', 'id', $aUserId);
$aTrack->authors = ($user) ? $user->firstname.' '.$user->lastname : '' ;
$aTrack->authors = ($user) ? fullname($user) : '' ;
$documents[] = new ChatTrackSearchDocument(get_object_vars($aTrack), $cm->id, $chat->course, $aTrack->groupid, $context->id);
}
}
@@ -177,7 +183,7 @@ function chat_get_content_for_index(&$chat) {
return $documents;
}
return array();
} //chat_get_content_for_index
}
/**
* returns a single data search document based on a chat_session id
@@ -202,11 +208,11 @@ function chat_single_document($id, $itemtype) {
if ($tracks){
$aTrack = $tracks[0];
$document = new ChatTrackSearchDocument(get_object_vars($aTrack), $cm->id, $chat->course, $aTrack->groupid, $context->id);
return $document;
}
return $document;
}
return null;
} //chat_single_document
}
/**
* dummy delete function that packs id with itemtype.
@@ -217,7 +223,7 @@ function chat_delete($info, $itemtype) {
$object->id = $info;
$object->itemtype = $itemtype;
return $object;
} //chat_delete
}
/**
* returns the var names needed to build a sql query for addition/deletions
@@ -226,7 +232,7 @@ function chat_delete($info, $itemtype) {
function chat_db_names() {
//[primary id], [table name], [time created field name], [time modified field name]
return null;
} //chat_db_names
}
/**
* this function handles the access policy to contents indexed as searchable documents. If this
@@ -241,6 +247,7 @@ function chat_db_names() {
* points out a session history which is a close sequence of messages.
* @param user the user record denoting the user who searches
* @param group_id the current group used by the user when searching
* @uses CFG
* @return true if access is allowed, false elsewhere
*/
function chat_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
@@ -280,7 +287,7 @@ function chat_check_text_access($path, $itemtype, $this_id, $user, $group_id, $c
}
return true;
} //chat_check_text_access
}
/**
* this call back is called when displaying the link for some last post processing
@@ -290,5 +297,5 @@ function chat_link_post_processing($title){
setLocale(LC_TIME, substr(current_language(), 0, 2));
$title = preg_replace('/TT_(.*)_TT/e', "userdate(\\1)", $title);
return $title;
} //chat_link_post_processing
}
?>
+35 -31
View File
@@ -1,8 +1,13 @@
<?php
/**
* Global Search Engine for Moodle
* add-on 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* document handling for data activity module
* This file contains the mapping between a database object and it's indexable counterpart,
@@ -10,23 +15,22 @@
* Functions for iterating and retrieving the necessary records are now also included
* in this file, rather than mod/data/lib.php
*
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package search
* @version 2007110400
**/
*/
/**
* includes and requires
*/
require_once("$CFG->dirroot/search/documents/document.php");
require_once("$CFG->dirroot/mod/data/lib.php");
/*
/**
* a class for representing searchable information (data records)
*
**/
*/
class DataSearchDocument extends SearchDocument {
/**
* constructor
*
*/
public function __construct(&$record, $course_id, $context_id) {
// generic information; required
@@ -51,18 +55,17 @@ class DataSearchDocument extends SearchDocument {
// construct the parent class
parent::__construct($doc, $data, $course_id, $record['groupid'], $record['userid'], PATH_FOR_SEARCH_TYPE_DATA);
} //constructor
} //ChatSearchDocument
}
}
/*
/**
* a class for representing searchable information (comments on data records)
*
**/
*/
class DataCommentSearchDocument extends SearchDocument {
/**
* constructor
*
*/
public function __construct(&$comment, $course_id, $context_id) {
// generic information; required
@@ -83,25 +86,27 @@ class DataCommentSearchDocument extends SearchDocument {
// construct the parent class
parent::__construct($doc, $data, $course_id, $comment['groupid'], $comment['userid'], PATH_FOR_SEARCH_TYPE_DATA);
} //constructor
} //ChatCommentSearchDocument
}
}
/**
* constructs a valid link to a data record content
* @param database_id the database reference
* @param record_id the record reference
* @uses CFG
* @return a valid url top access the information as a string
*/
function data_make_link($database_id, $record_id) {
global $CFG;
return $CFG->wwwroot.'/mod/data/view.php?d='.$database_id.'&amp;rid='.$record_id;
} //data_make_link
}
/**
* fetches all the records for a given database
* @param database_id the database
* @param typematch a comma separated list of types that should be considered for searching or *
* @uses CFG
* @return an array of objects representing the data records.
*/
function data_get_records($database_id, $typematch = '*') {
@@ -127,19 +132,19 @@ function data_get_records($database_id, $typematch = '*') {
if($typematch == '*' || preg_match("/\\b{$fieldset[$aDatum->fieldid]->type}\\b/", $typematch)){
if (!isset($records[$aDatum->recordid])){
$records[$aDatum->recordid]['_first'] = $aDatum->content.' '.$aDatum->content1.' '.$aDatum->content2.' '.$aDatum->content3.' '.$aDatum->content4.' ';
}
else{
} else {
$records[$aDatum->recordid][$fieldset[$aDatum->fieldid]->name] = $aDatum->content.' '.$aDatum->content1.' '.$aDatum->content2.' '.$aDatum->content3.' '.$aDatum->content4.' ';
}
}
}
}
return $records;
} //data_get_records
}
/**
* fetches all the comments for a given database
* @param database_id the database
* @uses CFG
* @return an array of objects representing the data record comments.
*/
function data_get_comments($database_id) {
@@ -163,7 +168,7 @@ function data_get_comments($database_id) {
";
$comments = get_records_sql($query);
return $comments;
} //data_get_comments
}
/**
@@ -173,7 +178,7 @@ function data_get_comments($database_id) {
function data_iterator() {
$databases = get_records('data');
return $databases;
} //data_iterator
}
/**
* part of search engine API
@@ -221,7 +226,7 @@ function data_get_content_for_index(&$database) {
}
}
return $documents;
} //data_get_content_for_index
}
/**
* returns a single data search document based on a data entry id
@@ -256,8 +261,7 @@ function data_single_document($id, $itemtype) {
$recordMetaData->content = $accumulator;
// make document
$documents[] = new DataSearchDocument(get_object_vars($recordMetaData), $record_course, $context->id);
}
elseif($itemtype == 'comment'){
} elseif($itemtype == 'comment') {
// get main records
$comment = get_record('data_comments', 'id', $id);
$record = get_record('data_records', 'id', $comment->recordid);
@@ -272,11 +276,10 @@ function data_single_document($id, $itemtype) {
$comment->groupid = $record->groupid;
// make document
$documents[] = new DataCommentSearchDocument(get_object_vars($comment), $record_course, $context->id);
}
else{
} else {
mtrace('Error : bad or missing item type');
}
} //data_single_document
}
/**
* dummy delete function that packs id with itemtype.
@@ -287,7 +290,7 @@ function data_delete($info, $itemtype) {
$object->id = $info;
$object->itemtype = $itemtype;
return $object;
} //data_delete
}
/**
* returns the var names needed to build a sql query for addition/deletions
@@ -299,7 +302,7 @@ function data_db_names() {
array('id', 'data_records', 'timecreated', 'timemodified', 'record'),
array('id', 'data_comments', 'created', 'modified', 'comment')
);
} //data_db_names
}
/**
* this function handles the access policy to contents indexed as searchable documents. If this
@@ -314,6 +317,7 @@ function data_db_names() {
* points out an indexed data record page.
* @param user the user record denoting the user who searches
* @param group_id the current group used by the user when searching
* @uses CFG
* @return true if access is allowed, false elsewhere
*/
function data_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
@@ -394,5 +398,5 @@ function data_check_text_access($path, $itemtype, $this_id, $user, $group_id, $c
}
return true;
} // data_check_text_access
}
?>
+13 -6
View File
@@ -1,14 +1,21 @@
<?php
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* review 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Michael Campanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* Base search document from which other module/block types can
* extend.
**/
*/
/**
*
*/
abstract class SearchDocument extends Zend_Search_Lucene_Document {
public function __construct(&$doc, &$data, $course_id, $group_id, $user_id, $path) {
//document identification and indexing
@@ -52,7 +59,7 @@ abstract class SearchDocument extends Zend_Search_Lucene_Document {
// of multiple capabilities in their code. This possibility should be left open here.
$this->addField(Zend_Search_Lucene_Field::UnIndexed('capabilities', $caps));
*/
} //constructor
} //SearchDocument
}
}
?>
+27 -22
View File
@@ -1,9 +1,13 @@
<?php
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* review 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Michael Campanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* document handling for forum activity module
* This file contains the mapping between a forum post and it's indexable counterpart,
@@ -11,24 +15,22 @@
* Functions for iterating and retrieving the necessary records are now also included
* in this file, rather than mod/forum/lib.php
*
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package search
* @version 2007110400
**/
/* see wiki_document.php for descriptions */
*/
/**
* includes and requires
*/
require_once("$CFG->dirroot/search/documents/document.php");
require_once("$CFG->dirroot/mod/forum/lib.php");
/*
/**
* a class for representing searchable information
*
**/
*/
class ForumSearchDocument extends SearchDocument {
/**
* constructor
*
*/
public function __construct(&$post, $forum_id, $course_id, $itemtype, $context_id) {
// generic information
@@ -50,8 +52,8 @@ class ForumSearchDocument extends SearchDocument {
$data->discussion = $post['discussion'];
parent::__construct($doc, $data, $course_id, $post['groupid'], $post['userid'], PATH_FOR_SEARCH_TYPE_FORUM);
} //constructor
} //ForumSearchDocument
}
}
/**
* constructs a valid link to a chat content
@@ -63,7 +65,7 @@ function forum_make_link($discussion_id, $post_id) {
global $CFG;
return $CFG->wwwroot.'/mod/forum/discuss.php?d='.$discussion_id.'#'.$post_id;
} //forum_make_link
}
/**
* search standard API
@@ -72,7 +74,7 @@ function forum_make_link($discussion_id, $post_id) {
function forum_iterator() {
$forums = get_records('forum');
return $forums;
} //forum_iterator
}
/**
* search standard API
@@ -108,7 +110,7 @@ function forum_get_content_for_index(&$forum) {
}
}
return $documents;
} //forum_get_content_for_index
}
/**
* returns a single forum search document based on a forum entry id
@@ -128,7 +130,7 @@ function forum_single_document($id, $itemtype) {
return new ForumSearchDocument(get_object_vars($post), $discussion->forum, $discussion->course, $itemtype, $context->id);
}
return null;
} //forum_single_document
}
/**
* dummy delete function that aggregates id with itemtype.
@@ -139,7 +141,7 @@ function forum_delete($info, $itemtype) {
$object->id = $info;
$object->itemtype = $itemtype;
return $object;
} //forum_delete
}
/**
* returns the var names needed to build a sql query for addition/deletions
@@ -151,11 +153,12 @@ function forum_db_names() {
array('id', 'forum_posts', 'created', 'modified', 'head', 'parent = 0'),
array('id', 'forum_posts', 'created', 'modified', 'post', 'parent != 0')
);
} //forum_db_names
}
/**
* reworked faster version from /mod/forum/lib.php
* @param forum_id a forum identifier
* @uses CFG, USER
* @return an array of posts
*/
function forum_get_discussions_fast($forum_id) {
@@ -202,12 +205,13 @@ function forum_get_discussions_fast($forum_id) {
d.timemodified DESC
";
return get_records_sql($query);
} //forum_get_discussions_fast
}
/**
* reworked faster version from /mod/forum/lib.php
* @param parent the id of the first post within the discussion
* @param forum_id the forum identifier
* @uses CFG
* @return an array of posts
*/
function forum_get_child_posts_fast($parent, $forum_id) {
@@ -241,7 +245,7 @@ function forum_get_child_posts_fast($parent, $forum_id) {
p.created ASC
";
return get_records_sql($query);
} //forum_get_child_posts_fast
}
/**
* this function handles the access policy to contents indexed as searchable documents. If this
@@ -256,6 +260,7 @@ function forum_get_child_posts_fast($parent, $forum_id) {
* points out the individual post.
* @param user the user record denoting the user who searches
* @param group_id the current group used by the user when searching
* @uses CFG, USER
* @return true if access is allowed, false elsewhere
*/
function forum_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
@@ -290,6 +295,6 @@ function forum_check_text_access($path, $itemtype, $this_id, $user, $group_id, $
}
return true;
} //forum_check_text_access
}
?>
+34 -23
View File
@@ -1,9 +1,13 @@
<?php
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* review 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Michael Campanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* document handling for glossary activity module
* This file contains a mapping between a glossary entry and it's indexable counterpart,
@@ -11,17 +15,17 @@
* Functions for iterating and retrieving the necessary records are now also included
* in this file, rather than mod/glossary/lib.php
*
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package search
* @version 2007110400
**/
*/
/**
* includes and requires
*/
require_once("$CFG->dirroot/search/documents/document.php");
/*
/**
* a class for representing searchable information
*
**/
*/
class GlossarySearchDocument extends SearchDocument {
/**
@@ -49,18 +53,17 @@ class GlossarySearchDocument extends SearchDocument {
// construct the parent class
parent::__construct($doc, $data, $course_id, -1, $entry['userid'], PATH_FOR_SEARCH_TYPE_GLOSSARY);
} //constructor
} //GlossarySearchDocument
}
}
/*
/**
* a class for representing searchable information
*
**/
*/
class GlossaryCommentSearchDocument extends SearchDocument {
/**
* document constructor
*
*/
public function __construct(&$entry, $glossary_id, $course_id, $context_id) {
// generic information; required
@@ -83,8 +86,8 @@ class GlossaryCommentSearchDocument extends SearchDocument {
// construct the parent class
parent::__construct($doc, $data, $course_id, -1, $entry['userid'], PATH_FOR_SEARCH_TYPE_GLOSSARY);
} //constructor
} //GlossaryCommentSearchDocument
}
}
/**
* constructs valid access links to information
@@ -102,7 +105,7 @@ function glossary_make_link($entry_id) {
// preserve glossary pop-up, be careful where you place your ' and "s
//this function is meant to return a url that is placed between href='[url here]'
return "$CFG->wwwroot/mod/glossary/showentry.php?eid=$entry_id' onclick='return openpopup(\"/mod/glossary/showentry.php?eid=$entry_id\", \"entry\", DEFAULT_POPUP_SETTINGS, 0);";
} //glossary_make_link
}
/**
* part of search engine API
@@ -111,7 +114,7 @@ function glossary_make_link($entry_id) {
function glossary_iterator() {
$glossaries = get_records('glossary');
return $glossaries;
} //glossary_iterator
}
/**
* part of search engine API
@@ -153,7 +156,7 @@ function glossary_get_content_for_index(&$glossary) {
}
}
return $documents;
} //glossary_get_content_for_index
}
/**
* part of search engine API
@@ -179,7 +182,7 @@ function glossary_single_document($id, $itemtype) {
elseif ($itemtype == 'comment'){
return new GlossaryCommentSearchDocument(get_object_vars($comment), $entry->glossaryid, $glossary_course, $context->id);
}
} //glossary_single_document
}
/**
* dummy delete function that packs id with itemtype.
@@ -190,7 +193,7 @@ function glossary_delete($info, $itemtype) {
$object->id = $info;
$object->itemtype = $itemtype;
return $object;
} //glossary_delete
}
/**
* returns the var names needed to build a sql query for addition/deletions
@@ -202,7 +205,7 @@ function glossary_db_names() {
array('id', 'glossary_entries', 'timecreated', 'timemodified', 'standard'),
array('id', 'glossary_comments', 'timemodified', 'timemodified', 'comment')
);
} //glossary_db_names
}
/**
* this function handles the access policy to contents indexed as searchable documents. If this
@@ -241,6 +244,14 @@ function glossary_check_text_access($path, $itemtype, $this_id, $user, $group_id
}
return true;
} //glossary_check_text_access
}
/**
* post processes the url for cleaner output.
* @param string $title
*/
function glossary_link_post_processing($title){
return mb_convert_encoding($title, 'auto', 'UTF-8');
}
?>
+22 -20
View File
@@ -1,29 +1,31 @@
<?php
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* creation : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Michael Campanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* document handling for lesson activity module
* This file contains the mapping between a lesson page and it's indexable counterpart,
*
* Functions for iterating and retrieving the necessary records are now also included
* in this file, rather than mod/lesson/lib.php
*
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package search
* @version 2007110400
**/
/* see wiki_document.php for descriptions */
*/
/**
* includes and requires
*/
require_once("$CFG->dirroot/search/documents/document.php");
require_once("$CFG->dirroot/mod/lesson/lib.php");
/*
/**
* a class for representing searchable information
*
**/
*/
class LessonPageSearchDocument extends SearchDocument {
/**
@@ -48,8 +50,8 @@ class LessonPageSearchDocument extends SearchDocument {
$data->lesson = $page['lessonid'];
parent::__construct($doc, $data, $course_id, 0, 0, PATH_FOR_SEARCH_TYPE_LESSON);
} //constructor
} //LessonPageSearchDocument
}
}
/**
* constructs a valid link to a chat content
@@ -64,7 +66,7 @@ function lesson_make_link($lessonmoduleid, $itemid, $itemtype) {
return "{$CFG->wwwroot}/mod/lesson/view.php?id={$lessonmoduleid}&amp;pageid={$itemid}";
}
return $CFG->wwwroot.'/mod/lesson/view.php?id='.$lessonmoduleid;
} //lesson_make_link
}
/**
* search standard API
@@ -73,7 +75,7 @@ function lesson_make_link($lessonmoduleid, $itemid, $itemtype) {
function lesson_iterator() {
$lessons = get_records('lesson');
return $lessons;
} //lesson_iterator
}
/**
* search standard API
@@ -96,7 +98,7 @@ function lesson_get_content_for_index(&$lesson) {
}
return $documents;
} //lesson_get_content_for_index
}
/**
* returns a single lesson search document based on a lesson page id
@@ -116,7 +118,7 @@ function lesson_single_document($id, $itemtype) {
return new LessonPageSearchDocument(get_object_vars($page), $cm->id, $lesson->course, $itemtype, $context->id);
}
return null;
} //lesson_single_document
}
/**
* dummy delete function that aggregates id with itemtype.
@@ -127,7 +129,7 @@ function lesson_delete($info, $itemtype) {
$object->id = $info;
$object->itemtype = $itemtype;
return $object;
} //lesson_delete
}
/**
* returns the var names needed to build a sql query for addition/deletions
@@ -138,7 +140,7 @@ function lesson_db_names() {
return array(
array('id', 'lesson_pages', 'timecreated', 'timemodified', 'page')
);
} //lesson_db_names
}
/**
* this function handles the access policy to contents indexed as searchable documents. If this
@@ -201,5 +203,5 @@ function lesson_check_text_access($path, $itemtype, $this_id, $user, $group_id,
}
return true;
} //lesson_check_text_access
}
?>
+17 -7
View File
@@ -1,40 +1,50 @@
<?php
/**
* Global Search Engine for Moodle
* add-on 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* this is a format handler for getting text out of a proprietary binary format
* so it can be indexed by Lucene search engine
*/
/*
/**
* MS Word extractor
* @param object $resource
* @uses CFG, USER
*/
function get_text_for_indexing_doc(&$resource){
global $CFG, $USER;
// SECURITY : do not allow non admin execute anything on system !!
if (!isadmin($USER->id)) return;
$moodleroot = (@$CFG->block_search_usemoodleroot) ? "{$CFG->dirroot}/" : '' ;
// just call pdftotext over stdout and capture the output
if (!empty($CFG->block_search_word_to_text_cmd)){
if (!file_exists("{$CFG->dirroot}/{$CFG->block_search_word_to_text_cmd}")){
if (!file_exists("{$moodleroot}{$CFG->block_search_word_to_text_cmd}")){
mtrace('Error with MSWord to text converter command : exectuable not found.');
}
else{
$file = escapeshellarg($CFG->dataroot.'/'.$resource->course.'/'.$resource->reference);
$text_converter_cmd = "{$CFG->dirroot}/{$CFG->block_search_word_to_text_cmd} $file";
$command = trim($CFG->block_search_word_to_text_cmd);
$text_converter_cmd = "{$moodleroot}{$command} \"$file\"";
if ($CFG->block_search_word_to_text_env){
putenv($CFG->block_search_word_to_text_env);
}
mtrace("Executing : $text_converter_cmd");
$result = shell_exec($text_converter_cmd);
if ($result){
return mb_convert_encoding($result, 'UTF8', 'auto');
}
else{
mtrace('Error with MSWord to text converter command : execution failed.');
mtrace('Error with MSWord to text converter command : execution failed. ');
return '';
}
}
+29 -9
View File
@@ -1,13 +1,22 @@
<?php
/**
* Global Search Engine for Moodle
* add-on 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* this is a format handler for getting text out of a proprietary binary format
* so it can be indexed by Lucene search engine
*/
/**
* @param object $resource
* @uses CFG, USER
*/
function get_text_for_indexing_htm(&$resource){
global $CFG, $USER;
@@ -15,21 +24,32 @@ function get_text_for_indexing_htm(&$resource){
if (!isadmin($USER->id)) return;
// just get text
$text = implode('', file("{$CFG->dataroot}/{$resource->course}/($resource->reference)"));
$text = implode('', file("{$CFG->dataroot}/{$resource->course}/{$resource->reference}"));
// extract keywords and other interesting meta information and put it back as real content for indexing
if (preg_match('/(.*)<meta ([^>]*)>(.*)/is',$text, $matches)){
if (preg_match('/(.*)<meta ([^>]*)>(.*)/is', $text, $matches)){
$prefix = $matches[1];
$meta_attributes = $matches[2];
$suffix = $matches[3];
if (preg_match('/name="(keywords|description)"/i', $attributes)){
preg_match('/content="[^"]+"/i', $attributes, $matches);
if (preg_match('/name="(keywords|description)"/i', $meta_attributes)){
preg_match('/content="([^"]+)"/i', $meta_attributes, $matches);
$text = $prefix.' '.$matches[1].' '.$suffix;
}
}
// filter all html tags
// $text = clean_text($text, FORMAT_PLAIN);
// NOTE : this is done in ResourceSearchDocument __constructor
// brutally filters all html tags
$text = preg_replace("/<[^>]*>/", '', $text);
$text = preg_replace("/<!--[^>]*-->/", '', $text);
$text = html_entity_decode($text, ENT_COMPAT, 'UTF-8');
$text = mb_convert_encoding($text, 'UTF-8', 'AUTO');
/*
* debug code for tracing input
echo "<hr/>";
$FILE = fopen("filetrace.log", 'w');
fwrite($FILE, $text);
fclose($FILE);
echo "<hr/>";
*/
if (!empty($CFG->block_search_limit_index_body)){
$text = shorten($text, $CFG->block_search_limit_index_body);
+11 -3
View File
@@ -1,13 +1,21 @@
<?php
/**
* Global Search Engine for Moodle
* add-on 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* this is a format handler for getting text out of a proprietary binary format
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* this is a format handler for getting text out of a standard html format
* so it can be indexed by Lucene search engine
*/
/**
* @param object $resource
*/
function get_text_for_indexing_html(&$resource){
// wraps to htm handler
+16 -4
View File
@@ -1,28 +1,40 @@
<?php
/**
* Global Search Engine for Moodle
* add-on 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* this is a format handler for getting text out of a proprietary binary format
* so it can be indexed by Lucene search engine
*/
/**
* @param object $resource
* @uses CFG, USER
*/
function get_text_for_indexing_pdf(&$resource){
global $CFG, $USER;
// SECURITY : do not allow non admin execute anything on system !!
if (!isadmin($USER->id)) return;
$moodleroot = (@$CFG->block_search_usemoodleroot) ? "{$CFG->dirroot}/" : '' ;
// just call pdftotext over stdout and capture the output
if (!empty($CFG->block_search_pdf_to_text_cmd)){
preg_match("/^\S+/", $CFG->block_search_pdf_to_text_cmd, $matches);
if (!file_exists("{$CFG->dirroot}/{$matches[0]}")){
if (!file_exists("{$moodleroot}/{$matches[0]}")){
mtrace('Error with pdf to text converter command : exectuable not found.');
}
else{
$file = escapeshellarg($CFG->dataroot.'/'.$resource->course.'/'.$resource->reference);
$text_converter_cmd = "{$CFG->dirroot}/{$CFG->block_search_pdf_to_text_cmd} $file -";
$command = trim($CFG->block_search_pdf_to_text_cmd);
$text_converter_cmd = "{$moodleroot}/{$command} \"$file\" -";
$result = shell_exec($text_converter_cmd);
if ($result){
return $result;
+12 -3
View File
@@ -1,14 +1,19 @@
<?php
/**
* Global Search Engine for Moodle
* add-on 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* this is a format handler for getting text out of a proprietary binary format
* so it can be indexed by Lucene search engine
*/
/**
/*
* first implementation is a trivial heuristic based on ppt character stream :
* text sequence always starts with a 00 9F 0F 04 sequence followed by a 15 bytes
* sequence
@@ -22,6 +27,10 @@
* based on these following rules, here is a little empiric texte extractor for PPT
*/
/**
* @param object $resource
* @uses CFG, USER
*/
function get_text_for_indexing_ppt(&$resource){
global $CFG, $USER;
+11 -2
View File
@@ -1,13 +1,22 @@
<?php
/**
* Global Search Engine for Moodle
* add-on 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* this is a format handler for getting text out of a proprietary binary format
* so it can be indexed by Lucene search engine
*/
/**
* @param object $resource
* @uses CFG, USER
*/
function get_text_for_indexing_txt(&$resource){
global $CFG, $USER;
+11 -2
View File
@@ -1,13 +1,22 @@
<?php
/**
* Global Search Engine for Moodle
* add-on 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* this is a format handler for getting text out of a proprietary binary format
* so it can be indexed by Lucene search engine
*/
/**
* @param object $resource
* @uses CFG, USER
*/
function get_text_for_indexing_xml(&$resource){
global $CFG, $USER;
+34 -15
View File
@@ -1,24 +1,31 @@
<?php
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* review 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Michael Campanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* document handling for all resources
* This file contains the mapping between a resource and it's indexable counterpart,
*
* Functions for iterating and retrieving the necessary records are now also included
* in this file, rather than mod/resource/lib.php
**/
*/
/**
* requires and includes
*/
require_once("$CFG->dirroot/search/documents/document.php");
require_once("$CFG->dirroot/mod/resource/lib.php");
/*
/* *
* a class for representing searchable information
*
**/
*/
class ResourceSearchDocument extends SearchDocument {
public function __construct(&$resource, $context_id) {
// generic information; required
@@ -68,6 +75,7 @@ function resource_iterator() {
* this function does not need a content iterator, returns all the info
* itself;
* @param notneeded to comply API, remember to fake the iterator array though
* @uses CFG
* @return an array of searchable documents
*/
function resource_get_content_for_index(&$notneeded) {
@@ -155,7 +163,10 @@ function resource_get_physical_file(&$resource, $context_id, $getsingle, &$docum
global $CFG;
// cannot index empty references
if (empty($resource->reference)) return false;
if (empty($resource->reference)){
mtrace("Cannot index, empty reference.");
return false;
}
// cannot index remote resources
if (resource_is_url($resource->reference)){
@@ -166,6 +177,7 @@ function resource_get_physical_file(&$resource, $context_id, $getsingle, &$docum
$fileparts = pathinfo($resource->reference);
// cannot index unknown or masked types
if (empty($fileparts['extension'])) {
mtrace("Cannot index without explicit extension.");
return false;
}
@@ -189,15 +201,15 @@ function resource_get_physical_file(&$resource, $context_id, $getsingle, &$docum
$resource->alltext = $function_name($resource);
if (!empty($resource->alltext)){
if ($getsingle){
return new ResourceSearchDocument(get_object_vars($resource), $context_id);
}
else{
$single = new ResourceSearchDocument(get_object_vars($resource), $context_id);
mtrace("finished file $resource->name as {$resource->reference}");
return $single;
} else {
$documents[] = new ResourceSearchDocument(get_object_vars($resource), $context_id);
}
mtrace("finished file $resource->name as {$resource->reference}");
}
}
else{
} else {
mtrace("fulltext handler not found for $ext type");
}
return false;
@@ -250,8 +262,7 @@ function resource_single_document($id, $itemtype) {
$document = resource_get_physical_file($resource, true, $context->id);
if (!$document) mtrace("Warning : this document {$resource->name} will not be indexed");
return $document;
}
else{
} else {
return new ResourceSearchDocument(get_object_vars($resource), $context->id);
}
}
@@ -305,5 +316,13 @@ function resource_check_text_access($path, $itemtype, $this_id, $user, $group_id
}
return true;
} //resource_check_text_access
}
/**
* post processes the url for cleaner output.
* @param string $title
*/
function resource_link_post_processing($title){
return mb_convert_encoding($title, 'auto', 'UTF-8');
}
?>
+16 -4
View File
@@ -1,13 +1,20 @@
<?php
/**
* Global Search Engine for Moodle
* add-on 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Michael Campanis, Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* document handling for techproject activity module
*/
/* see wiki_document.php for descriptions */
/**
* requires and includes
*/
require_once("$CFG->dirroot/search/documents/document.php");
require_once("$CFG->dirroot/mod/techproject/lib.php");
@@ -84,6 +91,7 @@ function techproject_get_content_for_index(&$techproject) {
foreach($entries as $anEntry) {
if ($anEntry) {
if (strlen($anEntry->description) > 0) {
$anEntry->author = '';
$documents[] = new TechprojectEntrySearchDocument(get_object_vars($anEntry), $techproject->course, $context->id);
}
}
@@ -113,18 +121,22 @@ function techproject_single_document($id, $itemtype) {
switch ($itemtype){
case 'requirement':{
$entry = get_record('techproject_requirement', 'id', $id);
$entry->author = '';
break;
}
case 'specification':{
$entry = get_record('techproject_specification', 'id', $id);
$entry->author = '';
break;
}
case 'milestone':{
$entry = get_record('techproject_milestone', 'id', $id);
$entry->author = '';
break;
}
case 'deliverable':{
$entry = get_record('techproject_deliverable', 'id', $id);
$entry->author = '';
break;
}
case 'task':{
@@ -136,7 +148,7 @@ function techproject_single_document($id, $itemtype) {
break;
}
}
$techprojet_course = get_field('techproject', 'course', 'id', $entry->projectid);
$techproject_course = get_field('techproject', 'course', 'id', $entry->projectid);
$coursemodule = get_field('modules', 'id', 'name', 'techproject');
$cm = get_record('course_modules', 'course', $techproject_course, 'module', $coursemodule, 'instance', $entry->projectid);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
+38 -33
View File
@@ -1,9 +1,13 @@
<?php
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* review 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Michael Campanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* document handling for wiki activity module
* This file contains the mapping between a wiki page and it's indexable counterpart,
@@ -11,22 +15,21 @@
*
* Functions for iterating and retrieving the necessary records are now also included
* in this file, rather than mod/wiki/lib.php
*
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package search
* @version 2007110400
**/
*/
/**
* includes and requires
*/
require_once("$CFG->dirroot/search/documents/document.php");
require_once("$CFG->dirroot/mod/wiki/lib.php");
/*
/**
* All the $doc->___ fields are required by the base document class!
* Each and every module that requires search functionality must correctly
* map their internal fields to the five $doc fields (id, title, author, contents
* and url). Any module specific data can be added to the $data object, which is
* serialised into a binary field in the index.
**/
*/
class WikiSearchDocument extends SearchDocument {
public function __construct(&$page, $wiki_id, $course_id, $group_id, $user_id, $context_id) {
// generic information; required
@@ -36,7 +39,7 @@ class WikiSearchDocument extends SearchDocument {
$doc->contextid = $context_id;
$doc->title = $page['pagename'];
$doc->date = $page['timemodified'];
$doc->date = $page['lastmodified'];
//remove '(ip.ip.ip.ip)' from wiki author field
$doc->author = preg_replace('/\(.*?\)/', '', $page['author']);
$doc->contents = $page['content'];
@@ -48,8 +51,8 @@ class WikiSearchDocument extends SearchDocument {
// construct the parent class
parent::__construct($doc, $data, $course_id, $group_id, $user_id, PATH_FOR_SEARCH_TYPE_WIKI);
} //constructor
} //WikiSearchDocument
}
}
/**
* converts a page name to cope Wiki constraints. Transforms spaces in plus.
@@ -58,13 +61,14 @@ class WikiSearchDocument extends SearchDocument {
*/
function wiki_name_convert($str) {
return str_replace(' ', '+', $str);
} //wiki_name_convert
}
/**
* constructs a valid link to a wiki content
* @param wikiId
* @param title
* @param version
* @param int $wikiId
* @param string $title
* @param int $version
* @uses CFG
*/
function wiki_make_link($wikiId, $title, $version) {
global $CFG;
@@ -75,9 +79,9 @@ function wiki_make_link($wikiId, $title, $version) {
/**
* rescued and converted from ewikimoodlelib.php
* retrieves latest version of a page
* @param entry the wiki object as a reference
* @param pagename the name of the page known by the wiki engine
* @param version
* @param object $entry the wiki object as a reference
* @param string $pagename the name of the page known by the wiki engine
* @param int $version
*/
function wiki_get_latest_page(&$entry, $pagename, $version = 0) {
$pagename = "'".addslashes($pagename)."'";
@@ -104,20 +108,20 @@ function wiki_get_latest_page(&$entry, $pagename, $version = 0) {
} else {
return false;
}
} //wiki_get_latest_page
}
/**
* fetches all pages, including old versions
* @param entry the wiki object as a reference
* @param object $entry the wiki object as a reference
* @return an array of record objects that represents pages of this wiki object
*/
function wiki_get_pages(&$entry) {
return get_records('wiki_pages', 'wiki', $entry->id);
} //wiki_get_pages
}
/**
* fetches all the latest versions of all the pages
*
* @param object $entry
*/
function wiki_get_latest_pages(&$entry) {
//== (My)SQL for this
@@ -134,14 +138,14 @@ function wiki_get_latest_pages(&$entry) {
if ($ids = get_records('wiki_pages', 'wiki', $entry->id, '', 'distinct pagename')) {
if ($pagesets = get_records('wiki_pages', 'wiki', $entry->id, '', 'distinct pagename')) {
foreach ($pagesets as $aPageset) {
$pages[] = wiki_get_latest_page($entry, $aPageset->id);
$pages[] = wiki_get_latest_page($entry, $aPageset->pagename);
}
} else {
return false;
}
}
return $pages;
} //wiki_get_latest_pages
}
/**
* part of search engine API
@@ -150,7 +154,7 @@ function wiki_get_latest_pages(&$entry) {
function wiki_iterator() {
$wikis = get_records('wiki');
return $wikis;
} //wiki_iterator
}
/**
* part of search engine API
@@ -182,13 +186,13 @@ function wiki_get_content_for_index(&$wiki) {
}
}
return $documents;
} //wiki_get_content_for_index
}
/**
* returns a single wiki search document based on a wiki_entry id
* @param id the id of the wiki
* @param itemtype the type of information (standard)
* @retuen a searchable document
* @return a searchable document
*/
function wiki_single_document($id, $itemtype) {
$page = get_record('wiki_pages', 'id', $id);
@@ -197,7 +201,7 @@ function wiki_single_document($id, $itemtype) {
$cm = get_record('course_modules', 'course', $entry->course, 'module', $coursemodule, 'instance', $entry->wikiid);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
return new WikiSearchDocument(get_object_vars($page), $entry->wikiid, $entry->course, $entry->groupid, $page->userid, $context->id);
} //wiki_single_document
}
/**
* dummy delete function that packs id with itemtype.
@@ -208,13 +212,13 @@ function wiki_delete($info, $itemtype) {
$object->id = $info;
$object->itemtype = $itemtype;
return $object;
} //wiki_delete
}
//returns the var names needed to build a sql query for addition/deletions
function wiki_db_names() {
//[primary id], [table name], [time created field name], [time modified field name]
return array(array('id', 'wiki_pages', 'created', 'lastmodified', 'standard'));
} //wiki_db_names
}
/**
* this function handles the access policy to contents indexed as searchable documents. If this
@@ -229,6 +233,7 @@ function wiki_db_names() {
* points out the indexed wiki page.
* @param user the user record denoting the user who searches
* @param group_id the current group used by the user when searching
* @uses CFG
* @return true if access is allowed, false elsewhere
*/
function wiki_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
@@ -256,5 +261,5 @@ function wiki_check_text_access($path, $itemtype, $this_id, $user, $group_id, $c
}
return true;
} //wiki_check_text_access
}
?>
+11 -2
View File
@@ -1,9 +1,18 @@
<?php
/*
/**
* Global Search Engine for Moodle
*
* @package search
* @category core
* @subpackage search_engine
* @author Michael Champanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* Entry page for /search
* Redirects to query.php, because that is the most likely place a
* user intended to go to when typing moodle.site/search
**/
*/
header("Location: query.php");
?>
+176 -155
View File
@@ -1,9 +1,13 @@
<?php
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* review 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage search_engine
* @author Michael Champanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* The indexer logic -
*
@@ -26,178 +30,195 @@
@ob_implicit_flush(true);
@ob_end_flush();
/**
* includes and requires
*/
require_once('../config.php');
require_once("$CFG->dirroot/search/lib.php");
//only administrators can index the moodle installation, because access to all pages is required
require_login();
/// only administrators can index the moodle installation, because access to all pages is required
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
require_login();
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
if (!isadmin()) {
error(get_string('beadmin', 'search'), "$CFG->wwwroot/login/index.php");
}
/// confirmation flag to prevent accidental reindexing (indexersplash.php is the correct entry point)
if (!isadmin()) {
error(get_string('beadmin', 'search'), "$CFG->wwwroot/login/index.php");
} //if
$sure = strtolower(optional_param('areyousure', '', PARAM_ALPHA));
if ($sure != 'yes') {
mtrace("<pre>Sorry, you need to confirm indexing via <a href='indexersplash.php'>indexersplash.php</a>"
.". (<a href='index.php'>Back to query page</a>).</pre>");
exit(0);
}
/// check for php5 (lib.php)
//confirmation flag to prevent accidental reindexing (indexersplash.php is the correct entry point)
$sure = strtolower(optional_param('areyousure', '', PARAM_ALPHA));
if (!search_check_php5()) {
$phpversion = phpversion();
mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version ".phpversion().")");
exit(0);
}
//php5 found, continue including php5-only files
//require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
require_once("$CFG->dirroot/search/indexlib.php");
mtrace('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /></head><body>');
mtrace('<pre>Server Time: '.date('r',time())."\n");
if (isset($CFG->search_indexer_busy) && $CFG->search_indexer_busy == '1') {
//means indexing was not finished previously
mtrace("Warning: Indexing was not successfully completed last time, restarting.\n");
}
/// turn on busy flag
if ($sure != 'yes') {
mtrace("<pre>Sorry, you need to confirm indexing via <a href='indexersplash.php'>indexersplash.php</a>"
.". (<a href='index.php'>Back to query page</a>).</pre>");
set_config('search_indexer_busy', '1');
//paths
$index_path = SEARCH_INDEX_PATH;
$index_db_file = "{$CFG->dirroot}/search/db/$CFG->dbtype.sql";
$dbcontrol = new IndexDBControl();
/// setup directory in data root
exit(0);
} //if
//check for php5 (lib.php)
if (!search_check_php5()) {
$phpversion = phpversion();
mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version $phpversion)");
exit(0);
}
//php5 found, continue including php5-only files
//require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
require_once("$CFG->dirroot/search/indexlib.php");
mtrace('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /></head><body>');
mtrace('<pre>Server Time: '.date('r',time())."\n");
if ($CFG->search_indexer_busy == '1') {
//means indexing was not finished previously
mtrace("Warning: Indexing was not successfully completed last time, restarting.\n");
}
//turn on busy flag
set_config('search_indexer_busy', '1');
//paths
$index_path = SEARCH_INDEX_PATH;
$index_db_file = "{$CFG->dirroot}/search/db/$CFG->dbtype.sql";
$dbcontrol = new IndexDBControl();
//setup directory in data root
if (!file_exists($index_path)) {
mtrace("Data directory ($index_path) does not exist, attempting to create.");
if (!mkdir($index_path)) {
search_pexit("Error creating data directory at: $index_path. Please correct.");
if (!file_exists($index_path)) {
mtrace("Data directory ($index_path) does not exist, attempting to create.");
if (!mkdir($index_path)) {
search_pexit("Error creating data directory at: $index_path. Please correct.");
}
else {
mtrace("Directory successfully created.");
}
}
else {
mtrace("Directory successfully created.");
mtrace("Using $index_path as data directory.");
}
}
else {
mtrace("Using $index_path as data directory.");
}
$index = new Zend_Search_Lucene($index_path, true);
/*
OBSOLETE REGENERATION - DB installs with search block by now
if (!$dbcontrol->checkDB()) {
search_pexit("Database error. Please check settings/files.");
}
*/
// New regeneration
mtrace('Deleting old index entries.');
delete_records(SEARCH_DATABASE_TABLE);
//begin timer
search_stopwatch();
mtrace("Starting activity modules\n");
//the presence of the required search functions -
// * mod_iterator
// * mod_get_content_for_index
//are the sole basis for including a module in the index at the moment.
$searchables = array();
// collects modules
if ($mods = get_records('modules', '', '', '', 'id,name')) {
$searchables = array_merge($searchables, $mods);
}
mtrace(count($searchables).' modules found.');
// collects blocks as indexable information may be found in blocks either
if ($blocks = get_records('block', '', '', '', 'id,name')) {
// prepend the "block_" prefix to discriminate document type plugins
foreach(array_keys($blocks) as $aBlockId){
$blocks[$aBlockId]->name = 'block_'.$blocks[$aBlockId]->name;
$index = new Zend_Search_Lucene($index_path, true);
/*
OBSOLETE REGENERATION - DB installs with search block by now
if (!$dbcontrol->checkDB()) {
search_pexit("Database error. Please check settings/files.");
}
$searchables = array_merge($searchables, $blocks);
mtrace(count($blocks).' blocks found.');
}
//add virtual modules onto the back of the array
$searchables = array_merge($searchables, search_get_additional_modules());
if ($searchables){
foreach ($searchables as $mod) {
$class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
if (file_exists($class_file)) {
include_once($class_file);
*/
//build function names
$iter_function = $mod->name.'_iterator';
$index_function = $mod->name.'_get_content_for_index';
$counter = 0;
if (function_exists($index_function) && function_exists($iter_function)) {
mtrace("Processing module function $index_function ...");
$sources = $iter_function();
if ($sources){
foreach ($sources as $i) {
$documents = $index_function($i);
//begin transaction
if ($documents){
foreach($documents as $document) {
$counter++;
//object to insert into db
$dbid = $dbcontrol->addDocument($document);
//synchronise db with index
$document->addField(Zend_Search_Lucene_Field::Keyword('dbid', $dbid));
//add document to index
$index->addDocument($document);
//commit every x new documents, and print a status message
if (($counter % 2000) == 0) {
$index->commit();
mtrace(".. $counter");
}
}
}
//end transaction
}
}
//commit left over documents, and finish up
$index->commit();
/// New regeneration
mtrace('Deleting old index entries.');
delete_records(SEARCH_DATABASE_TABLE);
/// begin timer
search_stopwatch();
mtrace("Starting activity modules\n");
//the presence of the required search functions -
// * mod_iterator
// * mod_get_content_for_index
//are the sole basis for including a module in the index at the moment.
$searchables = array();
/// collects modules
if ($mods = get_records('modules', '', '', '', 'id,name')) {
$searchables = array_merge($searchables, $mods);
}
mtrace(count($searchables).' modules found.');
mtrace("-- $counter documents indexed");
mtrace("done.\n");
// collects blocks as indexable information may be found in blocks either
if ($blocks = get_records('block', '', '', '', 'id,name')) {
// prepend the "block_" prefix to discriminate document type plugins
foreach(array_keys($blocks) as $aBlockId){
$blocks[$aBlockId]->name = 'block_'.$blocks[$aBlockId]->name;
}
$searchables = array_merge($searchables, $blocks);
mtrace(count($blocks).' blocks found.');
}
/// add virtual modules onto the back of the array
$searchables = array_merge($searchables, search_get_additional_modules());
if ($searchables){
foreach ($searchables as $mod) {
$class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
if (file_exists($class_file)) {
include_once($class_file);
//build function names
$iter_function = $mod->name.'_iterator';
$index_function = $mod->name.'_get_content_for_index';
$counter = 0;
if (function_exists($index_function) && function_exists($iter_function)) {
mtrace("Processing module function $index_function ...");
$sources = $iter_function();
if ($sources){
foreach ($sources as $i) {
$documents = $index_function($i);
//begin transaction
if ($documents){
foreach($documents as $document) {
$counter++;
//object to insert into db
$dbid = $dbcontrol->addDocument($document);
//synchronise db with index
$document->addField(Zend_Search_Lucene_Field::Keyword('dbid', $dbid));
//add document to index
$index->addDocument($document);
//commit every x new documents, and print a status message
if (($counter % 2000) == 0) {
$index->commit();
mtrace(".. $counter");
}
}
}
//end transaction
}
}
//commit left over documents, and finish up
$index->commit();
mtrace("-- $counter documents indexed");
mtrace("done.\n");
}
}
}
}
}
//finished modules
mtrace('Finished activity modules');
search_stopwatch();
/// finished modules
mtrace('Finished activity modules');
search_stopwatch();
mtrace(".<br/><a href='index.php'>Back to query page</a>.");
mtrace('</pre>');
mtrace(".<br/><a href='index.php'>Back to query page</a>.");
mtrace('</pre>');
/// finished, turn busy flag off
//finished, turn busy flag off
set_config('search_indexer_busy', '0');
set_config('search_indexer_busy', '0');
/// mark the time we last updated
//mark the time we last updated
set_config('search_indexer_run_date', time());
set_config('search_indexer_run_date', time());
/// and the index size
//and the index size
set_config('search_index_size', (int)$index->count());
set_config('search_index_size', (int)$index->count());
?>
+67 -42
View File
@@ -1,55 +1,80 @@
<?php
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* review 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage search_engine
* @author Michael Champanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* This file serves as a splash-screen (entry page) to the indexer script -
* it is in place to prevent accidental reindexing which can lead to a loss
* of time, amongst other things.
**/
*/
/**
* includes and requires
*/
require_once('../config.php');
require_once("$CFG->dirroot/search/lib.php");
require_login();
/// check global search is enabled
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
require_login();
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
if (!isadmin()) {
error(get_string('beadmin', 'search'), "$CFG->wwwroot/login/index.php");
}
/// check for php5 (lib.php)
if (!isadmin()) {
error(get_string('beadmin', 'search'), "$CFG->wwwroot/login/index.php");
}
//check for php5 (lib.php)
if (!search_check_php5()) {
$phpversion = phpversion();
mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version $phpversion)");
exit(0);
}
require_once("$CFG->dirroot/search/indexlib.php");
$indexinfo = new IndexInfo();
if ($indexinfo->valid()) {
mtrace("<pre>The data directory ($indexinfo->path) contains $indexinfo->filecount files, and\n"
."there are ".$indexinfo->dbcount." records in the <em>block_search_documents</em> table.\n"
."\n"
."This indicates that you have already succesfully indexed this site. Follow the link\n"
."if you are sure that you want to continue indexing - this will replace any existing\n"
."index data (no Moodle data is affected).\n"
."\n"
."You are encouraged to use the 'Test indexing' script before continuing onto\n"
."indexing - this will check if the modules are set up correctly. Please correct\n"
."any errors before proceeding.\n"
."\n"
."<a href='tests/index.php'>Test indexing</a> or "
."<a href='indexer.php?areyousure=yes'>Continue indexing</a> or <a href='index.php'>Back to query page</a>."
."</pre>");
}
else {
header('Location: indexer.php?areyousure=yes');
}
?>
if (!search_check_php5()) {
$phpversion = phpversion();
mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version ".phpversion().")");
exit(0);
}
require_once("$CFG->dirroot/search/indexlib.php");
$indexinfo = new IndexInfo();
if ($indexinfo->valid()) {
$strsearch = get_string('search', 'search');
$strquery = get_string('stats');
$navlinks[] = array('name' => $strsearch, 'link' => "index.php", 'type' => 'misc');
$navlinks[] = array('name' => $strquery, 'link' => "stats.php", 'type' => 'misc');
$navlinks[] = array('name' => get_string('runindexer','search'), 'link' => null, 'type' => 'misc');
if ($CFG->version <= 2007021541){ // 1.8 branch stable timestamp
$navigation = '';
} else {
$navigation = build_navigation($navlinks);
}
$site = get_site();
print_header("$strsearch", "$site->fullname" , $navigation, "", "", true, "&nbsp;", navmenu($site));
mtrace("<pre>The data directory ($indexinfo->path) contains $indexinfo->filecount files, and\n"
."there are ".$indexinfo->dbcount." records in the <em>block_search_documents</em> table.\n"
."\n"
."This indicates that you have already succesfully indexed this site. Follow the link\n"
."if you are sure that you want to continue indexing - this will replace any existing\n"
."index data (no Moodle data is affected).\n"
."\n"
."You are encouraged to use the 'Test indexing' script before continuing onto\n"
."indexing - this will check if the modules are set up correctly. Please correct\n"
."any errors before proceeding.\n"
."\n"
."<a href='tests/index.php'>Test indexing</a> or "
."<a href='indexer.php?areyousure=yes'>Continue indexing</a> or <a href='index.php'>Back to query page</a>."
."</pre>");
print_footer();
}
else {
header('Location: indexer.php?areyousure=yes');
}
?>
+43 -32
View File
@@ -1,20 +1,32 @@
<?php
/*
* Author: Michael Champanis
/**
* Global Search Engine for Moodle
*
* Reviewed by: Valery Fremaux (2007)
* @package search
* @category core
* @subpackage search_engine
* @author Michael Champanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* Index info class
*
* Used to retrieve information about an index.
* Has methods to check for valid database and data directory,
* and the index itself.
**/
*/
/**
* includes and requires
*/
require_once("$CFG->dirroot/search/lib.php");
require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
/**
* main class for searchable information in the Lucene index
*/
class IndexInfo {
private $path, //index data directory
$size, //size of directory (i.e. the whole index)
$filecount, //number of files
@@ -35,7 +47,7 @@ class IndexInfo {
$validindex = true;
} catch(Exception $e) {
$validindex = false;
} //catch
}
//retrieve file system info about the index if it is valid
if ($validindex) {
@@ -73,32 +85,29 @@ class IndexInfo {
$c = count_records(SEARCH_DATABASE_TABLE, 'doctype', $type);
$this->types[$type] = (int)$c;
}
}
else {
} else {
$this->dbcount = 0;
$this->types = array();
}
//check if the busy flag is set
if ($CFG->search_indexer_busy == '1') {
if (isset($CFG->search_indexer_busy) && $CFG->search_indexer_busy == '1') {
$this->complete = false;
}
else {
} else {
$this->complete = true;
}
//get the last run date for the indexer
if ($this->valid() && $CFG->search_indexer_run_date) {
$this->time = $CFG->search_indexer_run_date;
}
else {
} else {
$this->time = 0;
}
} //__construct
}
/**
* returns false on error, and the error message via referenced variable $err
*
* @param array $err array of errors
*/
public function valid(&$err = null) {
$err = array();
@@ -120,7 +129,7 @@ class IndexInfo {
}
return $ret;
} //valid
}
/**
* is the index dir valid
@@ -129,11 +138,10 @@ class IndexInfo {
public function is_valid_dir() {
if ($this->filecount > 0) {
return true;
}
else {
} else {
return false;
}
} //is_valid_dir
}
/**
* is the db table valid
@@ -142,34 +150,34 @@ class IndexInfo {
public function is_valid_db() {
if ($this->dbcount > 0) {
return true;
}
else {
} else {
return false;
}
} //is_valid_db
}
/**
* shorthand get method for the class variables
*
* @param object $var
*/
public function __get($var) {
if (in_array($var, array_keys(get_class_vars(get_class($this))))) {
return $this->$var;
}
} //__get
} //IndexInfo
}
}
/*
/**
* DB Index control class
*
* Used to control the search index database table
**/
*/
class IndexDBControl {
/**
* does the table exist?
* OBSOLETE
* @deprecated
* @uses CFG, db
*/
public function checkTableExists() {
global $CFG, $db;
@@ -186,7 +194,8 @@ class IndexDBControl {
/**
* is our database setup valid?
* OBSOLETE - Database is installed at install and should not be dropped out
* @uses db, CFG
* @deprecated Database is installed at install and should not be dropped out
*/
public function checkDB() {
global $CFG, $db;
@@ -209,6 +218,7 @@ class IndexDBControl {
/**
* add a document record to the table
* @param document must be a Lucene SearchDocument instance
* @uses db, CFG
*/
public function addDocument($document=null) {
global $db, $CFG;
@@ -223,7 +233,7 @@ class IndexDBControl {
$doc->itemtype = $document->itemtype;
$doc->title = search_escape_string($document->title);
$doc->url = search_escape_string($document->url);
$doc->update = time();
$doc->updated = time();
$doc->docdate = $document->date;
$doc->courseid = $document->course_id;
$doc->groupid = $document->group_id;
@@ -232,17 +242,18 @@ class IndexDBControl {
$id = insert_record(SEARCH_DATABASE_TABLE, $doc);
return $id;
} //addDocument
}
/**
* remove a document record from the index
* @param document must be a Lucene document instance, or at least a dbid enveloppe
* @uses db
*/
public function delDocument($document) {
global $db;
delete_records(SEARCH_DATABASE_TABLE, 'id', $document->dbid);
} //delDocument
} //IndexControl
}
}
?>
+12 -6
View File
@@ -1,14 +1,20 @@
<?php
/*
* Author: Michael Champanis
/**
* Global Search Engine for Moodle
*
* @package search
* @category core
* @subpackage search_engine
* @author Michael Champanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* General function library
*
* This file must not contain any PHP 5, because it is used to test for PHP 5
* itself, and needs to be able to be executed on PHP 4 installations.
*
* Reviewed by: Valery Fremaux (2007)
* - adding techproject search capabilities
* - adding full internationalization
**/
*/
/*
// function reference
+351 -327
View File
@@ -1,337 +1,361 @@
<?php
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* review 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* The query page - accepts a user-entered query string and returns results.
*
* Queries are boolean-aware, e.g.:
*
* '+' term required
* '-' term must not be present
* '' (no modifier) term's presence increases rank, but isn't required
* 'field:' search this field
*
* Examples:
*
* 'earthquake +author:michael'
* Searches for documents written by 'michael' that contain 'earthquake'
*
* 'earthquake +doctype:wiki'
* Search all wiki pages for 'earthquake'
*
* '+author:helen +author:foster'
* All articles written by Helen Foster
*
*/
require_once('../config.php');
require_once("$CFG->dirroot/search/lib.php");
if ($CFG->forcelogin) {
require_login();
}
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
$adv = new Object();
// check for php5, but don't die yet (see line 52)
if ($check = search_check_php5()) {
require_once("{$CFG->dirroot}/search/querylib.php");
$page_number = optional_param('page', -1, PARAM_INT);
$pages = ($page_number == -1) ? false : true;
$advanced = (optional_param('a', '0', PARAM_INT) == '1') ? true : false;
$query_string = optional_param('query_string', '', PARAM_CLEAN);
if ($pages && isset($_SESSION['search_advanced_query'])) {
// if both are set, then we are busy browsing through the result pages of an advanced query
$adv = unserialize($_SESSION['search_advanced_query']);
}
else if ($advanced) {
// otherwise we are dealing with a new advanced query
unset($_SESSION['search_advanced_query']);
session_unregister('search_advanced_query');
// chars to strip from strings (whitespace)
$chars = " \t\n\r\0\x0B,-+";
// retrieve advanced query variables
$adv->mustappear = trim(optional_param('mustappear', '', PARAM_CLEAN), $chars);
$adv->notappear = trim(optional_param('notappear', '', PARAM_CLEAN), $chars);
$adv->canappear = trim(optional_param('canappear', '', PARAM_CLEAN), $chars);
$adv->module = optional_param('module', '', PARAM_CLEAN);
$adv->title = trim(optional_param('title', '', PARAM_CLEAN), $chars);
$adv->author = trim(optional_param('author', '', PARAM_CLEAN), $chars);
}
if ($advanced) {
//parse the advanced variables into a query string
//TODO: move out to external query class (QueryParse?)
$query_string = '';
// get all available module types
$module_types = array_merge(array('all'), array_values(search_get_document_types()));
$adv->module = in_array($adv->module, $module_types) ? $adv->module : 'all';
// convert '1 2' into '+1 +2' for required words field
if (strlen(trim($adv->mustappear)) > 0) {
$query_string = ' +'.implode(' +', preg_split("/[\s,;]+/", $adv->mustappear));
}
// convert '1 2' into '-1 -2' for not wanted words field
if (strlen(trim($adv->notappear)) > 0) {
$query_string .= ' -'.implode(' -', preg_split("/[\s,;]+/", $adv->notappear));
}
// this field is left untouched, apart from whitespace being stripped
if (strlen(trim($adv->canappear)) > 0) {
$query_string .= ' '.implode(' ', preg_split("/[\s,;]+/", $adv->canappear));
}
// add module restriction
$doctypestr = get_string('doctype', 'search');
$titlestr = get_string('title', 'search');
$authorstr = get_string('author', 'search');
if ($adv->module != 'all') {
$query_string .= " +{$doctypestr}:".$adv->module;
}
// create title search string
if (strlen(trim($adv->title)) > 0) {
$query_string .= " +{$titlestr}:".implode(" +{$titlestr}:", preg_split("/[\s,;]+/", $adv->title));
}
// create author search string
if (strlen(trim($adv->author)) > 0) {
$query_string .= " +{$authorstr}:".implode(" +{$authorstr}:", preg_split("/[\s,;]+/", $adv->author));
}
// save our options if the query is valid
if (!empty($query_string)) {
$_SESSION['search_advanced_query'] = serialize($adv);
}
}
// normalise page number
if ($page_number < 1) {
$page_number = 1;
}
//run the query against the index
$sq = new SearchQuery($query_string, $page_number, 10, false);
}
if (!$site = get_site()) {
redirect("index.php");
}
$strsearch = get_string('search', 'search');
$strquery = get_string('enteryoursearchquery', 'search');
print_header("$site->shortname: $strsearch: $strquery", "$site->fullname",
"<a href=\"index.php\">$strsearch</a> -> $strquery");
//keep things pretty, even if php5 isn't available
if (!$check) {
print_heading(search_check_php5(true));
print_footer();
exit(0);
}
print_box_start();
print_heading($strquery);
print_box_start();
$vars = get_object_vars($adv);
if (isset($vars)) {
foreach ($vars as $key => $value) {
$adv->$key = stripslashes(htmlentities($value));
}
}
?>
<form id="query" method="get" action="query.php">
<?php
if (!$advanced) {
?>
<input type="text" name="query_string" length="50" value="<?php print stripslashes($query_string) ?>" />
&nbsp;<input type="submit" value="<?php print_string('search', 'search') ?>" /> &nbsp;
<a href="query.php?a=1"><?php print_string('advancedsearch', 'search') ?></a> |
<a href="stats.php"><?php print_string('statistics', 'search') ?></a>
<?php
}
else {
print_box_start();
?>
<input type="hidden" name="a" value="<?php print $advanced; ?>"/>
<table border="0" cellpadding="3" cellspacing="3">
<tr>
<td width="240"><?php print_string('thesewordsmustappear', 'search') ?>:</td>
<td><input type="text" name="mustappear" length="50" value="<?php print $adv->mustappear; ?>" /></td>
</tr>
<tr>
<td><?php print_string('thesewordsmustnotappear', 'search') ?>:</td>
<td><input type="text" name="notappear" length="50" value="<?php print $adv->notappear; ?>" /></td>
</tr>
<tr>
<td><?php print_string('thesewordshelpimproverank', 'search') ?>:</td>
<td><input type="text" name="canappear" length="50" value="<?php print $adv->canappear; ?>" /></td>
</tr>
<tr>
<td><?php print_string('whichmodulestosearch?', 'search') ?>:</td>
<td>
<select name="module">
<?php
foreach($module_types as $mod) {
if ($mod == $adv->module) {
if ($mod != 'all'){
print "<option value='$mod' selected=\"selected\">".get_string('modulenameplural', $mod)."</option>\n";
}
else{
print "<option value='$mod' selected=\"selected\">".get_string('all', 'search')."</option>\n";
}
}
else {
if ($mod != 'all'){
print "<option value='$mod'>".get_string('modulenameplural', $mod)."</option>\n";
}
else{
print "<option value='$mod'>".get_string('all', 'search')."</option>\n";
}
}
}
?>
</select>
</td>
</tr>
<tr>
<td><?php print_string('wordsintitle', 'search') ?>:</td>
<td><input type="text" name="title" length="50" value="<?php print $adv->title; ?>" /></td>
</tr>
<tr>
<td><?php print_string('authorname', 'search') ?>:</td>
<td><input type="text" name="author" length="50" value="<?php print $adv->author; ?>" /></td>
</tr>
<tr>
<td colspan="3" align="center"><br /><input type="submit" value="<?php print_string('search', 'search') ?>" /></td>
</tr>
<tr>
<td colspan="3" align="center">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td><a href="query.php"><?php print_string('normalsearch', 'search') ?></a> |</td>
<td>&nbsp;<a href="stats.php"><?php print_string('statistics', 'search') ?></a></td>
</tr>
</table>
</td>
</tr>
</table>
<?php
print_box_end();
}
?>
</form>
<br/>
<div align="center">
<?php
print_string('searching', 'search') . ': ';
if ($sq->is_valid_index()) {
//use cached variable to show up-to-date index size (takes deletions into account)
print $CFG->search_index_size;
}
else {
print "0";
}
print ' ';
print_string('documents', 'search');
print '.';
if (!$sq->is_valid_index() and isadmin()) {
print '<p>' . get_string('noindexmessage', 'search') . '<a href="indexersplash.php">' . get_string('createanindex', 'search')."</a></p>\n";
}
?>
</div>
<?php
print_box_end();
// prints all the results in a box
if ($sq->is_valid()) {
print_box_start();
/**
* Global Search Engine for Moodle
*
* @package search
* @category core
* @subpackage search_engine
* @author Michael Champanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* The query page - accepts a user-entered query string and returns results.
*
* Queries are boolean-aware, e.g.:
*
* '+' term required
* '-' term must not be present
* '' (no modifier) term's presence increases rank, but isn't required
* 'field:' search this field
*
* Examples:
*
* 'earthquake +author:michael'
* Searches for documents written by 'michael' that contain 'earthquake'
*
* 'earthquake +doctype:wiki'
* Search all wiki pages for 'earthquake'
*
* '+author:helen +author:foster'
* All articles written by Helen Foster
*
*/
search_stopwatch();
$hit_count = $sq->count();
/**
* includes and requires
*/
require_once('../config.php');
require_once("$CFG->dirroot/search/lib.php");
if ($CFG->forcelogin) {
require_login();
}
print "<br />";
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
print $hit_count.' '.get_string('resultsreturnedfor', 'search') . " '".stripslashes($query_string)."'.";
print "<br />";
$adv = new Object();
/// check for php5, but don't die yet (see line 52)
if ($check = search_check_php5()) {
require_once("{$CFG->dirroot}/search/querylib.php");
$page_number = optional_param('page', -1, PARAM_INT);
$pages = ($page_number == -1) ? false : true;
$advanced = (optional_param('a', '0', PARAM_INT) == '1') ? true : false;
$query_string = optional_param('query_string', '', PARAM_CLEAN);
if ($pages && isset($_SESSION['search_advanced_query'])) {
// if both are set, then we are busy browsing through the result pages of an advanced query
$adv = unserialize($_SESSION['search_advanced_query']);
}
else if ($advanced) {
// otherwise we are dealing with a new advanced query
unset($_SESSION['search_advanced_query']);
session_unregister('search_advanced_query');
// chars to strip from strings (whitespace)
$chars = " \t\n\r\0\x0B,-+";
// retrieve advanced query variables
$adv->mustappear = trim(optional_param('mustappear', '', PARAM_CLEAN), $chars);
$adv->notappear = trim(optional_param('notappear', '', PARAM_CLEAN), $chars);
$adv->canappear = trim(optional_param('canappear', '', PARAM_CLEAN), $chars);
$adv->module = optional_param('module', '', PARAM_CLEAN);
$adv->title = trim(optional_param('title', '', PARAM_CLEAN), $chars);
$adv->author = trim(optional_param('author', '', PARAM_CLEAN), $chars);
}
if ($hit_count > 0) {
$page_links = $sq->page_numbers();
$hits = $sq->results();
if ($advanced) {
// if in advanced mode, search options are saved in the session, so
// we can remove the query string var from the page links, and replace
// it with a=1 (Advanced = on) instead
$page_links = preg_replace("/query_string=[^&]+/", 'a=1', $page_links);
//parse the advanced variables into a query string
//TODO: move out to external query class (QueryParse?)
$query_string = '';
// get all available module types
$module_types = array_merge(array('all'), array_values(search_get_document_types()));
$adv->module = in_array($adv->module, $module_types) ? $adv->module : 'all';
// convert '1 2' into '+1 +2' for required words field
if (strlen(trim($adv->mustappear)) > 0) {
$query_string = ' +'.implode(' +', preg_split("/[\s,;]+/", $adv->mustappear));
}
// convert '1 2' into '-1 -2' for not wanted words field
if (strlen(trim($adv->notappear)) > 0) {
$query_string .= ' -'.implode(' -', preg_split("/[\s,;]+/", $adv->notappear));
}
// this field is left untouched, apart from whitespace being stripped
if (strlen(trim($adv->canappear)) > 0) {
$query_string .= ' '.implode(' ', preg_split("/[\s,;]+/", $adv->canappear));
}
// add module restriction
$doctypestr = get_string('doctype', 'search');
$titlestr = get_string('title', 'search');
$authorstr = get_string('author', 'search');
if ($adv->module != 'all') {
$query_string .= " +{$doctypestr}:".$adv->module;
}
// create title search string
if (strlen(trim($adv->title)) > 0) {
$query_string .= " +{$titlestr}:".implode(" +{$titlestr}:", preg_split("/[\s,;]+/", $adv->title));
}
// create author search string
if (strlen(trim($adv->author)) > 0) {
$query_string .= " +{$authorstr}:".implode(" +{$authorstr}:", preg_split("/[\s,;]+/", $adv->author));
}
// save our options if the query is valid
if (!empty($query_string)) {
$_SESSION['search_advanced_query'] = serialize($adv);
}
}
print "<ol>";
$typestr = get_string('type', 'search');
$scorestr = get_string('score', 'search');
$authorstr = get_string('author', 'search');
foreach ($hits as $listing) {
if ($CFG->unicodedb) $listing->title = mb_convert_encoding($listing->title, 'auto', 'UTF8');
$title_post_processing_function = $listing->doctype.'_link_post_processing';
require_once "{$CFG->dirroot}/search/documents/{$listing->doctype}_document.php";
if (function_exists($title_post_processing_function))
$listing->title = $title_post_processing_function($listing->title);
print "<li value='".($listing->number+1)."'><a href='".str_replace('DEFAULT_POPUP_SETTINGS', DEFAULT_POPUP_SETTINGS ,$listing->url)."'>$listing->title</a><br />\n"
."<em>".search_shorten_url($listing->url, 70)."</em><br />\n"
."{$typestr}: ".$listing->doctype.", {$scorestr}: ".round($listing->score, 3).", {$authorstr}: ".$listing->author."\n"
."</li>\n";
}
print "</ol>";
print $page_links;
// normalise page number
if ($page_number < 1) {
$page_number = 1;
}
//run the query against the index
$sq = new SearchQuery($query_string, $page_number, 10, false);
}
if (!$site = get_site()) {
redirect("index.php");
}
$strsearch = get_string('search', 'search');
$strquery = get_string('enteryoursearchquery', 'search');
if ($CFG->version < 2007032200){
print_header("$site->shortname: $strsearch: $strquery", "$site->fullname",
"<a href=\"index.php\">$strsearch</a> -> $strquery");
} else {
$navlinks[] = array('name' => $strsearch, 'link' => "index.php", 'type' => 'misc');
$navlinks[] = array('name' => $strquery, 'link' => null, 'type' => 'misc');
$navigation = build_navigation($navlinks);
$site = get_site();
print_header("$strsearch", "$site->fullname" , $navigation, "", "", true, "&nbsp;", navmenu($site));
}
//keep things pretty, even if php5 isn't available
if (!$check) {
print_heading(search_check_php5(true));
print_footer();
exit(0);
}
print_box_start();
print_heading($strquery);
print_box_start();
$vars = get_object_vars($adv);
if (isset($vars)) {
foreach ($vars as $key => $value) {
// htmlentities breaks non-ascii chars
$adv->key = stripslashes($value);
//$adv->$key = stripslashes(htmlentities($value));
}
}
?>
<form id="query" method="get" action="query.php">
<?php
if (!$advanced) {
?>
<input type="text" name="query_string" length="50" value="<?php print stripslashes($query_string) ?>" />
&nbsp;<input type="submit" value="<?php print_string('search', 'search') ?>" /> &nbsp;
<a href="query.php?a=1"><?php print_string('advancedsearch', 'search') ?></a> |
<a href="stats.php"><?php print_string('statistics', 'search') ?></a>
<?php
}
else {
print_box_start();
?>
<input type="hidden" name="a" value="<?php print $advanced; ?>"/>
<table border="0" cellpadding="3" cellspacing="3">
<tr>
<td width="240"><?php print_string('thesewordsmustappear', 'search') ?>:</td>
<td><input type="text" name="mustappear" length="50" value="<?php print $adv->mustappear; ?>" /></td>
</tr>
<tr>
<td><?php print_string('thesewordsmustnotappear', 'search') ?>:</td>
<td><input type="text" name="notappear" length="50" value="<?php print $adv->notappear; ?>" /></td>
</tr>
<tr>
<td><?php print_string('thesewordshelpimproverank', 'search') ?>:</td>
<td><input type="text" name="canappear" length="50" value="<?php print $adv->canappear; ?>" /></td>
</tr>
<tr>
<td><?php print_string('whichmodulestosearch?', 'search') ?>:</td>
<td>
<select name="module">
<?php
foreach($module_types as $mod) {
if ($mod == $adv->module) {
if ($mod != 'all'){
print "<option value='$mod' selected=\"selected\">".get_string('modulenameplural', $mod)."</option>\n";
}
else{
print "<option value='$mod' selected=\"selected\">".get_string('all', 'search')."</option>\n";
}
}
else {
if ($mod != 'all'){
print "<option value='$mod'>".get_string('modulenameplural', $mod)."</option>\n";
}
else{
print "<option value='$mod'>".get_string('all', 'search')."</option>\n";
}
}
}
?>
</select>
</td>
</tr>
<tr>
<td><?php print_string('wordsintitle', 'search') ?>:</td>
<td><input type="text" name="title" length="50" value="<?php print $adv->title; ?>" /></td>
</tr>
<tr>
<td><?php print_string('authorname', 'search') ?>:</td>
<td><input type="text" name="author" length="50" value="<?php print $adv->author; ?>" /></td>
</tr>
<tr>
<td colspan="3" align="center"><br /><input type="submit" value="<?php print_string('search', 'search') ?>" /></td>
</tr>
<tr>
<td colspan="3" align="center">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td><a href="query.php"><?php print_string('normalsearch', 'search') ?></a> |</td>
<td>&nbsp;<a href="stats.php"><?php print_string('statistics', 'search') ?></a></td>
</tr>
</table>
</td>
</tr>
</table>
<?php
print_box_end();
}
?>
</form>
<br/>
<div align="center">
<?php
print_string('searching', 'search') . ': ';
if ($sq->is_valid_index()) {
//use cached variable to show up-to-date index size (takes deletions into account)
print $CFG->search_index_size;
}
else {
print "0";
}
print ' ';
print_string('documents', 'search');
print '.';
if (!$sq->is_valid_index() and isadmin()) {
print '<p>' . get_string('noindexmessage', 'search') . '<a href="indexersplash.php">' . get_string('createanindex', 'search')."</a></p>\n";
}
?>
</div>
<?php
print_box_end();
?>
<div align="center">
<?php
print_string('ittook', 'search');
search_stopwatch();
print_string('tofetchtheseresults', 'search');
?>.
</div>
<?php
}
print_box_end();
print_footer();
// prints all the results in a box
if ($sq->is_valid()) {
print_box_start();
search_stopwatch();
$hit_count = $sq->count();
print "<br />";
print $hit_count.' '.get_string('resultsreturnedfor', 'search') . " '".stripslashes($query_string)."'.";
print "<br />";
if ($hit_count > 0) {
$page_links = $sq->page_numbers();
$hits = $sq->results();
if ($advanced) {
// if in advanced mode, search options are saved in the session, so
// we can remove the query string var from the page links, and replace
// it with a=1 (Advanced = on) instead
$page_links = preg_replace("/query_string=[^&]+/", 'a=1', $page_links);
}
print "<ol>";
$typestr = get_string('type', 'search');
$scorestr = get_string('score', 'search');
$authorstr = get_string('author', 'search');
foreach ($hits as $listing) {
//if ($CFG->unicodedb) {
//$listing->title = mb_convert_encoding($listing->title, 'auto', 'UTF8');
//}
$title_post_processing_function = $listing->doctype.'_link_post_processing';
require_once "{$CFG->dirroot}/search/documents/{$listing->doctype}_document.php";
if (function_exists($title_post_processing_function)) {
$listing->title = $title_post_processing_function($listing->title);
}
print "<li value='".($listing->number+1)."'><a href='".str_replace('DEFAULT_POPUP_SETTINGS', DEFAULT_POPUP_SETTINGS ,$listing->url)."'>$listing->title</a><br />\n"
."<em>".search_shorten_url($listing->url, 70)."</em><br />\n"
."{$typestr}: ".$listing->doctype.", {$scorestr}: ".round($listing->score, 3);
if (!empty($listing->author)){
print ", {$authorstr}: ".$listing->author."\n"
."</li>\n";
}
}
print "</ol>";
print $page_links;
}
print_box_end();
?>
<div align="center">
<?php
print_string('ittook', 'search');
search_stopwatch();
print_string('tofetchtheseresults', 'search');
?>.
</div>
<?php
}
print_box_end();
print_footer();
?>
+94 -65
View File
@@ -1,4 +1,18 @@
<?php
/**
* Global Search Engine for Moodle
*
* @package search
* @category core
* @subpackage search_engine
* @author Michael Champanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*/
/**
* includes and requires
*/
require_once("{$CFG->dirroot}/search/Zend/Search/Lucene.php");
define('DEFAULT_POPUP_SETTINGS', "\"menubar=0,location=0,scrollbars,resizable,width=600,height=450\"");
@@ -13,10 +27,12 @@ public $url,
$author,
$score,
$number;
} //SearchResult
}
//split this into Cache class and extend to SearchCache?
/**
* split this into Cache class and extend to SearchCache?
*/
class SearchCache {
private $mode,
$valid;
@@ -32,7 +48,7 @@ private $mode,
} //else
$this->valid = true;
} //constructor
}
/**
* returns the search cache status
@@ -40,7 +56,7 @@ private $mode,
*/
public function can_cache() {
return $this->valid;
} //can_cache
}
/**
*
@@ -53,7 +69,7 @@ private $mode,
//if this query is different from the last, clear out the last one
if ($id != false and $last_term != $id) {
$this->clear($last_term);
} //if
}
//store the new query if id and object are passed in
if ($object and $id) {
@@ -61,11 +77,10 @@ private $mode,
$this->store($id, $object);
return true;
//otherwise return the stored results
}
else if ($id and $this->exists($id)) {
} else if ($id and $this->exists($id)) {
return $this->fetch($id);
} //else
} //cache
}
}
/**
* do key exist in cache ?
@@ -76,8 +91,8 @@ private $mode,
switch ($this->mode) {
case 'session' :
return isset($_SESSION[$id]);
} //switch
} //exists
}
}
/**
* clears a cached object in cache
@@ -90,8 +105,8 @@ private $mode,
unset($_SESSION[$id]);
session_unregister($id);
return;
} //switch
} //clear
}
}
/**
* fetches a cached object
@@ -102,8 +117,8 @@ private $mode,
switch ($this->mode) {
case 'session' :
return ($this->exists($id)) ? unserialize($_SESSION[$id]) : false;
} //switch
} //fetch
}
}
/**
* put an object in cache
@@ -116,9 +131,9 @@ private $mode,
case 'session' :
$_SESSION[$id] = serialize($object);
return;
} //switch
} //store
} //SearchCache
}
}
}
/**
* Represents a single query with results
@@ -156,14 +171,14 @@ class SearchQuery {
} catch(Exception $e) {
$this->validindex = false;
return;
} //catch
}
if (empty($this->term)) {
$this->validquery = false;
} else {
$this->set_query($this->term);
} //else
} //constructor
}
}
/**
* determines state of query object depending on query entry and
@@ -173,22 +188,20 @@ class SearchQuery {
public function set_query($term = '') {
if (!empty($term)) {
$this->term = $term;
} //if
}
if (empty($this->term)) {
$this->validquery = false;
}
else {
} else {
$this->validquery = true;
} //else
}
if ($this->validquery and $this->validindex) {
$this->results = $this->get_results();
}
else {
} else {
$this->results = array();
} //else
} //set_query
}
}
/**
* accessor to the result table.
@@ -196,11 +209,12 @@ class SearchQuery {
*/
public function results() {
return $this->results;
} //results
}
/**
* do the effective collection of results
*
* @param boolean $all
* @uses USER
*/
private function process_results($all=false) {
global $USER;
@@ -224,22 +238,20 @@ class SearchQuery {
if (!$all) {
if ($hitcount < $this->results_per_page) {
$this->pagenumber = 1;
}
else if ($this->pagenumber > $totalpages) {
} else if ($this->pagenumber > $totalpages) {
$this->pagenumber = $totalpages;
} //if
}
$start = ($this->pagenumber - 1) * $this->results_per_page;
$end = $start + $this->results_per_page;
if ($end > $hitcount) {
$end = $hitcount;
} //if
}
else {
}
} else {
$start = 0;
$end = $hitcount;
} //else
}
$resultdoc = new SearchResult();
$resultdocs = array();
@@ -258,15 +270,14 @@ class SearchQuery {
//and store it
$resultdocs[] = clone($resultdoc);
} //if
else{
} else {
// lowers total_results one unit
$this->total_results--;
}
} //foreach
}
return $resultdocs;
} //process_results
}
/**
* get results of a search query using a caching strategy if available
@@ -281,20 +292,17 @@ class SearchQuery {
//cache the results so we don't have to compute this on every page-load
$cache->cache($this->term, $resultdocs);
//print "Using new results.";
}
else {
} else {
//There was something in the cache, so we're using that to save time
//print "Using cached results.";
} //else
}
else {
}
} else {
//no caching :(
//print "Caching disabled!";
$resultdocs = $this->process_results();
} //else
}
return $resultdocs;
} //get_results
}
/**
* constructs the results paging links on results.
@@ -314,7 +322,7 @@ class SearchQuery {
$ret .= "<a href='query.php?query_string={$query}&page=".($page-1)."'>&lt; {$back}</a>&nbsp;";
} else {
$ret .= "&lt; {$back}&nbsp;";
} //else
}
//don't <a href> the current page
for ($i = 1; $i <= $pages; $i++) {
@@ -322,15 +330,15 @@ class SearchQuery {
$ret .= "($i)&nbsp;";
} else {
$ret .= "<a href='query.php?query_string={$query}&page={$i}'>{$i}</a>&nbsp;";
} //else
} //for
}
}
//Next disabled if we're on the last page
if ($page < $pages) {
$ret .= "<a href='query.php?query_string={$query}&page=".($page+1)."'>{$next} &gt;</a>&nbsp;";
} else {
$ret .= "{$next} &gt;&nbsp;";
} //else
}
$ret .= "</div>";
@@ -343,10 +351,10 @@ class SearchQuery {
$start = $page + 5;
$end = $pages - 3;
$ret = preg_replace("/<a\D+\d+\D+>$start<\/a>.*?<a\D+\d+\D+>$end<\/a>/", '...', $ret);
} //if
}
return $ret;
} //page_numbers
}
/**
* can the user see this result ?
@@ -359,6 +367,7 @@ class SearchQuery {
* @param path the path that routes to the local lib.php of the searched
* surrounding object fot that document
* @param item_type a subclassing information for complex module data models
* @uses CFG
* // TODO reorder parameters more consistently
*/
private function can_display(&$user, $this_id, $doctype, $course_id, $group_id, $path, $item_type, $context_id) {
@@ -411,35 +420,55 @@ class SearchQuery {
}
return true;
} //can_display
}
/**
*
*/
public function count() {
return $this->total_results;
} //count
/**
*
*/
public function is_valid() {
return ($this->validquery and $this->validindex);
} //is_valid
}
/**
*
*/
public function is_valid_query() {
return $this->validquery;
} //is_valid_query
}
/**
*
*/
public function is_valid_index() {
return $this->validindex;
} //is_valid_index
}
/**
*
*/
public function total_pages() {
return ceil($this->count()/$this->results_per_page);
} //pages
}
/**
*
*/
public function get_pagenumber() {
return $this->pagenumber;
} //get_pagenumber
}
/**
*
*/
public function get_results_per_page() {
return $this->results_per_page;
} //get_results_per_page
} //SearchQuery
}
}
?>
+140 -129
View File
@@ -1,152 +1,163 @@
<?php
/**
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* review 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage search_engine
* @author Michael Champanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* Prints some basic statistics about the current index.
* Does some diagnostics if you are logged in as an administrator.
*
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package search
* @version 2007110400
*/
/**
* includes and requires
*/
require_once('../config.php');
require_once("{$CFG->dirroot}/search/lib.php");
if ($CFG->forcelogin) {
require_login();
}
/// checks global search is enabled
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
//check for php5, but don't die yet
if ($check = search_check_php5()) {
require_once("{$CFG->dirroot}/search/indexlib.php");
$indexinfo = new IndexInfo();
}
if (!$site = get_site()) {
redirect("index.php");
}
$strsearch = get_string('search', 'search');
$strquery = get_string('statistics', 'search');
print_header("$site->shortname: $strsearch: $strquery", "$site->fullname",
"<a href=\"index.php\">$strsearch</a> -> $strquery");
//keep things pretty, even if php5 isn't available
if (!$check) {
print_heading(search_check_php5(true));
print_footer();
exit(0);
}
print_box_start();
print_heading($strquery);
print_box_start();
$databasestr = get_string('database', 'search');
$documentsinindexstr = get_string('documentsinindex', 'search');
$deletionsinindexstr = get_string('deletionsinindex', 'search');
$documentsindatabasestr = get_string('documentsindatabase', 'search');
$databasestatestr = get_string('databasestate', 'search');
//this table is only for admins, shows index directory size and location
if (isadmin()) {
$datadirectorystr = get_string('datadirectory', 'search');
$inindexdirectorystr = get_string('filesinindexdirectory', 'search');
$totalsizestr = get_string('totalsize', 'search');
$errorsstr = get_string('errors', 'search');
$solutionsstr = get_string('solutions', 'search');
$checkdirstr = get_string('checkdir', 'search');
$checkdbstr = get_string('checkdb', 'search');
$checkdiradvicestr = get_string('checkdiradvice', 'search');
$checkdbadvicestr = get_string('checkdbadvice', 'search');
$runindexerteststr = get_string('runindexertest', 'search');
$runindexerstr = get_string('runindexer', 'search');
$admin_table->tablealign = "center";
$admin_table->align = array ("right", "left");
$admin_table->wrap = array ("nowrap", "nowrap");
$admin_table->cellpadding = 5;
$admin_table->cellspacing = 0;
$admin_table->width = '500';
$admin_table->data[] = array("<strong>{$datadirectorystr}</strong>", '<em><strong>'.$indexinfo->path.'</strong></em>');
$admin_table->data[] = array($inindexdirectorystr, $indexinfo->filecount);
$admin_table->data[] = array($totalsizestr, $indexinfo->size);
if ($indexinfo->time > 0) {
$admin_table->data[] = array(get_string('createdon', 'search'), date('r', $indexinfo->time));
}
else {
$admin_table->data[] = array(get_string('createdon', 'search'), '-');
}
if (!$indexinfo->valid($errors)) {
$admin_table->data[] = array("<strong>{$errorsstr}</strong>", '&nbsp;');
foreach ($errors as $key => $value) {
$admin_table->data[] = array($key.' ... ', $value);
}
if ($CFG->forcelogin) {
require_login();
}
print_table($admin_table);
print_spacer(20);
print_heading($solutionsstr);
unset($admin_table->data);
if (isset($errors['dir'])) {
$admin_table->data[] = array($checkdirstr, $checkdiradvicestr);
}
if (isset($errors['db'])) {
$admin_table->data[] = array($checkdbstr, $checkdbadvicestr);
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
/// check for php5, but don't die yet
if ($check = search_check_php5()) {
require_once("{$CFG->dirroot}/search/indexlib.php");
$indexinfo = new IndexInfo();
}
$admin_table->data[] = array($runindexerteststr, '<a href="tests/index.php" target="_blank">tests/index.php</a>');
$admin_table->data[] = array($runindexerstr, '<a href="indexersplash.php" target="_blank">indexersplash.php</a>');
if (!$site = get_site()) {
redirect("index.php");
}
print_table($admin_table);
print_spacer(20);
}
//this is the standard summary table for normal users, shows document counts
$table->tablealign = "center";
$table->align = array ("right", "left");
$table->wrap = array ("nowrap", "nowrap");
$table->cellpadding = 5;
$table->cellspacing = 0;
$table->width = '500';
$table->data[] = array("<strong>{$databasestr}</strong>", "<em><strong>{$CFG->prefix}".SEARCH_DATABASE_TABLE.'</strong></em>');
//add extra fields if we're admin
if (isadmin()) {
//don't want to confuse users if the two totals don't match (hint: they should)
$table->data[] = array($documentsinindexstr, $indexinfo->indexcount);
$strsearch = get_string('search', 'search');
$strquery = get_string('statistics', 'search');
//*cough* they should match if deletions were actually removed from the index,
//as it turns out, they're only marked as deleted and not returned in search results
$table->data[] = array($deletionsinindexstr, (int)$indexinfo->indexcount - (int)$indexinfo->dbcount);
}
print_header("$site->shortname: $strsearch: $strquery", "$site->fullname",
"<a href=\"index.php\">$strsearch</a> -> $strquery");
/// keep things pretty, even if php5 isn't available
$table->data[] = array($documentsindatabasestr, $indexinfo->dbcount);
if (!$check) {
print_heading(search_check_php5(true));
print_footer();
exit(0);
}
print_box_start();
print_heading($strquery);
print_box_start();
$databasestr = get_string('database', 'search');
$documentsinindexstr = get_string('documentsinindex', 'search');
$deletionsinindexstr = get_string('deletionsinindex', 'search');
$documentsindatabasestr = get_string('documentsindatabase', 'search');
$databasestatestr = get_string('databasestate', 'search');
/// this table is only for admins, shows index directory size and location
foreach($indexinfo->types as $key => $value) {
$table->data[] = array(get_string('documentsfor', 'search') . " '".get_string('modulenameplural', $key)."'", $value);
}
if (isadmin()) {
$datadirectorystr = get_string('datadirectory', 'search');
$inindexdirectorystr = get_string('filesinindexdirectory', 'search');
$totalsizestr = get_string('totalsize', 'search');
$errorsstr = get_string('errors', 'search');
$solutionsstr = get_string('solutions', 'search');
$checkdirstr = get_string('checkdir', 'search');
$checkdbstr = get_string('checkdb', 'search');
$checkdiradvicestr = get_string('checkdiradvice', 'search');
$checkdbadvicestr = get_string('checkdbadvice', 'search');
$runindexerteststr = get_string('runindexertest', 'search');
$runindexerstr = get_string('runindexer', 'search');
$admin_table->tablealign = "center";
$admin_table->align = array ("right", "left");
$admin_table->wrap = array ("nowrap", "nowrap");
$admin_table->cellpadding = 5;
$admin_table->cellspacing = 0;
$admin_table->width = '500';
$admin_table->data[] = array("<strong>{$datadirectorystr}</strong>", '<em><strong>'.$indexinfo->path.'</strong></em>');
$admin_table->data[] = array($inindexdirectorystr, $indexinfo->filecount);
$admin_table->data[] = array($totalsizestr, $indexinfo->size);
if ($indexinfo->time > 0) {
$admin_table->data[] = array(get_string('createdon', 'search'), date('r', $indexinfo->time));
}
else {
$admin_table->data[] = array(get_string('createdon', 'search'), '-');
}
if (!$indexinfo->valid($errors)) {
$admin_table->data[] = array("<strong>{$errorsstr}</strong>", '&nbsp;');
foreach ($errors as $key => $value) {
$admin_table->data[] = array($key.' ... ', $value);
}
}
print_table($admin_table);
print_spacer(20);
print_heading($solutionsstr);
unset($admin_table->data);
if (isset($errors['dir'])) {
$admin_table->data[] = array($checkdirstr, $checkdiradvicestr);
}
if (isset($errors['db'])) {
$admin_table->data[] = array($checkdbstr, $checkdbadvicestr);
}
$admin_table->data[] = array($runindexerteststr, '<a href="tests/index.php" target="_blank">tests/index.php</a>');
$admin_table->data[] = array($runindexerstr, '<a href="indexersplash.php" target="_blank">indexersplash.php</a>');
print_table($admin_table);
print_spacer(20);
}
/// this is the standard summary table for normal users, shows document counts
print_heading($databasestatestr);
print_table($table);
$table->tablealign = "center";
$table->align = array ("right", "left");
$table->wrap = array ("nowrap", "nowrap");
$table->cellpadding = 5;
$table->cellspacing = 0;
$table->width = '500';
$table->data[] = array("<strong>{$databasestr}</strong>", "<em><strong>{$CFG->prefix}".SEARCH_DATABASE_TABLE.'</strong></em>');
/// add extra fields if we're admin
print_box_end();
print_box_end();
print_footer();
if (isadmin()) {
//don't want to confuse users if the two totals don't match (hint: they should)
$table->data[] = array($documentsinindexstr, $indexinfo->indexcount);
//*cough* they should match if deletions were actually removed from the index,
//as it turns out, they're only marked as deleted and not returned in search results
$table->data[] = array($deletionsinindexstr, (int)$indexinfo->indexcount - (int)$indexinfo->dbcount);
}
$table->data[] = array($documentsindatabasestr, $indexinfo->dbcount);
foreach($indexinfo->types as $key => $value) {
$table->data[] = array(get_string('documentsfor', 'search') . " '".get_string('modulenameplural', $key)."'", $value);
}
print_heading($databasestatestr);
print_table($table);
print_box_end();
print_box_end();
print_footer();
?>
+130 -118
View File
@@ -1,9 +1,13 @@
<?php
/**
* Global Search Engine for Moodle
* Michael Champanis (mchampan) [[email protected]]
* review 1.8+ : Valery Fremaux [[email protected]]
* 2007/08/02
*
* @package search
* @category core
* @subpackage search_engine
* @author Michael Champanis (mchampan) [[email protected]], Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* Index asynchronous updator
*
@@ -11,133 +15,141 @@
* multiple arity to handle multiple document types modules
*/
/**
* includes and requires
*/
require_once('../config.php');
require_once("$CFG->dirroot/search/lib.php");
require_login();
/// checks global search activation
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
if (!isadmin()) {
error(get_string('beadmin', 'search'), "$CFG->wwwroot/login/index.php");
}
//check for php5 (lib.php)
if (!search_check_php5()) {
$phpversion = phpversion();
mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version $phpversion)");
exit(0);
}
require_once("$CFG->dirroot/search/indexlib.php");
$index = new Zend_Search_Lucene(SEARCH_INDEX_PATH);
$dbcontrol = new IndexDBControl();
$update_count = 0;
$indexdate = $CFG->search_indexer_update_date;
$startupdatedate = time();
mtrace("<pre>Starting index update (updates)...\n");
if ($mods = get_records_select('modules')) {
$mods = array_merge($mods, search_get_additional_modules());
require_login();
foreach ($mods as $mod) {
$class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
$get_document_function = $mod->name.'_single_document';
$delete_function = $mod->name.'_delete';
$db_names_function = $mod->name.'_db_names';
$updates = array();
if (file_exists($class_file)) {
require_once($class_file);
//if both required functions exist
if (function_exists($delete_function) and function_exists($db_names_function) and function_exists($get_document_function)) {
mtrace("Checking $mod->name module for updates.");
$valuesArray = $db_names_function();
if ($valuesArray){
foreach($valuesArray as $values){
$where = (isset($values[5])) ? 'AND ('.$values[5].')' : '';
$itemtypes = ($values[4] != '*') ? " AND itemtype = '{$values[4]}' " : '' ;
if (empty($CFG->enableglobalsearch)) {
error(get_string('globalsearchdisabled', 'search'));
}
if (!isadmin()) {
error(get_string('beadmin', 'search'), "$CFG->wwwroot/login/index.php");
}
/// check for php5 (lib.php)
//TODO: check 'in' syntax with other RDBMS' (add and update.php as well)
$table = SEARCH_DATABASE_TABLE;
$query = "
SELECT
docid,
itemtype
FROM
{$CFG->prefix}{$table}
WHERE
doctype = '{$mod->name}'
$itemtypes
";
$docIds = get_records_sql_menu($query);
$docIdList = ($docIds) ? implode("','", array_keys($docIds)) : '' ;
if (!search_check_php5()) {
$phpversion = phpversion();
mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version ".phpversion().")");
exit(0);
}
require_once("$CFG->dirroot/search/indexlib.php");
$index = new Zend_Search_Lucene(SEARCH_INDEX_PATH);
$dbcontrol = new IndexDBControl();
$update_count = 0;
$indexdate = $CFG->search_indexer_update_date;
$startupdatedate = time();
/// indexing changed resources
mtrace("Starting index update (updates)...\n");
if ($mods = get_records_select('modules')) {
$mods = array_merge($mods, search_get_additional_modules());
foreach ($mods as $mod) {
$class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
$get_document_function = $mod->name.'_single_document';
$delete_function = $mod->name.'_delete';
$db_names_function = $mod->name.'_db_names';
$updates = array();
if (file_exists($class_file)) {
require_once($class_file);
//if both required functions exist
if (function_exists($delete_function) and function_exists($db_names_function) and function_exists($get_document_function)) {
mtrace("Checking $mod->name module for updates.");
$valuesArray = $db_names_function();
if ($valuesArray){
foreach($valuesArray as $values){
$query = "
SELECT
id,
{$values[0]} as docid
FROM
{$CFG->prefix}{$values[1]}
WHERE
{$values[3]} > {$indexdate} AND
id IN ('{$docIdList}')
$where
";
$records = get_records_sql($query);
if (is_array($records)) {
foreach($records as $record) {
$updates[] = $delete_function($record->docid, $docIds[$record->docid]);
$where = (isset($values[5])) ? 'AND ('.$values[5].')' : '';
$itemtypes = ($values[4] != '*' && $values[4] != 'any') ? " AND itemtype = '{$values[4]}' " : '' ;
//TODO: check 'in' syntax with other RDBMS' (add and update.php as well)
$table = SEARCH_DATABASE_TABLE;
$query = "
SELECT
docid,
itemtype
FROM
{$CFG->prefix}{$table}
WHERE
doctype = '{$mod->name}'
$itemtypes
";
$docIds = get_records_sql_menu($query);
$docIdList = ($docIds) ? implode("','", array_keys($docIds)) : '' ;
$query = "
SELECT
id,
{$values[0]} as docid
FROM
{$CFG->prefix}{$values[1]}
WHERE
{$values[3]} > {$indexdate} AND
id IN ('{$docIdList}')
$where
";
$records = get_records_sql($query);
if (is_array($records)) {
foreach($records as $record) {
$updates[] = $delete_function($record->docid, $docIds[$record->docid]);
}
}
}
foreach ($updates as $update) {
++$update_count;
//delete old document
$doc = $index->find("+docid:{$update->id} +doctype:{$mod->name} +itemtype:{$update->itemtype}");
//get the record, should only be one
foreach ($doc as $thisdoc) {
mtrace(" Delete: $thisdoc->title (database id = $thisdoc->dbid, index id = $thisdoc->id, moodle instance id = $thisdoc->docid)");
$dbcontrol->delDocument($thisdoc);
$index->delete($thisdoc->id);
}
//add new modified document back into index
$add = $get_document_function($update->id, $update->itemtype);
//object to insert into db
$dbid = $dbcontrol->addDocument($add);
//synchronise db with index
$add->addField(Zend_Search_Lucene_Field::Keyword('dbid', $dbid));
mtrace(" Add: $add->title (database id = $add->dbid, moodle instance id = $add->docid)");
$index->addDocument($add);
}
}
foreach ($updates as $update) {
++$update_count;
//delete old document
$doc = $index->find("+docid:{$update->id} +doctype:{$mod->name} +itemtype:{$update->itemtype}");
//get the record, should only be one
foreach ($doc as $thisdoc) {
mtrace(" Delete: $thisdoc->title (database id = $thisdoc->dbid, index id = $thisdoc->id, moodle instance id = $thisdoc->docid)");
$dbcontrol->delDocument($thisdoc);
$index->delete($thisdoc->id);
}
//add new modified document back into index
$add = $get_document_function($update->id, $update->itemtype);
//object to insert into db
$dbid = $dbcontrol->addDocument($add);
//synchronise db with index
$add->addField(Zend_Search_Lucene_Field::Keyword('dbid', $dbid));
mtrace(" Add: $add->title (database id = $add->dbid, moodle instance id = $add->docid)");
$index->addDocument($add);
}
}
else{
mtrace("No types to update.\n");
}
mtrace("Finished $mod->name.\n");
else{
mtrace("No types to update.\n");
}
mtrace("Finished $mod->name.\n");
}
}
}
}
}
//commit changes
$index->commit();
//update index date
set_config("search_indexer_update_date", $startupdatedate);
mtrace("Finished $update_count updates.</pre>");
//commit changes
$index->commit();
//update index date
set_config("search_indexer_update_date", $startupdatedate);
mtrace("Finished $update_count updates");
?>