Source for file search-lucene-defs.php

Documentation is available at search-lucene-defs.php

  1. <?php
  2. /* ******************************************************************** */
  3. /* CATALYST PHP Source Code */
  4. /* -------------------------------------------------------------------- */
  5. /* This program is free software; you can redistribute it and/or modify */
  6. /* it under the terms of the GNU General Public License as published by */
  7. /* the Free Software Foundation; either version 2 of the License, or */
  8. /* (at your option) any later version. */
  9. /* */
  10. /* This program is distributed in the hope that it will be useful, */
  11. /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
  12. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
  13. /* GNU General Public License for more details. */
  14. /* */
  15. /* You should have received a copy of the GNU General Public License */
  16. /* along with this program; if not, write to: */
  17. /* The Free Software Foundation, Inc., 59 Temple Place, Suite 330, */
  18. /* Boston, MA 02111-1307 USA */
  19. /* -------------------------------------------------------------------- */
  20. /* */
  21. /* Filename: search-lucene-defs.php */
  22. /* Author: Paul Waite */
  23. /* Description: NB: This module is a variant of the original lucene */
  24. /* module which processed fields line-by-line. This module */
  25. /* implements the XML interface to Lucene. */
  26. /* */
  27. /* Definitions for interfacing to the LUCENE search */
  28. /* engine system. LUCENE is a system which is optimised */
  29. /* for indexing and searching in a generic way. It is */
  30. /* implemented as a server accessible via a port over TCP. */
  31. /* This module understands the protocol that this server */
  32. /* uses to implement indexing and search queries. */
  33. /* */
  34. /* ******************************************************************** */
  35. /** @package search */
  36. include_once("search-defs.php");
  37. /** Stopwatch microtimer */
  38. ("timer-defs.php");
  39. /** XML classes */
  40. ("xml-defs.php");
  41.  
  42. // ----------------------------------------------------------------------
  43. /** Do not wait on socket receive, return immediately */
  44. ("SOCK_NO_WAIT", 0);
  45. /** Wait on socket forever (well, 24hrs is that, more or less) */
  46. ("SOCK_FOREVER", 86400);
  47. /** Times to retry timed-out socket sends/receives */
  48. ("SOCK_RETRIES", 3);
  49. /** Used to indicate that a field should be indexed by Lucene */
  50. ("INDEXED", true);
  51. /** Used to indicate that a field should NOT be indexed by Lucene */
  52. ("NOT_INDEXED", false);
  53. /** Used to indicate that a field should be stored by Lucene */
  54. ("STORED", true);
  55. /** Used to indicate that a field should NOT be stored by Lucene */
  56. ("NOT_STORED", false);
  57. /** The name of the field Lucene should assume if none specified */
  58. ("DEFAULT_FIELD", "Text");
  59. /** Default type of field: 'Text', 'Date', 'Id' */
  60. ("DEFAULT_FIELDTYPE", "Text");
  61. /** Mode of index ID generation is by incrementing integer */
  62. ("ID_FROM_INC", 0);
  63. /** Mode of index ID generation is by filename stripped of path and extension */
  64. ("ID_FROM_NAME", 1);
  65. /** Mode of index ID generation is by full filename (incl. extension) */
  66. ("ID_FROM_FILENAME", 2);
  67. /** Mode of index ID generation is by full path to file */
  68. ("ID_FROM_PATH", 3);
  69. /** Indicates index fields come from meta tag extraction */
  70. ("META_TAG_FIELDS", true);
  71.  
  72. // ----------------------------------------------------------------------
  73. /**
  74. * The SearchEngine connection class
  75. * This class inherits the functionality of the 'search' class since mostly
  76. * that is what we will be connecting to SearchEngine for. The Indexing and
  77. * Control descendants can just ignore this inherited basic searching
  78. * functionality.
  79. * This class knows how to connect to a SearchEngine server and send and
  80. * receive messages to/from it. Child classes which need to talk to this
  81. * server to do indexing or querying should inherit this class.
  82. * @package search
  83. */
  84. class searchengine_connection extends search {
  85. // Public
  86. /** HOST running the SearchEngine query server */
  87.  
  88. var $host = "";
  89. /** PORT that the server is listening on */
  90.  
  91. var $port = "";
  92. /** Timeout for send in seconds */
  93.  
  94. var $timeoutsecs = 10;
  95.  
  96. // Private
  97. /** Whether SearchEngine is enabled..
  98. @access private */
  99. var $enabled = true;
  100. /** The message waiting to be sent
  101. @access private */
  102. var $message = "";
  103. /** Raw response content we receive back from the SearchEngine server
  104. @access private */
  105. var $responsebuf = "";
  106. /** Socket file pointer
  107. @access private */
  108. var $sockfp = false;
  109. /** True if we are connected to socket
  110. @access private */
  111. var $connected = false;
  112. /** An execution timer
  113. @access private */
  114. var $timer;
  115. // .....................................................................
  116. /** Constructor - SearchEngine connection. Normally this will just be
  117. * called with no host/port, and the object is just initialised ready for
  118. * the call to send(). If called with host/port, then the connection is
  119. * fired up immediately.
  120. * @param string $host Hostname or IP of SearchEngine server
  121. * @param string $port Port of SearchEngine server
  122. * @param integer $timeoutsecs Seconds to timeout the connection
  123. */
  124. function searchengine_connection($host="", $port="", $timeoutsecs="") {
  125. if ($host != "" && $port != "") {
  126. $this->connect($host, $port, $timeoutsecs);
  127. }
  128. $this->timer = new microtimer();
  129. } // searchengine_connection
  130. // .....................................................................
  131. /**
  132. * Sets the search engine host and port for the connection
  133. * @param string $host Hostname or IP of SearchEngine server
  134. * @param string $port Port of SearchEngine server
  135. */
  136. function set_host_and_port($host, $port) {
  137. $this->host = $host;
  138. $this->port = $port;
  139. } // set_host_and_port
  140. // .....................................................................
  141. /**
  142. * Connect to the SearchEngine server. Optionally over-ride various settings
  143. * which were set in the constructor. Normally this method is only
  144. * called internally, in response to a request to send a message to
  145. * the SearchEngineserver.
  146. * @access private
  147. * @param string $host Hostname or IP of SearchEngine server
  148. * @param string $port Port of SearchEngine server
  149. * @param integer $timeoutsecs Seconds to timeout the connection
  150. */
  151. function connect($host="", $port="", $timeoutsecs="") {
  152. // Override host and port if given..
  153. if ($host != "") $this->host = $host;
  154. if ($port != "") $this->port = $port;
  155. // If host and port not defined, try config..
  156. if ($this->host == "") {
  157. if (class_exists("configuration")) {
  158. $config = new configuration("sys_control");
  159. if ($config->field_exists("Search Engine Host")) {
  160. $this->host = $config->value("Search Engine Host");
  161. $this->port = $config->value("Search Engine Port");
  162. }
  163. debugbr("acquired Axyl config: host [$this->host] port [$this->port]", DBG_DUMP);
  164. }
  165. }
  166. // Try to open socket if we have a host..
  167. $this->connected = false;
  168. if ($this->enabled && $this->host != "") {
  169. $this->sockfp = fsockopen($this->host, $this->port);
  170. if(!$this->sockfp) {
  171. $this->log_error("failed to connect to '$this->host:$this->port'");
  172. }
  173. else {
  174. if ($timeoutsecs != "") $this->timeoutsecs = $timeoutsecs;
  175. $this->set_timeout($this->timeoutsecs);
  176. $this->connected = true;
  177. debugbr("searchengine_connection: connected to '$this->host:$this->port'", DBG_DUMP);
  178. }
  179. }
  180. // Return result..
  181. return $this->connected;
  182. } // connect
  183. // .....................................................................
  184. /**
  185. * Disconnect from the SearchEngine server. Normally this is used only by
  186. * internal SearchEngineserver methods.
  187. * @access private
  188. */
  189. function disconnect() {
  190. if ($this->connected) {
  191. fclose($this->sockfp);
  192. $this->sockfp = false;
  193. $this->connected = false;
  194. }
  195. } // disconnect
  196. // .....................................................................
  197. /**
  198. * Set the socket timeout. Deals with the special case of setting
  199. * the socket to non-blocking mode (zero timeout)..
  200. * @param integer $timeoutsecs Set the timeout in seconds
  201. */
  202. function set_timeout($timeoutsecs) {
  203. if ($this->connected && $timeoutsecs != "") {
  204. $this->timeoutsecs = $timeoutsecs;
  205. if ($this->timeoutsecs != SOCK_NO_WAIT) {
  206. socket_set_timeout( $this->sockfp, $this->timeoutsecs);
  207. }
  208. socket_set_blocking( $this->sockfp, (($this->timeoutsecs == SOCK_NO_WAIT) ? false : true) );
  209. }
  210. } // set_timeout
  211. // .....................................................................
  212. /**
  213. * Sends a message to the SearchEngine server, and receives the response. We
  214. * operate on the understanding that every time we send something to
  215. * SearchEngine we expect a response. Since this method already calls the
  216. * recieve() method, there is no need to call it from your application.
  217. * The content to be sent is expected to be already in the class
  218. * string variable $message. The response is put into $response which
  219. * is an array of LF-delimited lines sent back.
  220. * @param integer $timeoutsecs Override for timeout in seconds
  221. * @return boolean True if the message was sent ok
  222. */
  223. function send($timeoutsecs="") {
  224. $send_ok = true;
  225. if (!$this->connected) {
  226. $this->connect();
  227. }
  228. if ($this->connected) {
  229. // Check for timeout over-ride..
  230. if ($timeoutsecs != "") $this->timeoutsecs = $timeoutsecs;
  231. $this->set_timeout($this->timeoutsecs);
  232. // Send message..
  233. if ($this->message != "") {
  234. $this->timer->restart();
  235. $bytesput = fputs($this->sockfp, $this->message);
  236. $this->timer->stop();
  237. if (debugging()) {
  238. $buf = trim(substr(rawurldecode($this->message),0, 5000));
  239. debugbr("<pre>" . xmldump($buf) . "</pre>", DBG_DUMP);
  240. debugbr("searchengine_connection: send transaction took "
  241. . $this->timer->formatted_millisecs() . "mS",
  242. DBG_DUMP
  243. );
  244. }
  245. if ($bytesput != -1) {
  246. debugbr("searchengine_connection: send ok ($bytesput bytes)", DBG_DUMP);
  247. for ($i=0; $i< SOCK_RETRIES; $i++) {
  248. $send_ok = $this->receive();
  249. if ($send_ok) break;
  250. debugbr("searchengine_connection: receive retry #" . ($i + 1), DBG_DUMP);
  251. }
  252. }
  253. else {
  254. $this->log_error("write to server failed");
  255. $send_ok = false;
  256. }
  257. }
  258. else {
  259. $this->log_error("trying to send null content");
  260. $send_ok = false;
  261. }
  262. }
  263. else {
  264. $this->log_error("send with no open socket to host [$this->host] port [$this->port]");
  265. $send_ok = false;
  266. }
  267. // Return status..
  268. return $send_ok;
  269. } // send
  270. // .....................................................................
  271. /**
  272. * Receive a message from the SearchEngine server. We can specify a timeout
  273. * period in seconds. If set to SOCK_NO_WAIT, it will return immediately with or
  274. * without a message. This is a low-level routine which deals with receiving the
  275. * message over TCP sockets.
  276. * @return boolean True if the message was received loud and clear
  277. * @access private
  278. */
  279. function receive() {
  280. $received_ok = true;
  281. if ($this->connected) {
  282. $this->timer->restart();
  283. $this->responsebuf = "";
  284. while (!feof($this->sockfp)) {
  285. $buf = fread($this->sockfp, 10000);
  286. if ($buf !== false) {
  287. $this->responsebuf .= $buf;
  288. }
  289. else {
  290. $this->log_error("no response from server");
  291. $received_ok = false;
  292. break;
  293. }
  294. }
  295. $this->timer->stop();
  296. if (debugging()) {
  297. debugbr("<pre>" . xmldump($this->responsebuf) . "</pre>", DBG_DUMP);
  298. debugbr("searchengine_connection: response from server took "
  299. . $this->timer->formatted_millisecs() . "mS",
  300. DBG_DUMP
  301. );
  302. }
  303. }
  304. else {
  305. $this->log_error("receive with no open socket");
  306. $received_ok = false;
  307. }
  308. // Return status..
  309. return $received_ok;
  310. } // receive
  311. // .....................................................................
  312. /** Log a message to the syslog and print info to debugger.
  313. * @access private
  314. */
  315. function log_error($err) {
  316. $prefix = (defined("APP_NAME") ? APP_NAME . ": " : "");
  317. $err = "SearchEngine error: " . get_class($this) . ": $this->host:$this->port: $err";
  318. debugbr($err);
  319. error_log($prefix . $err, 0);
  320. } // log_error
  321.  
  322. } // searchengine_connection class
  323. // ----------------------------------------------------------------------
  324.  
  325. /** The SearchEngine fieldset class. This holds the SearchEngine fields for a SearchEngine
  326. * message. These fields comprise the list of tags which make up
  327. * a query message or an index message.
  328. * @access private
  329. * @package search
  330. */
  331. class searchengine_fieldset {
  332. /** Fields stored as an array of XML <Field> tags */
  333.  
  334. var $xmltags = array();
  335. // .....................................................................
  336. /** Constructor */
  337.  
  338. function searchengine_fieldset() { }
  339. // .....................................................................
  340. /**
  341. * Return a copy of the named field object from fieldset by name.
  342. * NOTES: This function will return a new field if it does not already
  343. * exist. In this case the field will not be stored until you use the
  344. * put() method to do so. Always returns a field object.
  345. * @param string $fieldname The name of the field to get
  346. * @return object An xmltag object for the field
  347. */
  348. function get_field($fieldname) {
  349. if (isset($this->xmltags[$fieldname])) {
  350. $field = $this->xmltags[$fieldname];
  351. }
  352. else {
  353. $field = new xmltag("Field");
  354. $field->setattribute("name", $fieldname);
  355. }
  356. return $field;
  357. } // get_field
  358. // .....................................................................
  359. /**
  360. * Puts the named field into fieldset, indexed by fieldname.
  361. * @param string $fieldname Unique name of the field in the set
  362. * @param object $field The field object to store
  363. */
  364. function put_field($fieldname, $field) {
  365. $this->xmltags[$fieldname] = $field;
  366. } // put_field
  367. // .....................................................................
  368. /** Define a field in the fieldset. Set the definition for a field
  369. * in this fieldset. If the field does not exist it is created and
  370. * its definition set. If it exists the definition is updated.
  371. * @param string $fieldname Name of the field
  372. * @param string $type Type of this field eg. "Date"
  373. * @param boolean $stored Whether field value should be stored by SearchEngine
  374. * @param boolean $indexed Whether field value should be indexed by SearchEngine
  375. */
  376. function define_field($fieldname, $type, $stored=STORED, $indexed=INDEXED) {
  377. $field = $this->get_field($fieldname);
  378. $field->setattribute("type", $type);
  379. $field->setattribute("stored", ($stored ? "true" : "false"));
  380. $field->setattribute("indexed", ($indexed ? "true" : "false"));
  381. $this->put_field($fieldname, $field);
  382. } // define_field
  383. // .....................................................................
  384. /** Add a field to the fieldset.
  385. * @param string $fieldname Name of the field
  386. * @param string $fieldvalue Value to associate with this field
  387. */
  388. function add_field($fieldname, $fieldvalue="") {
  389. $field = $this->get_field($fieldname);
  390. $field->value = $fieldvalue;
  391. $this->put_field($fieldname, $field);
  392. } // add_field
  393. // .....................................................................
  394. /** Clear all fields from the fieldset */
  395.  
  396. function clear() {
  397. $this->xmltags = array();
  398. } // clear
  399. // .....................................................................
  400. function render() {
  401. $s = "";
  402. foreach ($this->xmltags as $field) {
  403. $s .= $field->render();
  404. }
  405. return $s;
  406. } // render
  407.  
  408. } // searchengine_fieldset class
  409. // ----------------------------------------------------------------------
  410.  
  411. /**
  412. * The SearchEngine msg class. This is a raw class which holds the basic
  413. * message fields and data and knows how to build them into a full
  414. * message for sending to the SearchEngine server.
  415. * @package search
  416. */
  417. class searchengine_msg extends searchengine_connection {
  418. // Public
  419. /** Type/name of this message */
  420.  
  421. var $type = "";
  422.  
  423. // Private
  424. /** Array containing XML tags
  425. @access private */
  426. var $xmltags = array();
  427. /** Object containing SearchEngine fields
  428. @access private */
  429. var $fieldset;
  430. /** True if message has been built
  431. @access private */
  432. var $built = false;
  433. /** Error message if any error occurred
  434. @access private */
  435. var $error_msg = "";
  436. // .....................................................................
  437. /** Constructor
  438. * Notes: The application is either specified in the formal paramters or it
  439. * can be determined for an Axyl application by using the APP_PREFIX which
  440. * is unique to the application. This is the recommended option. Other
  441. * developers have, however, also used the configvalue 'SearchEngine Application'
  442. * for some reason, so this is still supported here. If none of these
  443. * methods results in a valid identifier, 'default' is used.
  444. * @param string $type Type of message this is, eg; QUERY, INDEX..
  445. * @param string $application The application name. Sets default SearchEngine config.
  446. * @param string $host Hostname or IP of SearchEngine server
  447. * @param string $port Port of SearchEngine server
  448. */
  449. function searchengine_msg($type="", $application="?", $host="", $port="") {
  450. $this->searchengine_connection($host, $port);
  451. $this->type = $type;
  452. $this->fieldset = new searchengine_fieldset();
  453. // We must have an application..
  454. if ($application == "?") {
  455. // Axyl configuration value is not be defined so the
  456. // APP_PREFIX could be used in this case..
  457. if ( defined("APP_PREFIX")) {
  458. $application = APP_PREFIX;
  459. }
  460. // If still not defined, try config..
  461. if ($application == "" || $application == "?") {
  462. if (class_exists("configuration")) {
  463. $config = new configuration("sys_control");
  464. $application = $config->value("Search Engine Application");
  465. }
  466. else {
  467. // The default case for standalone apps..
  468. $application = "default";
  469. }
  470. }
  471. }
  472. // Set the application..
  473. $this->set_application($application);
  474. } // searchengine_msg
  475. // .....................................................................
  476. /**
  477. * Add a new XML tag object to this SearchEngine message. We usually just
  478. * append the tag to an array of tags, which is produced for the message,
  479. * however the $mode option allows us to replace an existing tag
  480. * previously added, by tag name. Eg. this could be used to re-assign the
  481. * 'application' tag, since there should only ever be one of those. This
  482. * mode will only ever replace the first occurence, not multiple.
  483. * @param object $tag The xmltag object to add to our SearchEngine msg
  484. * @param string $mode If "replace": replace existing, "append": append tag
  485. */
  486. function add_xmltag($tag, $mode="append") {
  487. switch ($mode) {
  488. case "append":
  489. $this->xmltags[] = $tag;
  490. $this->built = false;
  491. break;
  492. case "replace":
  493. $new_xmltags = array();
  494. $replaced = false;
  495. foreach ($this->xmltags as $xmltag) {
  496. if (!$replaced && $xmltag->tagname == $tag->tagname) {
  497. $new_xmltags[] = $tag;
  498. $replaced = true;
  499. }
  500. else {
  501. $new_xmltags[] = $xmltag;
  502. }
  503. } // foreach
  504. if (!$replaced) {
  505. $new_xmltags[] = $tag;
  506. }
  507. // Install new set of tags..
  508. $this->xmltags = $new_xmltags;
  509. $this->built = false;
  510. break;
  511. } // switch
  512. } // add_xmltag
  513. // .....................................................................
  514. /**
  515. * Specify the application. The application is the name of a configuration
  516. * set which has been specified either by a control message, or by using
  517. * configuration files on the server. A given configuration set identified
  518. * by an application name can have specific fields already defined, such
  519. * as Sort: or Domain: etc.
  520. * Notes: The 'Application' header can only appear once in the message.
  521. * To this end we call 'add_xmltag' in "replace" mode, so this method can
  522. * in fact be called multiple times, and only one application tag will
  523. * be present in the final message.
  524. * @param string $application The application name to set.
  525. */
  526. function set_application($application) {
  527. $this->add_xmltag( new xmltag("Application", $application), "replace" );
  528. } // set_application
  529. // .....................................................................
  530. /**
  531. * Specify a domain. A domain is an identifier which groups indexed
  532. * objects internally to SearchEngine. This allows searches on multiple
  533. * archives of documents in a single SearchEngine installation.
  534. * Notes: There may be zero or more domain headers in the message. If it
  535. * does not appear, then any domain header defined for the application
  536. * will be applied on its own. Otherwise any definitions added by this
  537. * method are OR'd with any specified in the application config.
  538. * NB: If no domains are specified anywhere, any searching will be done
  539. * across all domains (which would probably yield very confusing return
  540. * data!).
  541. * @param string $domain The domain to set.
  542. */
  543. function set_domain($domain) {
  544. $this->add_xmltag( new xmltag("Domain", $domain) );
  545. } // set_domain
  546. // .....................................................................
  547. /** Add a field to the fieldset.
  548. * @param string $fieldname Name of the field
  549. * @param string $fieldvalue Value to associate with this field
  550. */
  551. function add_field($fieldname, $fieldvalue="") {
  552. $this->fieldset->add_field($fieldname, $fieldvalue);
  553. $this->built = false;
  554. } // add_field
  555. // .....................................................................
  556. /** Clear all data/fields, leaving type definition alone. */
  557.  
  558. function clear() {
  559. $this->fieldset->clear();
  560. $this->message = "";
  561. $this->built = false;
  562. } // clear
  563. // .....................................................................
  564. /**
  565. * Builds the message according to the message type. This method
  566. * may be over-ridden in children inheriting this class
  567. * @access private
  568. */
  569. function build() {
  570. if (!$this->built) {
  571. if ($this->type != "") {
  572. $xml = new xmltag($this->type);
  573. // XML TAGS
  574. foreach ($this->xmltags as $tag) {
  575. $xml->childtag($tag);
  576. }
  577. // FIELDS
  578. if (count($this->fieldset->xmltags) > 0) {
  579. $fields = new xmltag("Fields");
  580. foreach ($this->fieldset->xmltags as $field) {
  581. $fields->childtag($field);
  582. }
  583. $xml->childtag($fields);
  584. }
  585. $this->message = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" . $xml->render();
  586. $this->built = true;
  587. }
  588. }
  589. return $this->built;
  590. } // build
  591. // .....................................................................
  592. /**
  593. * Sends the current message to SearchEngine, and checks for protocol
  594. * errors in the received response.
  595. * @param integer $timeoutsecs Override for timeout in seconds
  596. * @return boolean True if the send operation was a success
  597. */
  598. function send($timeoutsecs="") {
  599. $success = false;
  600. if ($this->build()) {
  601. // Low-level socket send-receive transaction..
  602. $success = searchengine_connection::send($timeoutsecs);
  603. $this->disconnect();
  604. }
  605. return $success;
  606. } // send
  607.  
  608. } // searchengine_msg class
  609. // ----------------------------------------------------------------------
  610.  
  611. /**
  612. * The SearchEngine message class. This class extends its parent class
  613. * searchengine_msg and adds some higher level methods for adding groups of
  614. * fields to the message.
  615. * @package search
  616. */
  617. class searchengine_message extends searchengine_msg {
  618. /** Response object which will parse XML content
  619. @access private */
  620. var $response;
  621. // .....................................................................
  622. /** Constructor
  623. * This is a more complex class which builds on the basic searchengine_msg
  624. * class to provide some higher level methods for adding fields in
  625. * specific ways to support CONTROL, QUERY and INDEX message types.
  626. * @param string $type Type of message this is, eg; QUERY, INDEX..
  627. * @param string $application The application name. Sets default SearchEngine config.
  628. * @param string $host Hostname or IP of SearchEngine server
  629. * @param string $port Port of SearchEngine server
  630. */
  631. function searchengine_message($type="", $application="?", $host="", $port="") {
  632. $this->searchengine_msg($type, $application, $host, $port);
  633. } // searchengine_message
  634. // .....................................................................
  635. /**
  636. * Strip field type specifiers out of field strings. A field string with
  637. * a type specifier in it is of the form: 'Foo:Date', where the field
  638. * name is 'Foo' and the field type is 'Date'. Possible field types are
  639. * 'Id', 'Text' (the default), and 'Date'.
  640. * Note that sort field specification is a special case, where the syntax
  641. * can be 'Foo:Date:Desc' or 'Foo:Desc' indicating the sort on the given
  642. * field should be done in descending order.
  643. * At present you would only use this facility with a 'Date' field, and
  644. * everything else would then default to 'Text'. [The 'Id' type being a
  645. * special one]
  646. * We return the field stripped of any type, and if a type was present
  647. * we issue the define_field() directive to define it. A field so-defined
  648. * will always be both stored by SearchEngine and indexed.
  649. * @param string $field Field in 'Foo:Date' format, or just 'Foo' for default type
  650. * @return string The fieldname stripped of any type specifier
  651. * @access private
  652. */
  653. function strip_field_type($field) {
  654. $fieldname = $field;
  655. $retfieldname = $field;
  656. if (strstr($field, ":")) {
  657. // Extract field specifier parts..
  658. $bits = explode(":", $field);
  659. $fieldname = trim( array_shift($bits) );
  660. if (strtolower($fieldname) == "rank") {
  661. $fieldname = "RANK";
  662. }
  663. $retfieldname = $fieldname;
  664. $f1 = trim(array_shift($bits));
  665. $f2 = trim(array_shift($bits));
  666. // Check for a sort field with DESC specifier..
  667. if ($f1 == "Desc" || $f2 == "Desc") {
  668. $retfieldname .= ":Desc";
  669. }
  670. // Check for valid field type specifier..
  671. if ($f1 == "Date" || $f1 == "Text" || $f1 == "Id") {
  672. // Define field by name..
  673. $this->define_field($fieldname, $f1);
  674. }
  675. }
  676. // Return fieldname plus any sort spec..
  677. return $retfieldname;
  678. } // strip_field_type
  679. // .....................................................................
  680. /**
  681. * Define a field. We supply the name of the field, it's type (Text, Date
  682. * or Id), and whether it should be stored by SearchEngine for later retreival
  683. * in queries. For example you would not store the raw document/content as
  684. * this is usually stored elsewhere.
  685. * We also cater for fields which might not need to be indexed. These would
  686. * be fields of data you just want to return with the document, if found in
  687. * a query, but not search on. An example might be a field containing the
  688. * path to the physical document on disk. For these fields you would then
  689. * specify NOT_INDEXED for the $indexed parameter. These fields MUST be
  690. * stored, so we make the rule: if the field is NOT_INDEXED then it must
  691. * be STORED (this will be forced).
  692. * In the normal course of events, fields will be defined to be both stored
  693. * and indexed. The exception is the special "Text" field associated with
  694. * an item "Body", which is indexed, but never stored.
  695. * This method adds the field settings directly via the add_field() method.
  696. * @see add_field()
  697. * @param string $fieldname Name of the field to index
  698. * @param string $type Type of field data: Text, Date or Id.
  699. * @param boolean $stored If true then SearchEngine will store the content itself
  700. * @param boolean $indexed If true then SearchEngine will index the field content
  701. */
  702. function define_field($fieldname, $type, $stored=STORED, $indexed=INDEXED) {
  703. // Force non-indexed fields to be stored..
  704. if ($indexed == NOT_INDEXED) {
  705. $stored = STORED;
  706. }
  707. $this->fieldset->define_field($fieldname, $type, $stored, $indexed);
  708. } // define_field
  709. // .....................................................................
  710. /**
  711. * Specify the fields you want returned from SearchEngine.
  712. * Fields should be in a comma-separated list of field names. Each field
  713. * name can have the field type included in the form 'Foo:Date', where
  714. * 'Date' is the type in this instance. In fact, since 'Text' is the
  715. * default filed type, 'Date' is probably the only one you need to use
  716. * as the current implementation stands.
  717. * This method adds the field setting directly via the add_field() method.
  718. * @see add_field
  719. * @param mixed $fields Comma-delimited fieldname list, or array of fields
  720. */
  721. function set_returnfields($fields) {
  722. if (!is_array($fields)) {
  723. $flds = explode(",", $fields);
  724. }
  725. else {
  726. $flds = $fields;
  727. }
  728. $returnfields = array();
  729. foreach ($flds as $field) {
  730. $returnfields[] = $this->strip_field_type($field);
  731. }
  732. $returnlist = implode(" ", $returnfields);
  733. $this->add_xmltag( new xmltag("Return", $returnlist) );
  734. } // set_returnfields
  735. // .....................................................................
  736. /**
  737. * Specify query limit field. This sets the maximum number of results
  738. * that SearchEngine should return.
  739. * @param integer $limit Maximum number of results (hits) to return
  740. */
  741. function set_limit($limit) {
  742. $this->add_xmltag( new xmltag("Limit", $limit) );
  743. } // set_limit
  744. // .....................................................................
  745. /**
  746. * Specify query offset field 'First'. This sets the offset for the
  747. * returned results. For example, if this was set to 3, and SearchEngine
  748. * found 20 hits, then results would be sent back from the 3rd hit
  749. * onwards.
  750. * @param integer $first Offset in result set to start from
  751. */
  752. function set_first($first) {
  753. $this->add_xmltag( new xmltag("First", $first) );
  754. } // set_first
  755. // .....................................................................
  756. /**
  757. * Specify the fields you want query results to be ordered by.
  758. * Fields should be in a comma-separated list of field names. Each field
  759. * name can have the field type included in the form 'Foo:Date', where
  760. * 'Date' is the type in this instance. In fact, since 'Text' is the
  761. * default filed type, 'Date' is probably the only one you need to use
  762. * as the current implementation stands.
  763. * Note that sort field specification is a special case, where the syntax
  764. * can be 'Foo:Date:Desc' or 'Foo:Desc' indicating the sort on the given
  765. * field should be done in descending order.
  766. * @param mixed $fields Comma-delimited fieldname list, or array of fields
  767. */
  768. function set_sortorder($fields) {
  769. if (!is_array($fields)) {
  770. $flds = explode(",", $fields);
  771. }
  772. else {
  773. $flds = $fields;
  774. }
  775. $sortfields = array();
  776. foreach ($flds as $field) {
  777. $sortfields[] = $this->strip_field_type($field);
  778. }
  779. // Create the field..
  780. $sortlist = implode(" ", $sortfields);
  781. $this->add_xmltag( new xmltag("Sort", $sortlist) );
  782. } // set_sortorder
  783. // .....................................................................
  784. /**
  785. * Specify a range on a field for querying. We specify the name of a field
  786. * which is used to select articles within the given limits, and
  787. * the limits themeselves. Either limit may be passed as nullstring
  788. * which indicates no limit on that side. Any dates must be passed as
  789. * standard Unix timestamps (seconds since 1970).
  790. * Notes: This method can be called multiple times to define additional
  791. * ranges for different field names.
  792. * This method adds the field setting directly via the add_field() method.
  793. * @see add_field
  794. * @param string $range_from Value of lowerbound range
  795. * @param string $range_to Value of upperbound range
  796. * @param string $range_fieldname Name of field to use in range query.
  797. */
  798. function set_range($range_from="", $range_to="", $range_fieldname="") {
  799. if ($range_fieldname != "") {
  800. $range = new xmltag("Range");
  801. $range->setattribute("field", $this->strip_field_type($range_fieldname));
  802. if ($range_from != "" && $range_from != false) {
  803. $range->childtag( new xmltag("From", $range_from) );
  804. }
  805. if ($range_to != "" && $range_to != false) {
  806. $range->childtag( new xmltag("To", $range_to) );
  807. }
  808. $this->add_xmltag( $range );
  809. }
  810. } // set_range
  811. // .....................................................................
  812. /**
  813. * Supply a stopword list to SearchEngine.
  814. * This method adds the field setting directly via the add_field() method.
  815. * @see add_field
  816. * @param mixed $stopwords Space-delimited list, or array of stopwords
  817. */
  818. function set_stopwords($stopwords) {
  819. if (is_array($stopwords)) {
  820. $mystops = implode(" ", $stopwords);
  821. }
  822. else {
  823. $mystops = $stopwords;
  824. }
  825. $this->add_xmltag( new xmltag("Stop-List", $mystops) );
  826. } // set_stopwords
  827.  
  828. } // searchengine_message class
  829. // ----------------------------------------------------------------------
  830.  
  831. /**
  832. * Encapsulation of the result of a generic search query. This is for
  833. * internal use only.
  834. * @package search
  835. * @access private
  836. */
  837. class queryresult {
  838. var $rank = "";
  839. var $fields = array();
  840.  
  841. function queryresult($rank="") {
  842. $this->rank = $rank;
  843. }
  844. function addfield($fieldname, $fieldvalue) {
  845. $this->fields[$fieldname] = $fieldvalue;
  846. }
  847. } // queryresult class
  848. // ----------------------------------------------------------------------
  849.  
  850. /**
  851. * Class comprising the functionality of a SearchEngine response parser. This
  852. * is for internal use only.
  853. * @package search
  854. * @access private
  855. */
  856. class response_parser extends xmlparser {
  857. /** Current/last tag opened */
  858.  
  859. var $tag = "";
  860. /** Attributes array for current/last tag */
  861.  
  862. var $attr = array();
  863. /** Serial transaction ID */
  864.  
  865. var $serial = "";
  866. /** Status message */
  867.  
  868. var $status_message = "";
  869. /** True if response was valid, ie. no errors */
  870.  
  871. var $valid = true;
  872. /** All cdata content for the response */
  873.  
  874. var $tag_data = array();
  875. // .....................................................................
  876. /** Construct a new parser. */
  877.  
  878. function response_parser() {
  879. $this->xmlparser();
  880. } // response_parser
  881. // .....................................................................
  882. /** Method invoked when a tag is opened */
  883.  
  884. function tag_open($parser, $tag, $attributes) {
  885. $this->tag = $tag;
  886. if (is_array($attributes) && count($attributes) > 0) {
  887. foreach ($attributes as $key => $value ) {
  888. $this->attr[$key] = $value;
  889. }
  890. }
  891. switch ($tag) {
  892. case "Error":
  893. $this->valid = false;
  894. break;
  895. } // switch
  896. } // tag_open
  897. // .....................................................................
  898. /**
  899. * Method invoked when character data is available. This is essentially
  900. * a field of data, with the name of the field being the tag-name, and
  901. * the value being the cdata itself. Here we cherry-pick a few 'special'
  902. * values and assign to class vars for easier access. The character
  903. * data is all stashed in the 'tag_data' array under the name of the tag
  904. * as well, so no fields are lost.
  905. */
  906. function cdata($parser, $cdata) {
  907. switch ($this->tag) {
  908. case "Error":
  909. $this->error_message = $cdata;
  910. debugbr("SearchEngine error: $this->error_message", DBG_DUMP);
  911. break;
  912. case "Status":
  913. $this->status_message = $cdata;
  914. debugbr("SearchEngine status: $this->status_message", DBG_DUMP);
  915. break;
  916. case "Serial":
  917. $this->serial = $cdata;
  918. debugbr("SearchEngine serial#: $this->serial", DBG_DUMP);
  919. break;
  920. } // switch
  921. // Record all tag data. Note that attributes, if any, are
  922. // not recorded at this point..
  923. $this->tag_data[$this->tag] = $cdata;
  924. } // cdata
  925. // .....................................................................
  926. /** Method invoked when a tag is closed */
  927.  
  928. function tag_close($parser, $tag) {
  929. $this->tag = "";
  930. $this->attr = array();
  931. } // tag_close
  932. // .....................................................................
  933. function parse($xml) {
  934. xmlparser::parse($xml);
  935. if (!$this->valid_xml) {
  936. $this->valid = false;
  937. }
  938. if ($this->error_message != "") {
  939. log_sys($this->error_message);
  940. }
  941. } // parse
  942.  
  943. } // response_parser class
  944. // ----------------------------------------------------------------------
  945.  
  946. /**
  947. * Class comprising the functionality of an XML parser for queries. This
  948. * is for internal use only.
  949. * @package search
  950. * @access private
  951. */
  952. class queryresponse_parser extends response_parser {
  953. /** Results returned count */
  954.  
  955. var $count = 0;
  956. var $results;
  957. var $results_stream = false;
  958. // .....................................................................
  959. /** Construct a new parser. */
  960.  
  961. function queryresponse_parser() {
  962. $this->response_parser();
  963. } // queryresponse_parser
  964. // .....................................................................
  965. /** Method invoked when a tag is opened */
  966.  
  967. function tag_open($parser, $tag, $attributes) {
  968. response_parser::tag_open($parser, $tag, $attributes);
  969. switch ($tag) {
  970. case "Results":
  971. $this->results_stream = true;
  972. break;
  973. case "Result":
  974. $this->addresult(
  975. $this->attr["counter"],
  976. $this->attr["rank"]
  977. );
  978. $this->attr = array();
  979. break;
  980. } // switch
  981. } // tag_open
  982. // .....................................................................
  983. /** Method invoked when character data is available */
  984.  
  985. function cdata($parser, $cdata) {
  986. response_parser::cdata($parser, $cdata);
  987. switch ($this->tag) {
  988. case "Count":
  989. $this->count = $cdata;
  990. break;
  991. case "Field":
  992. if ($this->results_stream) {
  993. if (count($this->attr) > 0) {
  994. $result = array_pop($this->results);
  995. $fieldname = $this->attr["name"];
  996. $fieldval = $cdata;
  997. $result->addfield($fieldname, $fieldval);
  998. array_push($this->results, $result);
  999. }
  1000. $this->attr = array();
  1001. }
  1002. break;
  1003. } // switch
  1004. } // cdata
  1005. // .....................................................................
  1006. /** Method invoked when a tag is closed */
  1007.  
  1008. function tag_close($parser, $tag) {
  1009. response_parser::tag_close($parser, $tag);
  1010. switch ($tag) {
  1011. case "Results":
  1012. $this->results_stream = false;
  1013. break;
  1014. } // switch
  1015. } // tag_close
  1016. // .....................................................................
  1017. /** Add a result field to the response */
  1018.  
  1019. function addresult($id, $rank) {
  1020. $this->results[$id] = new queryresult($rank);
  1021. } // addresult
  1022.  
  1023. } // queryresponse_parser class
  1024. // ----------------------------------------------------------------------
  1025.  
  1026. /**
  1027. * The SearchEngine query message class. This class inherits all the functionality
  1028. * of the searchengine_connection, searchengine_msg and searchengine_message classes. It adds
  1029. * query-specific methods for searching.
  1030. * @package search
  1031. */
  1032. class searchengine_querymsg extends searchengine_message {
  1033. /** Set to true if sort limit was exceeded in query */
  1034.  
  1035. var $sort_limit_exceeded = false;
  1036. /** Set to true if SearchEngine blew its memory trying to sort */
  1037.  
  1038. var $sort_memory_exceeded = false;
  1039. // .....................................................................
  1040. /** Constructor
  1041. * Make a new SearchEngine query message. You can specify the application to
  1042. * use here, and also an optional query string to send.
  1043. * @param string $application Optional application specifier.
  1044. * @param string $host Hostname or IP of SearchEngine server
  1045. * @param string $port Port of SearchEngine server
  1046. */
  1047. function searchengine_querymsg($application="?", $host="", $port="") {
  1048. $this->searchengine_message("LuceneQueryRequest", $application, $host, $port);
  1049. } // searchengine_querymsg
  1050. // .....................................................................
  1051. /**
  1052. * Set the query for this message. There can be only one query defined.
  1053. * This method can be called repeatedly, and each time it is called the
  1054. * new value will replace the old one.
  1055. * @param string $query The query to submit to SearchEngine.
  1056. */
  1057. function set_query($query) {
  1058. $queryxml = new xmltag("Query", $query);
  1059. $queryxml->setattribute("default-field", DEFAULT_FIELD);
  1060. $this->add_xmltag($queryxml);
  1061. } // set_query
  1062. // .....................................................................
  1063. /**
  1064. * Send the message to SearchEngine, and then post-process the response for
  1065. * query hits. The hitcount is extracted, followed by the hits, which
  1066. * may comprise multiple fields. A hit is thus defined as an array of
  1067. * fields, and each hit is put into a single container array called
  1068. * 'hit', which is a property of the parent class 'search'.
  1069. * @param integer $timeoutsecs Override for timeout in seconds
  1070. */
  1071. function send($timeoutsecs="") {
  1072. // Initialise flags..
  1073. $this->sort_limit_exceeded = false;
  1074. $this->sort_memory_exceeded = false;
  1075.  
  1076. // Msg-level send-receive transaction..
  1077. searchengine_message::send($timeoutsecs);
  1078.  
  1079. // Process the response to our request..
  1080. $this->response = new queryresponse_parser();
  1081. $this->response->parse($this->responsebuf);
  1082.  
  1083. // Unpack the response if no errors..
  1084. if ($this->response->valid) {
  1085. // Here we will unpack the returned search query hits
  1086. // and store them locally for use by child classes.
  1087. if (isset($this->response->results)) {
  1088. foreach ($this->response->results as $result) {
  1089. $hit = array();
  1090. $hit["RANK"] = $result->rank;
  1091. foreach ($result->fields as $fieldname => $fieldvalue) {
  1092. $hit[$fieldname] = $fieldvalue;
  1093. }
  1094. $this->hit[] = $hit;
  1095. }
  1096. }
  1097. }
  1098. else {
  1099. // Check for sort limit/memory error conditions..
  1100. if (stristr($this->response->error_message, "system sort limit")) {
  1101. $this->sort_limit_exceeded = true;
  1102. }
  1103. if (stristr($this->response->error_message, "out of memory")) {
  1104. $this->sort_memory_exceeded = true;
  1105. }
  1106. }
  1107. } // send
  1108.  
  1109. } // searchengine_querymsg class
  1110. // ----------------------------------------------------------------------
  1111.  
  1112. /**
  1113. * The SearchEngine index message class. This class inherits all the functionality
  1114. * of the searchengine_connection, searchengine_msg and searchengine_message classes. It adds
  1115. * indexing-specific methods.
  1116. * @package search
  1117. */
  1118. class searchengine_indexmsg extends searchengine_message {
  1119. // Public
  1120. /** Indication that the indexing was successful */
  1121.  
  1122. var $indexed = false;
  1123.  
  1124. // Private
  1125. /** A unique handle to identify the index
  1126. response from SearchEngine
  1127. @access private */
  1128. var $serialno = "";
  1129. // .....................................................................
  1130. /** Constructor
  1131. * Make a new SearchEngine index message.
  1132. * @param string $application Optional application specifier
  1133. * @param string $host Hostname or IP of SearchEngine server
  1134. * @param string $port Port of SearchEngine server
  1135. * @param string $serialno Optional specific serial number to use
  1136. */
  1137. function searchengine_indexmsg($application="?", $host="", $port="", $serialno="") {
  1138. global $RESPONSE;
  1139. $this->searchengine_message("LuceneIndexRequest", $application, $host, $port);
  1140. if ($serialno != "") {
  1141. $this->serialno = $serialno;
  1142. }
  1143. else {
  1144. $this->serialno = md5(uniqid(""));
  1145. }
  1146. $this->add_xmltag( new xmltag("Serial", $this->serialno) );
  1147. $this->define_field(DEFAULT_FIELD, DEFAULT_FIELDTYPE, NOT_STORED);
  1148. } // searchengine_indexmsg
  1149. // .....................................................................
  1150. /**
  1151. * Supply field content for indexing. This causes SearchEngine to take the given
  1152. * fieldname and index the given value against it. NB: we silently ignore
  1153. * the request for nullstring, since these cause SearchEngine indexing to throw
  1154. * an exception, and indexing will fail.
  1155. * The field name can have the field type included in the form 'Foo:Date',
  1156. * where 'Date' is the type in this instance. In fact, since 'Text' is the
  1157. * default filed type, 'Date' is probably the only one you need to use
  1158. * as the current implementation stands.
  1159. * @param string $fieldname Name of the field to index.
  1160. * @param string $fieldvalue Content of the field to index
  1161. */
  1162. function index_field($fieldname, $fieldvalue) {
  1163. if ($fieldvalue !== "") {
  1164. $fieldname = $this->strip_field_type($fieldname);
  1165. $this->add_field($fieldname, $fieldvalue);
  1166. }
  1167. } // index_field
  1168. // .....................................................................
  1169. /**
  1170. * Index the given content against the given ID. This automatically
  1171. * defines the default field called "Text", and the data added as a field
  1172. * called "Text" as well. Attaches the "Body" tag to this field via a
  1173. * call to add_data() method. Thus, the content is submitted as a raw
  1174. * binary stream, rather than url-encoded text.
  1175. * @param string $id The ID to associate with the given indexed data.
  1176. * @param string $content The binary/text content to be indexed.
  1177. */
  1178. function index_content($id, $content) {
  1179. if ($content !== "") {
  1180. $this->add_xmltag( new xmltag("Id", $id), "replace" );
  1181. $content = preg_replace("/[\n\r\t]/", " ", $content);
  1182. $content = preg_replace("/[ ]{2,}/", " ", $content);
  1183. $this->add_field(DEFAULT_FIELD, $content);
  1184. }
  1185. } // index_content
  1186. // .....................................................................
  1187. /**
  1188. * Send the message to SearchEngine, and then post-process the response for
  1189. * indication of a successful index operation. We expect to receive
  1190. * a response back from SearchEngine which has our serialno in it. This method
  1191. * returns True if the indexing was successful, else False.
  1192. * @param integer $timeoutsecs Override for timeout in seconds
  1193. * @return boolean True if indexing was successful.
  1194. */
  1195. function send($timeoutsecs="") {
  1196. $success = false;
  1197. if (searchengine_message::send($timeoutsecs)) {
  1198. $this->response = new response_parser();
  1199. $this->response->parse($this->responsebuf);
  1200. if ($this->response->valid) {
  1201. $this->indexed = ($this->response->serial == $this->serialno);
  1202. $success = $this->indexed;
  1203. }
  1204. }
  1205. return $success;
  1206. } // send
  1207.  
  1208. } // searchengine_indexmsg class
  1209. // ----------------------------------------------------------------------
  1210.  
  1211. /**
  1212. * The SearchEngine unindex message class. This class allows you to remove an
  1213. * item from the SearchEngine index. You must know the unique ID that identifies
  1214. * the document.
  1215. * @package search
  1216. */
  1217. class searchengine_unindexmsg extends searchengine_message {
  1218. // .....................................................................
  1219. /** Constructor
  1220. * Make a new SearchEngine unindex message. This message is provided to allow
  1221. * you to delete an item from the SearchEngine index. It has a single method
  1222. * 'unindex' which takes the ID of the item to delete.
  1223. * @param string $application Optional application specifier
  1224. * @param string $host Hostname or IP of SearchEngine server
  1225. * @param string $port Port of SearchEngine server
  1226. */
  1227. function searchengine_unindexmsg($application="?", $host="", $port="") {
  1228. $this->searchengine_message("LuceneUnIndexRequest", $application, $host, $port);
  1229. } // searchengine_unindexmsg
  1230. // .....................................................................
  1231. /**
  1232. * Unindex the given document, as identified by the unique ID. If no errors
  1233. * arise, then the item will be removed from the SearchEngine index.
  1234. * @param string $id The ID to allow SearchEngine to identify the item to unindex
  1235. */
  1236. function unindex($id) {
  1237. $this->add_xmltag( new xmltag("Id", $id), "replace" );
  1238. } // unindex
  1239.  
  1240. // .....................................................................
  1241. /**
  1242. * Send the message to SearchEngine, and then post-process the response for
  1243. * indication of a successful index operation.
  1244. * @param integer $timeoutsecs Override for timeout in seconds
  1245. * @return boolean True if everything was successful.
  1246. */
  1247. function send($timeoutsecs="") {
  1248. $success = false;
  1249. if (searchengine_message::send($timeoutsecs)) {
  1250. $this->response = new response_parser();
  1251. $this->response->parse($this->responsebuf);
  1252. $success = $this->response->valid;
  1253. }
  1254. return $success;
  1255. } // send
  1256.  
  1257.  
  1258.  
  1259. } // searchengine_unindexmsg class
  1260. // ----------------------------------------------------------------------
  1261.  
  1262. /**
  1263. * The SearchEngine purge message class. This class allows you to remove all
  1264. * items from the SearchEngine index. Take care!
  1265. * @package search
  1266. */
  1267. class searchengine_purgemsg extends searchengine_unindexmsg {
  1268. // .....................................................................
  1269. /** Constructor
  1270. * Make a new SearchEngine purge message. This message is provided to allow
  1271. * you to delete all items from the SearchEngine index. It is just a special
  1272. * case of the unindex message.
  1273. * @param string $application Optional application specifier
  1274. * @param string $host Hostname or IP of SearchEngine server
  1275. * @param string $port Port of SearchEngine server
  1276. */
  1277. function searchengine_purgemsg($application="?", $host="", $port="") {
  1278. $this->searchengine_unindexmsg($application, $host, $port);
  1279. $this->add_xmltag( new xmltag("Purge") );
  1280. } // searchengine_purgemsg
  1281.  
  1282. } // searchengine_purgemsg class
  1283. // ----------------------------------------------------------------------
  1284.  
  1285. /**
  1286. * The SearchEngine utility message class. Used for special SearchEngine operations.
  1287. * @package search
  1288. */
  1289. class searchengine_utilitymsg extends searchengine_message {
  1290. /** Constructor
  1291. * @param string $utilitycmd Command for this utility message.
  1292. * @param string $application Optional application specifier
  1293. * @param string $host Hostname or IP of SearchEngine server
  1294. * @param string $port Port of SearchEngine server
  1295. */
  1296. function searchengine_utilitymsg($utilitycmd="", $application="?", $host="", $port="") {
  1297. $this->searchengine_message("LuceneUtilityRequest", $application, $host, $port);
  1298. if ($utilitycmd != "") {
  1299. $this->add_xmltag( new xmltag("Utility", $utilitycmd) );
  1300. }
  1301. } // searchengine_utilitymsg
  1302. // .....................................................................
  1303. /**
  1304. * Send the message to SearchEngine, and then post-process the response for
  1305. * indication of a successful utility operation. We expect to receive
  1306. * a response back from SearchEngine which has nothing much it, unless there
  1307. * has been an error.
  1308. * returns True if the operation was successful, else False.
  1309. * @param integer $timeoutsecs Override for timeout in seconds
  1310. * @return boolean True if operation was successful.
  1311. */
  1312. function send($timeoutsecs="") {
  1313. // Msg-level send-receive transaction..
  1314. searchengine_message::send($timeoutsecs);
  1315.  
  1316. // Process the response to our request..
  1317. $this->response = new response_parser();
  1318. $this->response->parse($this->responsebuf);
  1319.  
  1320. // Return status of indexing operation..
  1321. return $this->response->valid;
  1322. } // send
  1323.  
  1324. } // searchengine_utilitymsg class
  1325. // ----------------------------------------------------------------------
  1326.  
  1327. ?>

Documentation generated by phpDocumentor 1.3.0RC3