OSDN Git Service

BugTrack/692 Show page contents in search result - search2 plugin
[pukiwiki/pukiwiki.git] / plugin / search2.inc.php
diff --git a/plugin/search2.inc.php b/plugin/search2.inc.php
new file mode 100644 (file)
index 0000000..195267d
--- /dev/null
@@ -0,0 +1,222 @@
+<?php
+// PukiWiki - Yet another WikiWikiWeb clone.
+// search2.inc.php
+// Copyright 2017 PukiWiki Development Team
+// License: GPL v2 or (at your option) any later version
+//
+// Search2 plugin - Show detail result using JavaScript
+
+define('PLUGIN_SEARCH2_MAX_LENGTH', 80);
+define('PLUGIN_SEARCH2_MAX_BASE',   16); // #search(1,2,3,...,15,16)
+
+// Show a search box on a page
+function plugin_search2_convert()
+{
+       $args = func_get_args();
+       return plugin_search_search_form('', '', $args);
+}
+
+function plugin_search2_action()
+{
+       global $vars, $_title_search, $_title_result;
+
+       $action = isset($vars['action']) ? $vars['action'] : '';
+       $base = isset($vars['base']) ? $vars['base'] : '';
+       $bases = array();
+       if ($base !== '') {
+               $bases[] = $base;
+       }
+       if ($action === '') {
+               $q = isset($vars['q']) ? $vars['q'] : '';
+               if ($q === '') {
+                       return array('msg' => $_title_search,
+                               'body' => plugin_search2_search_form($q, '', $bases));
+               } else {
+                       $msg  = str_replace('$1', htmlsc($q), $_title_result);
+                       return array('msg' => $msg,
+                                       'body' => plugin_search2_search_form($q, '', $bases));
+               }
+       } else if ($action === 'query') {
+               $text = isset($vars['q']) ? $vars['q'] : '';
+               header('Content-Type: application/json; charset=UTF-8');
+               plugin_search2_do_search($text, $base);
+               exit;
+       }
+}
+
+function plugin_search2_do_search($query_text, $base)
+{
+       global $whatsnew, $non_list, $search_non_list;
+       global $_msg_andresult, $_msg_orresult, $_msg_notfoundresult;
+       global $search_auth;
+
+       $retval = array();
+
+       $b_type_and = true; // AND:TRUE OR:FALSE
+       $key_candidates = preg_split('/\s+/', $query_text, -1, PREG_SPLIT_NO_EMPTY);
+       for ($i = count($key_candidates) - 1; $i >= 0; $i--) {
+               if ($key_candidates[$i] === 'OR') {
+                       $b_type_and = false;
+                       unset($key_candidates[$i]);
+               }
+       }
+       $key_candidates = array_merge($key_candidates);
+       $keys = get_search_words($key_candidates);
+       foreach ($keys as $key=>$value)
+               $keys[$key] = '/' . $value . '/S';
+
+       $pages = get_existpages();
+
+       // Avoid
+       if ($base != '') {
+               $pages = preg_grep('/^' . preg_quote($base, '/') . '/S', $pages);
+       }
+       if (! $search_non_list) {
+               $pages = array_diff($pages, preg_grep('/' . $non_list . '/S', $pages));
+       }
+       natsort($pages);
+       $pages = array_flip($pages);
+       unset($pages[$whatsnew]);
+       $page_names = array_keys($pages);
+
+       $found_pages = array();
+       $readable_page_index = -1;
+       $scan_page_index = -1;
+       $last_read_page_name = null;
+       foreach ($page_names as $page) {
+               $b_match = FALSE;
+               $pagename_only = false;
+               $scan_page_index++;
+               if (! is_page_readable($page)) {
+                       if ($search_auth) {
+                               // $search_auth - 1: User can know page names that contain search text if the page is readable
+                               continue;
+                       }
+                       // $search_auth - 0: All users can know page names that conntain search text
+                       $pagename_only = true;
+               }
+               $readable_page_index++;
+               // Search for page name and contents
+               $body = get_source($page, TRUE, TRUE, TRUE);
+               $target = $page . "\n" . remove_author_header($body);
+               foreach ($keys as $key) {
+                       $b_match = preg_match($key, $target);
+                       if ($b_type_and xor $b_match) break; // OR
+               }
+               if ($b_match) {
+                       // Found!
+                       $filemtime = null;
+                       $author_info = get_author_info($body);
+                       if ($author_info === false || $pagename_only) {
+                               $updated_at = get_date_atom(filemtime(get_filename($page)));
+                       }
+                       if ($pagename_only) {
+                               // The user cannot read this page body
+                               $found_pages[] = array('name' => (string)$page,
+                                       'url' => get_page_uri($page), 'updated_at' => $updated_at,
+                                       'body' => '', 'pagename_only' => 1);
+                       } else {
+                               $found_pages[] = array('name' => (string)$page,
+                                       'url' => get_page_uri($page), 'updated_at' => $updated_at,
+                                       'body' => (string)$body);
+                       }
+               }
+               $last_read_page_name = $page;
+       }
+       $message = str_replace('$1', htmlsc($query_text), str_replace('$2', count($found_pages),
+               str_replace('$3', count($page_names), $b_type_and ? $_msg_andresult : $_msg_orresult)));
+       $search_done = (boolean)($scan_page_index + 1 === count($page_names));
+       $result_obj = array(
+               'message' => $message,
+               'q' => $query_text,
+               'read_page_count' => $readable_page_index + 1,
+               'scan_page_count' => $scan_page_index + 1,
+               'page_count' => count($page_names),
+               'last_read_page_name' => $last_read_page_name,
+               'search_done' => $search_done,
+               'results' => $found_pages);
+       $obj = $result_obj;
+       if (!defined('PKWK_UTF8_ENABLE')) {
+               if (SOURCE_ENCODING === 'EUC-JP') {
+                       mb_convert_variables('UTF-8', 'CP51932', $obj);
+               } else {
+                       mb_convert_variables('UTF-8', SOURCE_ENCODING, $obj);
+               }
+       }
+       print(json_encode($obj, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
+}
+
+function plugin_search2_search_form($s_word = '', $type = '', $bases = array())
+{
+       global $_btn_search;
+       global $_search_pages, $_search_all;
+       global $_msg_andresult, $_msg_orresult, $_msg_notfoundresult;
+       global $_search_detail, $_search_searching;
+       global $_msg_unsupported_webbrowser, $_msg_use_alternative_link;
+
+       $script = get_base_uri();
+       $h_search_text = htmlsc($s_word);
+
+       $base_option = '';
+       if (!empty($bases)) {
+               $base_msg = '';
+               $_num = 0;
+               $check = ' checked';
+               foreach($bases as $base) {
+                       ++$_num;
+                       if (PLUGIN_SEARCH2_MAX_BASE < $_num) break;
+                       $s_base   = htmlsc($base);
+                       $base_str = '<strong>' . $s_base . '</strong>';
+                       $base_label = str_replace('$1', $base_str, $_search_pages);
+                       $base_msg  .=<<<EOD
+ <div>
+  <label>
+   <input type="radio" name="base" value="$s_base" $check> $base_label
+  </label>
+ </div>
+EOD;
+                       $check = '';
+               }
+               $base_msg .=<<<EOD
+<label><input type="radio" name="base" value=""> $_search_all</label>
+EOD;
+               $base_option = '<div class="small">' . $base_msg . '</div>';
+       }
+       $_search2_result_notfound = htmlsc($_msg_notfoundresult);
+       $_search2_result_found = htmlsc($_msg_andresult);
+       $_search2_search_wait_milliseconds = PLUGIN_SEARCH2_SEARCH_WAIT_MILLISECONDS;
+       $result_page_panel =<<<EOD
+<div id="_plugin_search2_search_status"></div>
+<div id="_plugin_search2_message"></div>
+<input type="checkbox" id="_plugin_search2_detail" checked><label for="_plugin_search2_detail">$_search_detail</label>
+<input type="hidden" id="_plugin_search2_msg_searching" value="$_search_searching">
+<input type="hidden" id="_plugin_search2_msg_result_notfound" value="$_search2_result_notfound">
+<input type="hidden" id="_plugin_search2_msg_result_found" value="$_search2_result_found">
+<input type="hidden" id="_search2_search_wait_milliseconds" value="$_search2_search_wait_milliseconds">
+EOD;
+       if ($h_search_text == '') {
+               $result_page_panel = '';
+       }
+
+       $plain_search_link = '<a href="' . $script . '?cmd=search' . '">' . htmlsc($_btn_search) . '</a>';
+       $alt_msg = str_replace('$1', $plain_search_link, $_msg_use_alternative_link);
+       return <<<EOD
+<noscript>
+ <p>$_msg_unsupported_webbrowser $alt_msg</p>
+</noscript>
+<p class="_plugin_search2_nosupport_message" style="display:none;">
+  $_msg_unsupported_webbrowser $alt_msg
+</p>
+<form action="$script" method="GET" class="_plugin_search2_form">
+ <div>
+  <input type="hidden" name="cmd" value="search2">
+  <input type="search"  name="q" value="$h_search_text" size="30">
+  <input type="submit" value="$_btn_search">
+ </div>
+$base_option
+</form>
+$result_page_panel
+<ul id="result-list">
+</ul>
+EOD;
+}