Commit 9603a82cffb68c3b1a5bd48d1f802e46938d49c6

Authored by jjordaan
1 parent a193b828

StoryId:702985 Open Search Formated Results

Commited by: Jarrett Jordaan

Reviewed by: Megan Watson
Showing 1 changed file with 554 additions and 0 deletions
plugins/search2/openSearch.php 0 → 100644
  1 +<?php
  2 +require_once('../../config/dmsDefaults.php');
  3 +require_once('../../ktapi/ktapi.inc.php');
  4 +
  5 +class openSearch extends KTStandardDispatcher {
  6 + // XML object
  7 + private $dom; // DOMDocument
  8 + private $type; // rss or atom
  9 + private $query; // Search Query
  10 + private $results; // Search Results
  11 + private $requestUri; //
  12 + private $server; //
  13 + protected $ktapi; //
  14 + private $session_id; //
  15 + private $status_code; //
  16 + private $message; //
  17 + private $username; //
  18 + private $password; //
  19 + // 1.1 Draft parameters
  20 + protected $searchTerms; // required
  21 + protected $count; // optional
  22 + protected $startIndex; // optional
  23 + protected $startPage; // optional
  24 + protected $language; // optional
  25 + protected $inputEncoding; // optional
  26 + protected $outputEncoding; // optional
  27 +
  28 + private $osQuery; // Query Element
  29 +
  30 + public function openSearch() {
  31 + $this->dom = new DOMDocument("1.0", "UTF-8");
  32 + $this->query = "";
  33 + $this->searchTerms = "";
  34 + $this->count = 20;
  35 + $this->startIndex = 1;
  36 + $this->startPage = 1;
  37 + $this->language = "";
  38 + $this->inputEncoding = "UTF-8";
  39 + $this->outputEncoding = "UTF-8";
  40 + $this->type = "rss";
  41 + $this->osQuery = new osQuery();
  42 + $this->requestUri = '';
  43 + $this->results = false;
  44 + $this->ktapi = null;
  45 + $this->status_code = 1;
  46 + $this->message = "";
  47 + }
  48 +
  49 +/* Getters */
  50 + function getQuery($txtQuery) {
  51 + $query = str_replace(array("\r\n", "\r", "\n"), array(' ', ' ', ' '), $txtQuery);
  52 + $query = strip_tags($query);
  53 +
  54 + return $query;
  55 + }
  56 +
  57 + function getSearchTerms($query) {
  58 + if(preg_match("/\"([^\"\"]+|\"?R\")*\"/",$query,$matches)) {
  59 + $query = $matches[1];
  60 + }
  61 +
  62 + return $query;
  63 + }
  64 +
  65 + function getResults($query) {
  66 + $this->status_code = 1;
  67 + $response['results'] = array();
  68 + $expr = parseExpression($query);
  69 + $results = $expr->evaluate();
  70 +
  71 + //echo "<pre>";print_r($rs);echo "</pre>";die;
  72 + if (PEAR::isError($results)) {
  73 +
  74 + return false;
  75 + }
  76 + if(empty($results)){
  77 + $this->message = _kt('Your search did not return any results');
  78 + }
  79 + $this->status_code = 0;
  80 + $response['results'] = $results;
  81 +
  82 + return $response;
  83 + }
  84 +
  85 + function getTotalResults() {
  86 + return count($this->results['results']['docs'])+count($this->results['results']['folders']);
  87 + }
  88 +/* Setters */
  89 + // Set search terms
  90 + function setQuery($query) {
  91 + $this->query = $query;
  92 + }
  93 +
  94 + // Set search terms
  95 + function setSearchTerms($searchTerms) {
  96 + $this->searchTerms = $searchTerms;
  97 + }
  98 +
  99 + // Set count
  100 + function setCount($count) {
  101 + $this->count = $count;
  102 + }
  103 +
  104 + // Set start index
  105 + function setStartIndex($startIndex) {
  106 + $this->startIndex = $startIndex;
  107 + }
  108 +
  109 + // Set start page
  110 + function setStartPage($startPage) {
  111 + $this->startPage = $startPage;
  112 + }
  113 +
  114 + // Set language
  115 + function setLanguage($lang) {
  116 + $this->language = $lang;
  117 + }
  118 +
  119 + // Set input encoding
  120 + function setInputEncoding($inputEncoding) {
  121 + $this->inputEncoding = $inputEncoding;
  122 + }
  123 +
  124 + // Set output encoding
  125 + function setOutputEncoding($outputEncoding) {
  126 + $this->outputEncoding = $outputEncoding;
  127 + }
  128 +
  129 + // Set xml output type
  130 + function setType($type) {
  131 + $this->type = $type;
  132 + }
  133 +
  134 + // Set search results
  135 + function setResults($results) {
  136 + $this->results = $results;
  137 + }
  138 +
  139 + // Set up Open Search Query
  140 + function setOSQuery() {
  141 + $this->osQuery->setTotalResults($this->getTotalResults());
  142 + $this->osQuery->setTitle($this->searchTerms);
  143 + $this->osQuery->setRoles();
  144 + }
  145 +
  146 + // Set search URL
  147 + function setRequestUri($requestUri) {
  148 + $this->requestUri = $requestUri;
  149 + }
  150 +
  151 + // Set session id
  152 + function setSessionId($session_id) {
  153 + $this->session_id = $session_id;
  154 + }
  155 +
  156 + // Set host
  157 + function setServer($server) {
  158 + $this->server = $server;
  159 + }
  160 +
  161 + // Set username
  162 + function setUsername($username) {
  163 + $this->username = $username;
  164 + }
  165 +
  166 + // Set password
  167 + function setPassword($password) {
  168 + $this->password = $password;
  169 + }
  170 +/* Helpers */
  171 + function presetParams() { // Set params needed regardless
  172 + if(isset($_REQUEST['session_id'])) { $this->setSessionId($_REQUEST['session_id']); }
  173 + if(isset($_REQUEST['type'])) { $this->setType($_REQUEST['type']); }
  174 + }
  175 +
  176 + // Split request and instantiate open search object
  177 + function setParams() { // Set all needed params
  178 + if(isset($_REQUEST['txtQuery'])) {
  179 + $query = $this->getQuery($_REQUEST['txtQuery']);
  180 + $this->setQuery($query);
  181 + $this->setSearchTerms($this->getSearchTerms($query));
  182 + $this->setResults($this->getResults($query));
  183 + }
  184 + if(isset($_REQUEST['count'])) { $this->setCount($_REQUEST['count']); }
  185 + if(isset($_REQUEST['starti'])) { $this->setStartIndex($_REQUEST['starti']); }
  186 + if(isset($_REQUEST['startp'])) { $this->setStartPage($_REQUEST['startp']); }
  187 + if(isset($_REQUEST['kt_language'])) { $this->setLanguage($_REQUEST['kt_language']); }
  188 + if(isset($_SERVER['REQUEST_URI'])) { $this->setRequestUri($_SERVER['REQUEST_URI']); }
  189 + if(isset($_SERVER['HTTP_HOST'])) { $this->setServer($_SERVER['HTTP_HOST']); }
  190 + $this->setOSQuery();
  191 + }
  192 +
  193 + private function build_feed() {
  194 + if($this->type == "atom") { $this->build_atom(); } else { $this->build_rss(); }
  195 + }
  196 +
  197 + private function build_atom() {
  198 + $dom_response = $this->dom->appendChild($this->dom->createElement("response"));
  199 + $dom_response->setAttribute("xmlns", "http://www.w3.org/2005/Atom");
  200 + $dom_response->setAttribute("xmlns:opensearch", "http://a9.com/-/spec/opensearch/1.1/");
  201 + if(!$this->status_code) {
  202 + $dom_response = $this->body_atom($dom_response);
  203 + $dom_response = $this->opensearch_results($dom_response); // Add search results in open search format
  204 + }
  205 + $channel_statusCode = $dom_response->appendChild($this->dom->createElement("status_code"));
  206 + $channel_statusCode->appendChild($this->dom->createTextNode("{$this->status_code}"));
  207 + if($this->message != '') {
  208 + $channel_message = $dom_response->appendChild($this->dom->createElement("message"));
  209 + $channel_message->appendChild($this->dom->createTextNode("{$this->message}"));
  210 + }
  211 + }
  212 +
  213 + private function body_atom($dom_response) {
  214 + $channel_title = $dom_response->appendChild($this->dom->createElement("title"));
  215 + $channel_title->appendChild($this->dom->createTextNode("Knowledgetree Search: {$this->searchTerms}"));
  216 + $channel_subtitle = $dom_response->appendChild($this->dom->createElement("subtitle"));
  217 + $channel_subtitle->appendChild($this->dom->createTextNode('Search metadata and content on KnowledgeTree'));
  218 + $channel_author = $dom_response->appendChild($this->dom->createElement("author"));
  219 + $author_name = $channel_author->appendChild($this->dom->createElement("name"));
  220 + $author_name->appendChild($this->dom->createTextNode("Knowledgetree"));
  221 + $channel_numResults = $dom_response->appendChild($this->dom->createElement("opensearch:totalResults"));
  222 + $channel_numResults->appendChild($this->dom->createTextNode("{$this->osQuery->getTotalResults()}"));
  223 + $channel_index = $dom_response->appendChild($this->dom->createElement("opensearch:startIndex"));
  224 + $channel_index->appendChild($this->dom->createTextNode("{$this->startIndex}"));
  225 + $channel_itemsPerPage = $dom_response->appendChild($this->dom->createElement("opensearch:itemsPerPage"));
  226 + $channel_itemsPerPage->appendChild($this->dom->createTextNode("{$this->count}"));
  227 +
  228 + return $dom_response;
  229 + }
  230 +
  231 + private function build_rss() {
  232 + $dom_rss = $this->dom->appendChild($this->dom->createElement("rss"));
  233 + $dom_rss->setAttribute("version", "2.0");
  234 + $dom_rss->setAttribute("xmlns:opensearch", "http://a9.com/-/spec/opensearch/1.1/");
  235 + $dom_rss->setAttribute("xmlns:atom", "http://www.w3.org/2005/Atom");
  236 + $rss_channel = $dom_rss->appendChild($this->dom->createElement("channel"));
  237 + if(!$this->status_code) {
  238 + $rss_channel = $this->body_rss($rss_channel);
  239 + $rss_channel = $this->opensearch_results($rss_channel); // Add search results in open search format
  240 + }
  241 + $channel_statusCode = $rss_channel->appendChild($this->dom->createElement("status_code"));
  242 + $channel_statusCode->appendChild($this->dom->createTextNode("{$this->status_code}"));
  243 + if($this->message != '') {
  244 + $channel_message = $rss_channel->appendChild($this->dom->createElement("message"));
  245 + $channel_message->appendChild($this->dom->createTextNode("{$this->message}"));
  246 + }
  247 + }
  248 +
  249 + private function body_rss($rss_channel) {
  250 + $channel_title = $rss_channel->appendChild($this->dom->createElement("title"));
  251 + $channel_title->appendChild($this->dom->createTextNode("Knowledgetree Search: {$this->searchTerms}"));
  252 + $channel_description = $rss_channel->appendChild($this->dom->createElement("description"));
  253 + $channel_description->appendChild($this->dom->createTextNode('Search metadata and content on KnowledgeTree'));
  254 + $channel_numResults = $rss_channel->appendChild($this->dom->createElement("opensearch:totalResults"));
  255 + $channel_numResults->appendChild($this->dom->createTextNode("{$this->osQuery->getTotalResults()}"));
  256 + $channel_index = $rss_channel->appendChild($this->dom->createElement("opensearch:startIndex"));
  257 + $channel_index->appendChild($this->dom->createTextNode("{$this->startIndex}"));
  258 + $channel_itemsPerPage = $rss_channel->appendChild($this->dom->createElement("opensearch:itemsPerPage"));
  259 + $channel_itemsPerPage->appendChild($this->dom->createTextNode("{$this->count}"));
  260 +
  261 + return $rss_channel;
  262 + }
  263 +
  264 + private function opensearch_results($channel) { // Add search results in open search format
  265 +// echo '<pre>';print_r($this->results);echo '</pre>';die;
  266 + if($this->results) {
  267 + $this->encodeDocs($channel, $this->results['results']['docs']);
  268 + $this->encodeFolders($channel, $this->results['results']['folders']);
  269 + }
  270 +
  271 + return $channel;
  272 + }
  273 +
  274 + private function encodeDocs($channel, $docs) {
  275 + foreach($docs as $doc) {
  276 + if($this->type == 'atom') {
  277 + $channel = $this->adocument_item($channel, $doc);
  278 + } else {
  279 + $channel = $this->document_item($channel, $doc);
  280 + }
  281 + }
  282 + }
  283 +
  284 + private function encodeFolders($channel, $folders) {
  285 + foreach($folders as $folder) {
  286 + if($this->type == 'atom') {
  287 + $channel = $this->afolder_item($channel, $folder);
  288 + } else {
  289 + $channel = $this->folder_item($channel, $folder);
  290 + }
  291 + }
  292 + }
  293 +
  294 + private function adocument_item($channel, $doc) {
  295 + $channel_entry = $channel->appendChild($this->dom->createElement("entry"));
  296 + $channel_author = $channel_entry->appendChild($this->dom->createElement("author"));
  297 + $channel_author->appendChild($this->dom->createTextNode("{$doc->createdBy}"));
  298 + $channel_id = $channel_entry->appendChild($this->dom->createElement("id"));
  299 + $channel_id->appendChild($this->dom->createTextNode("{$doc->id}"));
  300 + $channel_title = $channel_entry->appendChild($this->dom->createElement("title"));
  301 + $channel_title->appendChild($this->dom->createTextNode("{$doc->title}"));
  302 + $channel_link = $channel_entry->appendChild($this->dom->createElement("link"));
  303 + $channel_link->setAttribute("href", "http://{$this->server}/view.php?fDocumentId={$doc->id}");
  304 + $channel_updated = $channel_entry->appendChild($this->dom->createElement("updated"));
  305 + $channel_updated->appendChild($this->dom->createTextNode("{$doc->dateModified}"));
  306 +
  307 + return $channel;
  308 + }
  309 +
  310 + private function afolder_item($channel, $folder) {
  311 + $channel_entry = $channel->appendChild($this->dom->createElement("entry"));
  312 + $channel_author = $channel_entry->appendChild($this->dom->createElement("author"));
  313 + $channel_author->appendChild($this->dom->createTextNode("{$folder->createdBy}"));
  314 + $channel_id = $channel_entry->appendChild($this->dom->createElement("id"));
  315 + $channel_id->appendChild($this->dom->createTextNode("{$folder->id}"));
  316 + $channel_title = $channel_entry->appendChild($this->dom->createElement("title"));
  317 + $channel_title->appendChild($this->dom->createTextNode("{$folder->title}"));
  318 + $channel_link = $channel_entry->appendChild($this->dom->createElement("link"));
  319 + $channel_link->setAttribute("href", "http://{$this->server}/view.php?fFolderId={$folder->id}");
  320 + $channel_updated = $channel_entry->appendChild($this->dom->createElement("updated"));
  321 + $channel_updated->appendChild($this->dom->createTextNode("{$folder->dateModified}"));
  322 +
  323 + return $channel;
  324 + }
  325 +
  326 + private function document_item($channel, $doc) { // Document results
  327 + $channel_entry = $channel->appendChild($this->dom->createElement("item"));
  328 + $channel_author = $channel_entry->appendChild($this->dom->createElement("author"));
  329 + $channel_author->appendChild($this->dom->createTextNode("{$doc->createdBy}"));
  330 + $channel_id = $channel_entry->appendChild($this->dom->createElement("guid"));
  331 + $channel_id->appendChild($this->dom->createTextNode("{$doc->id}"));
  332 + $channel_title = $channel_entry->appendChild($this->dom->createElement("title"));
  333 + $channel_title->appendChild($this->dom->createTextNode("{$doc->title}"));
  334 + $channel_link = $channel_entry->appendChild($this->dom->createElement("link"));
  335 + $channel_link->setAttribute("href", "http://{$this->server}/view.php?fDocumentId={$doc->id}");
  336 +
  337 + return $channel;
  338 + }
  339 +
  340 + private function folder_item($channel, $folder) { // Document results
  341 + $channel_entry = $channel->appendChild($this->dom->createElement("item"));
  342 + $channel_author = $channel_entry->appendChild($this->dom->createElement("author"));
  343 + $channel_author->appendChild($this->dom->createTextNode("{$folder->createdBy}"));
  344 + $channel_id = $channel_entry->appendChild($this->dom->createElement("guid"));
  345 + $channel_id->appendChild($this->dom->createTextNode("{$folder->id}"));
  346 + $channel_title = $channel_entry->appendChild($this->dom->createElement("title"));
  347 + $channel_title->appendChild($this->dom->createTextNode("{$folder->title}"));
  348 + $channel_link = $channel_entry->appendChild($this->dom->createElement("link"));
  349 + $channel_link->setAttribute("href", "http://{$this->server}/view.php?fFolderId={$folder->id}");
  350 +
  351 + return $channel;
  352 + }
  353 +
  354 + private function toRSS() {
  355 + header('Content-Type: application/rss+xml; charset=utf-8;');
  356 + header('Content-Disposition: inline; filename="rss.xml"');
  357 + header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
  358 +
  359 + echo $this->dom->saveXML();
  360 + }
  361 +
  362 + private function toAtom() {
  363 + header('Content-Type: application/rss+xml; charset=utf-8;');
  364 + header('Content-Disposition: inline; filename="rss.xml"');
  365 + header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
  366 +
  367 + echo $this->dom->saveXML();
  368 + }
  369 +
  370 + private function outputRSS() {
  371 + header('Content-Type: text/xml');
  372 + echo $this->dom->saveXML();
  373 + }
  374 +
  375 + private function outputAtom() {
  376 + header('Content-Type: text/xml');
  377 + echo $this->dom->saveXML();
  378 + }
  379 +
  380 + public function auth() {
  381 + $ktapi = $this->get_ktapi($_REQUEST['session_id']);// instantiate KTAPI and invoke method
  382 + if(PEAR::isError($ktapi)) {
  383 + $this->message = _kt('API could not be authenticated');
  384 +
  385 + return false;
  386 + }
  387 +
  388 + return true;
  389 + }
  390 +
  391 + /**
  392 + * Instantiate KTAPI and get the active session, if the session id is supplied
  393 + *
  394 + * @author KnowledgeTree Team
  395 + * @access protected
  396 + * @param string $session_id
  397 + * @return KTAPI
  398 + */
  399 + protected function &get_ktapi($session_id = null) {
  400 + if (!is_null($this->ktapi)) {
  401 + return $this->ktapi;
  402 + }
  403 + $kt = new KTAPI();
  404 + if(!empty($session_id)) { // if the session id has been passed through - get the active session.
  405 + $session = $kt->get_active_session($session_id, null);
  406 + if (PEAR::isError($session)) {
  407 +
  408 + return $session;
  409 + }
  410 + }
  411 + $this->ktapi = $kt;
  412 +
  413 + return $kt;
  414 + }
  415 +
  416 + /**
  417 + * Creates a new session for the user.
  418 + *
  419 + * @param string $username
  420 + * @param string $password
  421 + * @param string $ip
  422 + * @return kt_response
  423 + */
  424 + public function login() {
  425 + if(isset($_REQUEST['username'])) { $this->setUsername($_REQUEST['username']); }
  426 + if(isset($_REQUEST['password'])) { $this->setPassword($_REQUEST['password']); }
  427 + $kt = new KTAPI();
  428 + $session = $kt->start_session($this->username,$this->password, $ip);
  429 + if (PEAR::isError($session))
  430 + {
  431 + $this->status_code = 1;
  432 + $this->message = $session->getMessage();
  433 +
  434 + return $this->login_fail();
  435 + }
  436 + $session = $session->get_session();
  437 + $this->status_code = 0;
  438 + $this->message = "";
  439 + $this->results = $session;
  440 +
  441 + return $this->login_pass($response);
  442 + }
  443 +
  444 + private function login_fail() {
  445 + $response = $this->dom->appendChild($this->dom->createElement("response"));
  446 + $response_status = $response->appendChild($this->dom->createElement("status_code"));
  447 + $response_status->appendChild($this->dom->createTextNode("{$this->status_code}"));
  448 + $response_message = $response->appendChild($this->dom->createElement("message"));
  449 + $response_message->appendChild($this->dom->createTextNode("{$this->message}"));
  450 + if($this->type == 'atom') {
  451 + $this->outputAtom();
  452 + } else {
  453 + $this->outputRSS();
  454 + }
  455 + }
  456 +
  457 + private function login_pass() {
  458 + $response = $this->dom->appendChild($this->dom->createElement("response"));
  459 + $response_status = $response->appendChild($this->dom->createElement("status_code"));
  460 + $response_status->appendChild($this->dom->createTextNode("{$this->status_code}"));
  461 + $response_results = $response->appendChild($this->dom->createElement("results"));
  462 + $response_results->appendChild($this->dom->createTextNode("{$this->results}"));
  463 + if($this->type == 'atom') {
  464 + $this->outputAtom();
  465 + } else {
  466 + $this->outputRSS();
  467 + }
  468 + }
  469 +
  470 + public function driver($test = false) {
  471 + if(isset($_GET['method'])) {
  472 + if($_GET['method'] == 'login')
  473 + return $this->$_GET['method']();
  474 + else
  475 + $this->message = 'Unknown Method';
  476 + }
  477 + $this->presetParams();
  478 + if($this->auth()) { $this->setParams(); } else { $this->message = "API could not be authenticated";}
  479 + $this->build_feed();
  480 + if($this->type == 'atom') {
  481 + if(!$test) { $this->driverAtom(); } else { $this->outputAtom(); }
  482 + } else {
  483 + if(!$test) { $this->driverRss(); } else { $this->outputRSS(); }
  484 + }
  485 + }
  486 +
  487 + public function driverAtom() {
  488 + $this->toAtom();
  489 + }
  490 +
  491 + public function driverRss() {
  492 + $this->toRSS();
  493 + }
  494 +}
  495 +
  496 +class osQuery {
  497 + // 1.1 Query Element
  498 + private $role; // Contains a string identifying how the search client should interpret the search request defined by this Query
  499 + private $totalResults; // Contains the expected number of results to be found if the search request were made.
  500 + private $title; // Contains a human-readable plain text string describing the search request.
  501 +
  502 + function osQuery() {
  503 + $this->totalResults = 0;
  504 + $this->title = "";
  505 + $this->role = array();
  506 + }
  507 +
  508 +/* Getters */
  509 + function getTotalResults() {
  510 + return $this->totalResults;
  511 + }
  512 +
  513 + function setTotalResults($totalResults) {
  514 + $this->totalResults = $totalResults;
  515 + }
  516 +
  517 +/* Setters */
  518 + function setTitle($title) {
  519 + $this->title = $title;
  520 + }
  521 +
  522 + function setRoles() {
  523 + $this->role["request"] = new queryRole("request", ""); // request Represents the search query that can be performed to retrieve the same set of search results.
  524 + $this->role["example"] = new queryRole("example", ""); // example Represents a search query that can be performed to demonstrate the search engine.
  525 + $this->role["related"] = new queryRole("related", ""); // related Represents a search query that can be performed to retrieve similar but different search results.
  526 + $this->role["correction"] = new queryRole("related", ""); // correction Represents a search query that can be performed to improve the result set, such as with a spelling correction.
  527 + $this->role["subset"] = new queryRole("subset", ""); // subset Represents a search query that will narrow the current set of search results.
  528 + $this->role["superset"] = new queryRole("superset", ""); // superset Represents a search query that will broaden the current set of search results.
  529 + }
  530 +
  531 +/* Helpers */
  532 +}
  533 +
  534 +class queryRole {
  535 + private $role;
  536 + private $url;
  537 +
  538 + public function queryRole($role, $url) {
  539 + $this->role = $role;
  540 + $this->url = $url;
  541 + }
  542 +
  543 + function setRole($role) {
  544 + $this->role = $role;
  545 + }
  546 +
  547 + function setUrl($url) {
  548 + $this->url = $url;
  549 + }
  550 +}
  551 +
  552 +$os = new openSearch();
  553 +$os->driver(true);
  554 +?>
0 \ No newline at end of file 555 \ No newline at end of file