* @category class * @package core * @subpackage util * @copyright 2005-2017 Titan Framework * @license http://www.titanframework.com/license/ BSD License (3 Clause) * @see Instance, Section, Action, Business * @link https://lucene.apache.org/ */ class Lucene { static private $lucene = FALSE; static private $index = FALSE; private $path = FALSE; const ITEM = '__ITEM__'; const FILE = '__FILE__'; const MEDIA = '__MEDIA__'; private final function __construct () { $array = Instance::singleton ()->getLucene (); if (!is_array ($array) || !array_key_exists ('index-path', $array)) return; if (!class_exists ('Zend_Search_Lucene', FALSE)) return; $this->path = $array ['index-path']; try { Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding ('utf-8'); if (file_exists ($this->getPath ())) { self::$index = new Zend_Search_Lucene ($this->getPath ()); return; } set_time_limit (0); self::$index = new Zend_Search_Lucene ($this->getPath (), TRUE); $aSection = Business::singleton ()->getSection (Section::TCURRENT)->getName (); $aAction = Business::singleton ()->getAction (Action::TCURRENT)->getName (); $db = Database::singleton (); set_error_handler ('logPhpError'); while ($section = Business::singleton ()->getSection ()) { $targetActions = array (); while ($aux = $section->getAction ()) { $indexTo = trim ($aux->getIndex ()); if ($indexTo == '' || !$section->actionExists ($indexTo) || in_array ($indexTo, $targetActions)) continue; $targetActions [] = $indexTo; $action = $section->getAction ($indexTo); Business::singleton ()->setCurrent ($section->getName (), $action->getName ()); $form = new Form (array ($action->getXmlPath (), $action->getName () .'.xml', $action->getEngine () .'.xml', 'all.xml')); try { $sql = "SELECT ". $form->getPrimary () ." FROM ". $form->getTable () ." WHERE _deleted = B'0'"; $sth = $db->prepare ($sql); $sth->execute (); } catch (PDOException $e) { try { $sql = "SELECT ". $form->getPrimary () ." FROM ". $form->getTable (); $sth = $db->prepare ($sql); $sth->execute (); } catch (PDOException $e) { toLog ('Lucene Exception: Impossível capturar tuplas de ['. $form->getTable () .'].'); continue; } } $primary = $form->getPrimary (); while ($obj = $sth->fetch (PDO::FETCH_OBJ)) { $itemId = $obj->$primary; $url = 'titan.php?target=body&toSection='. $section->getName () .'&toAction='. $indexTo .'&itemId='. $itemId; $doc = new Zend_Search_Lucene_Document (); $doc->addField (Zend_Search_Lucene_Field::Keyword ('url', $url, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Keyword ('type', self::ITEM, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('local', getBreadPath ($section, FALSE, FALSE) . $section->getAction ($indexTo)->getLabel (), 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('content', $form->getResume ($itemId, TRUE), 'utf-8')); self::$index->addDocument ($doc); $form->setLoad (FALSE); } } } self::$index->commit (); self::$index->optimize (); $this->saveFile (array (), TRUE); restore_error_handler (); Log::singleton ()->add (__ ('Automatic Lucene Index creation. Added [1] documents.', self::$index->count ())); Message::singleton ()->addMessage (__ ('Automatic Lucene Index creation. Added [1] documents.', self::$index->count ())); Business::singleton ()->setCurrent ($aSection, $aAction); } catch (Exception $e) { $error = Instance::singleton ()->onDebugMode () ? $e->getMessage () : ''; Message::singleton ()->addWarning (__ ('Error on automatic Lucene Index creation! Contact administrator. [1]', '['. $error .']')); toLog ($e->getMessage ()); restore_error_handler (); } catch (PDOException $e) { $error = Instance::singleton ()->onDebugMode () ? $e->getMessage () : ''; Message::singleton ()->addWarning (__ ('Error on automatic Lucene Index creation! Contact administrator. [1]', '['. $error .']')); toLog ($e->getMessage ()); restore_error_handler (); return; } Message::singleton ()->save (); } static public function singleton () { if (self::$lucene !== FALSE) return self::$lucene; $class = __CLASS__; self::$lucene = new $class (); return self::$lucene; } public function getPath () { return $this->path; } public function getIndex () { return self::$index; } public function isActive () { return self::$index !== FALSE; } public function save ($url, $content, $indexTo = FALSE, $section = FALSE, $local = '') { if (!$this->isActive ()) return FALSE; if (is_numeric ($url)) { try { if ($section === FALSE) $oSection = Business::singleton ()->getSection (Section::TCURRENT); else $oSection = Business::singleton ()->getSection ($section); if ($indexTo === FALSE) $indexTo = Business::singleton ()->getAction (Action::TCURRENT)->getIndex (); if (trim ($indexTo) == '' || !$oSection->actionExists ($indexTo)) return FALSE; $oAction = $oSection->getAction ($indexTo); $url = 'titan.php?target=body&toSection='. $oSection->getName () .'&toAction='. $oAction->getName () .'&itemId='. $url; if ($local == '') $local = getBreadPath ($oSection, FALSE, FALSE) . $oAction->getLabel (); } catch (Exception $e) { toLog ($e->getMessage ()); return FALSE; } } try { set_time_limit (0); $index = $this->getIndex (); $term = new Zend_Search_Lucene_Index_Term ($url, 'url'); $ids = $index->termDocs ($term); foreach ($ids as $id) $index->delete ($id); $doc = new Zend_Search_Lucene_Document (); $doc->addField (Zend_Search_Lucene_Field::Keyword ('url', $url, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Keyword ('type', self::ITEM, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('local', $local, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('content', $content, 'utf-8')); $index->addDocument ($doc); $index->commit (); } catch (Exception $e) { toLog (__ ('Impossible create index search for [[1]]: [2].', $url, $e->getMessage ())); return FALSE; } return TRUE; } public function delete ($url) { if (!$this->isActive ()) return FALSE; if (is_numeric ($url)) { try { $oSection = Business::singleton ()->getSection (Section::TCURRENT); $indexTo = Business::singleton ()->getAction (Action::TCURRENT)->getIndex (); if (trim ($indexTo) == '') return FALSE; $oAction = $oSection->getAction ($indexTo); $url = 'titan.php?target=body&toSection='. $oSection->getName () .'&toAction='. $oAction->getName () .'&itemId='. $url; } catch (Exception $e) { toLog ($e->getMessage ()); return FALSE; } } try { $index = $this->getIndex (); $term = new Zend_Search_Lucene_Index_Term ($url, 'url'); $ids = $index->termDocs ($term); foreach ($ids as $id) $index->delete ($id); $index->commit (); } catch (Exception $e) { toLog (__ ('Impossible delete index search for [[1]]: [2].', $url, $e->getMessage ())); return FALSE; } catch (Zend_Search_Lucene_Search_QueryParserException $e) { toLog (__ ('Impossible delete index search for [[1]]: [2].', $url, $e->getMessage ())); return FALSE; } return TRUE; } public function saveFile ($ids, $indexAll = FALSE) { if (!$this->isActive ()) return FALSE; if (!is_array ($ids)) $ids = array ($ids); $sql = "SELECT _file.*, _user._name AS _user_name, to_char(_file._create_date, 'DD-MM-YYYY HH24:MI:SS') AS _date FROM _file LEFT JOIN _user ON _user._id = _file._user"; if ($indexAll !== TRUE) if (sizeof ($ids)) $sql .= " WHERE _file._id IN ('". implode ("', '", $ids) ."')"; else return TRUE; $db = Database::singleton (); $sth = $db->prepare ($sql); $sth->execute (); $flag = FALSE; while ($obj = $sth->fetch (PDO::FETCH_OBJ)) { $doc = FALSE; try { switch (trim ($obj->_mimetype)) { case 'application/pdf': $doc = self::pdfToIndex ($obj); break; case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': $doc = self::docxToIndex ($obj); break; case 'application/vnd.openxmlformats-officedocument.presentationml.presentation': $doc = self::pptxToIndex ($obj); break; case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': $doc = self::xlsxToIndex ($obj); break; case 'text/plain': $doc = self::txtToIndex ($obj); break; case 'application/msword': $doc = self::docToIndex ($obj); break; case 'text/html': $doc = self::htmlToIndex ($obj); break; default: continue; } } catch (Exception $e) { toLog ($e->getMessage ()); continue; } if (!is_object ($doc)) continue; self::$index->addDocument ($doc); $flag = TRUE; } if ($flag) { set_time_limit (0); self::$index->commit (); self::$index->optimize (); } return TRUE; } public function deleteFile ($fileIds) { if (!$this->isActive ()) return FALSE; if (!is_array ($fileIds)) $ids = array ($fileIds); try { $index = $this->getIndex (); foreach ($fileIds as $trash => $fileId) { $url = 'titan.php?target=openFile&fileId='. $fileId; $term = new Zend_Search_Lucene_Index_Term ($url, 'url'); $ids = $index->termDocs ($term); foreach ($ids as $id) $index->delete ($id); } $index->commit (); $index->optimize (); } catch (Exception $e) { toLog (__ ('Impossible delete index search for [[1]]: [2].', $url, $e->getMessage ())); return FALSE; } return TRUE; } static private function pdfToIndex ($obj) { $file = 'file_'. str_pad ($obj->_id, 7, '0', STR_PAD_LEFT); $original = File::getFilePath ($obj->_id); if (!file_exists ($original)) $original = File::getLegacyFilePath ($obj->_id); if (!file_exists ($original)) throw new Exception (__ ('File dont exists [[1]].', $original)); $path = Instance::singleton ()->getCachePath () .'text/'; if (!file_exists ($path) && !@mkdir ($path, 0777)) throw new Exception (__ ('Impossible to create [[1]].', $path)); if (!file_exists ($path . $file) || !(int) filesize ($path . $file)) @system ('pdftotext -enc Latin1 -nopgbrk -q '. $original .' '. $path . $file .' > '. $path .'log', $trash); if (!file_exists ($path . $file) || !(int) filesize ($path . $file)) throw new Exception (__ ('Impossible to create [[1]].', $path . $file)); $content = $obj->_name ." \n\n". $obj->_date ." \n\n". $obj->_user_name ." \n\n". file_get_contents ($path . $file); $url = 'titan.php?target=openFile&fileId='. $obj->_id; $doc = new Zend_Search_Lucene_Document (); $doc->addField (Zend_Search_Lucene_Field::Keyword ('url', $url, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Keyword ('type', self::FILE, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('local', __ ('File'), 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('content', $content, 'utf-8')); return $doc; } static private function docxToIndex ($obj) { $file = 'file_'. str_pad ($obj->_id, 7, '0', STR_PAD_LEFT); $original = File::getFilePath ($obj->_id); if (!file_exists ($original)) $original = File::getLegacyFilePath ($obj->_id); if (!file_exists ($original)) throw new Exception (__ ('File dont exists [[1]].', $original)); $doc = Zend_Search_Lucene_Document_Docx::loadDocxFile ($original, FALSE); $content = $obj->_name ." \n\n". $obj->_date ." \n\n". $obj->_user_name ." \n\n". $doc->body; $url = 'titan.php?target=openFile&fileId='. $obj->_id; $doc->addField (Zend_Search_Lucene_Field::Keyword ('url', $url, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Keyword ('type', self::FILE, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('local', __ ('File'), 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('content', $content, 'utf-8')); return $doc; } static private function pptxToIndex ($obj) { $file = 'file_'. str_pad ($obj->_id, 7, '0', STR_PAD_LEFT); $original = File::getFilePath ($obj->_id); if (!file_exists ($original)) $original = File::getLegacyFilePath ($obj->_id); if (!file_exists ($original)) throw new Exception (__ ('File dont exists [[1]].', $original)); $doc = Zend_Search_Lucene_Document_Pptx::loadPptxFile ($original, FALSE); $content = $obj->_name ." \n\n". $obj->_date ." \n\n". $obj->_user_name ." \n\n". $doc->body; $url = 'titan.php?target=openFile&fileId='. $obj->_id; $doc->addField (Zend_Search_Lucene_Field::Keyword ('url', $url, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Keyword ('type', self::FILE, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('local', __ ('File'), 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('content', $content, 'utf-8')); return $doc; } static private function xlsxToIndex ($obj) { $file = 'file_'. str_pad ($obj->_id, 7, '0', STR_PAD_LEFT); $original = File::getFilePath ($obj->_id); if (!file_exists ($original)) $original = File::getLegacyFilePath ($obj->_id); if (!file_exists ($original)) throw new Exception (__ ('File dont exists [[1]].', $original)); $doc = Zend_Search_Lucene_Document_Xlsx::loadXlsxFile ($original, FALSE); $content = $obj->_name ." \n\n". $obj->_date ." \n\n". $obj->_user_name ." \n\n". $doc->body; $url = 'titan.php?target=openFile&fileId='. $obj->_id; $doc->addField (Zend_Search_Lucene_Field::Keyword ('url', $url, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Keyword ('type', self::FILE, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('local', __ ('File'), 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('content', $content, 'utf-8')); return $doc; } static private function txtToIndex ($obj) { $file = 'file_'. str_pad ($obj->_id, 7, '0', STR_PAD_LEFT); $original = File::getFilePath ($obj->_id); if (!file_exists ($original)) $original = File::getLegacyFilePath ($obj->_id); if (!file_exists ($original)) throw new Exception (__ ('File dont exists [[1]].', $original)); $content = $obj->_name ." \n\n". $obj->_date ." \n\n". $obj->_user_name ." \n\n". file_get_contents ($original); $url = 'titan.php?target=openFile&fileId='. $obj->_id; $doc = new Zend_Search_Lucene_Document (); $doc->addField (Zend_Search_Lucene_Field::Keyword ('url', $url, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Keyword ('type', self::FILE, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('local', __ ('File'), 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('content', $content, 'utf-8')); return $doc; } static private function docToIndex ($obj) { $file = 'file_'. str_pad ($obj->_id, 7, '0', STR_PAD_LEFT); $original = File::getFilePath ($obj->_id); if (!file_exists ($original)) $original = File::getLegacyFilePath ($obj->_id); if (!file_exists ($original)) throw new Exception (__ ('File dont exists [[1]].', $original)); $path = Instance::singleton ()->getCachePath () .'text/'; if (!file_exists ($path) && !@mkdir ($path, 0777)) throw new Exception (__ ('Impossible to create [[1]].', $path)); if (!file_exists ($path . $file) || !(int) filesize ($path . $file)) @system ('antiword '. $original .' 1> '. $path . $file .' 2> '. $path .'log', $trash); if (!file_exists ($path . $file) || !(int) filesize ($path . $file)) throw new Exception (__ ('Impossible to create [[1]].', $path . $file)); $content = $obj->_name ." \n\n". $obj->_date ." \n\n". $obj->_user_name ." \n\n". file_get_contents ($path . $file); $url = 'titan.php?target=openFile&fileId='. $obj->_id; $doc = new Zend_Search_Lucene_Document (); $doc->addField (Zend_Search_Lucene_Field::Keyword ('url', $url, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Keyword ('type', self::FILE, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('local', __ ('File'), 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('content', $content, 'utf-8')); return $doc; } static private function htmlToIndex ($obj) { $file = 'file_'. str_pad ($obj->_id, 7, '0', STR_PAD_LEFT); $original = File::getFilePath ($obj->_id); if (!file_exists ($original)) $original = File::getLegacyFilePath ($obj->_id); if (!file_exists ($original)) throw new Exception (__ ('File dont exists [[1]].', $original)); $doc = Zend_Search_Lucene_Document_Html::loadHTMLFile ($original, FALSE); $content = $obj->_name ." \n\n". $obj->_date ." \n\n". $obj->_user_name ." \n\n". $doc->body; $url = 'titan.php?target=openFile&fileId='. $obj->_id; $doc->addField (Zend_Search_Lucene_Field::Keyword ('url', $url, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Keyword ('type', self::FILE, 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('local', __ ('File'), 'utf-8')); $doc->addField (Zend_Search_Lucene_Field::Text ('content', $content, 'utf-8')); return $doc; } }