OSDN Git Service

195267d2aa20ecfe078230793bd66d1f9dec551d
[pukiwiki/pukiwiki.git] / plugin / search2.inc.php
1 <?php
2 // PukiWiki - Yet another WikiWikiWeb clone.
3 // search2.inc.php
4 // Copyright 2017 PukiWiki Development Team
5 // License: GPL v2 or (at your option) any later version
6 //
7 // Search2 plugin - Show detail result using JavaScript
8
9 define('PLUGIN_SEARCH2_MAX_LENGTH', 80);
10 define('PLUGIN_SEARCH2_MAX_BASE',   16); // #search(1,2,3,...,15,16)
11
12 // Show a search box on a page
13 function plugin_search2_convert()
14 {
15         $args = func_get_args();
16         return plugin_search_search_form('', '', $args);
17 }
18
19 function plugin_search2_action()
20 {
21         global $vars, $_title_search, $_title_result;
22
23         $action = isset($vars['action']) ? $vars['action'] : '';
24         $base = isset($vars['base']) ? $vars['base'] : '';
25         $bases = array();
26         if ($base !== '') {
27                 $bases[] = $base;
28         }
29         if ($action === '') {
30                 $q = isset($vars['q']) ? $vars['q'] : '';
31                 if ($q === '') {
32                         return array('msg' => $_title_search,
33                                 'body' => plugin_search2_search_form($q, '', $bases));
34                 } else {
35                         $msg  = str_replace('$1', htmlsc($q), $_title_result);
36                         return array('msg' => $msg,
37                                         'body' => plugin_search2_search_form($q, '', $bases));
38                 }
39         } else if ($action === 'query') {
40                 $text = isset($vars['q']) ? $vars['q'] : '';
41                 header('Content-Type: application/json; charset=UTF-8');
42                 plugin_search2_do_search($text, $base);
43                 exit;
44         }
45 }
46
47 function plugin_search2_do_search($query_text, $base)
48 {
49         global $whatsnew, $non_list, $search_non_list;
50         global $_msg_andresult, $_msg_orresult, $_msg_notfoundresult;
51         global $search_auth;
52
53         $retval = array();
54
55         $b_type_and = true; // AND:TRUE OR:FALSE
56         $key_candidates = preg_split('/\s+/', $query_text, -1, PREG_SPLIT_NO_EMPTY);
57         for ($i = count($key_candidates) - 1; $i >= 0; $i--) {
58                 if ($key_candidates[$i] === 'OR') {
59                         $b_type_and = false;
60                         unset($key_candidates[$i]);
61                 }
62         }
63         $key_candidates = array_merge($key_candidates);
64         $keys = get_search_words($key_candidates);
65         foreach ($keys as $key=>$value)
66                 $keys[$key] = '/' . $value . '/S';
67
68         $pages = get_existpages();
69
70         // Avoid
71         if ($base != '') {
72                 $pages = preg_grep('/^' . preg_quote($base, '/') . '/S', $pages);
73         }
74         if (! $search_non_list) {
75                 $pages = array_diff($pages, preg_grep('/' . $non_list . '/S', $pages));
76         }
77         natsort($pages);
78         $pages = array_flip($pages);
79         unset($pages[$whatsnew]);
80         $page_names = array_keys($pages);
81
82         $found_pages = array();
83         $readable_page_index = -1;
84         $scan_page_index = -1;
85         $last_read_page_name = null;
86         foreach ($page_names as $page) {
87                 $b_match = FALSE;
88                 $pagename_only = false;
89                 $scan_page_index++;
90                 if (! is_page_readable($page)) {
91                         if ($search_auth) {
92                                 // $search_auth - 1: User can know page names that contain search text if the page is readable
93                                 continue;
94                         }
95                         // $search_auth - 0: All users can know page names that conntain search text
96                         $pagename_only = true;
97                 }
98                 $readable_page_index++;
99                 // Search for page name and contents
100                 $body = get_source($page, TRUE, TRUE, TRUE);
101                 $target = $page . "\n" . remove_author_header($body);
102                 foreach ($keys as $key) {
103                         $b_match = preg_match($key, $target);
104                         if ($b_type_and xor $b_match) break; // OR
105                 }
106                 if ($b_match) {
107                         // Found!
108                         $filemtime = null;
109                         $author_info = get_author_info($body);
110                         if ($author_info === false || $pagename_only) {
111                                 $updated_at = get_date_atom(filemtime(get_filename($page)));
112                         }
113                         if ($pagename_only) {
114                                 // The user cannot read this page body
115                                 $found_pages[] = array('name' => (string)$page,
116                                         'url' => get_page_uri($page), 'updated_at' => $updated_at,
117                                         'body' => '', 'pagename_only' => 1);
118                         } else {
119                                 $found_pages[] = array('name' => (string)$page,
120                                         'url' => get_page_uri($page), 'updated_at' => $updated_at,
121                                         'body' => (string)$body);
122                         }
123                 }
124                 $last_read_page_name = $page;
125         }
126         $message = str_replace('$1', htmlsc($query_text), str_replace('$2', count($found_pages),
127                 str_replace('$3', count($page_names), $b_type_and ? $_msg_andresult : $_msg_orresult)));
128         $search_done = (boolean)($scan_page_index + 1 === count($page_names));
129         $result_obj = array(
130                 'message' => $message,
131                 'q' => $query_text,
132                 'read_page_count' => $readable_page_index + 1,
133                 'scan_page_count' => $scan_page_index + 1,
134                 'page_count' => count($page_names),
135                 'last_read_page_name' => $last_read_page_name,
136                 'search_done' => $search_done,
137                 'results' => $found_pages);
138         $obj = $result_obj;
139         if (!defined('PKWK_UTF8_ENABLE')) {
140                 if (SOURCE_ENCODING === 'EUC-JP') {
141                         mb_convert_variables('UTF-8', 'CP51932', $obj);
142                 } else {
143                         mb_convert_variables('UTF-8', SOURCE_ENCODING, $obj);
144                 }
145         }
146         print(json_encode($obj, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
147 }
148
149 function plugin_search2_search_form($s_word = '', $type = '', $bases = array())
150 {
151         global $_btn_search;
152         global $_search_pages, $_search_all;
153         global $_msg_andresult, $_msg_orresult, $_msg_notfoundresult;
154         global $_search_detail, $_search_searching;
155         global $_msg_unsupported_webbrowser, $_msg_use_alternative_link;
156
157         $script = get_base_uri();
158         $h_search_text = htmlsc($s_word);
159
160         $base_option = '';
161         if (!empty($bases)) {
162                 $base_msg = '';
163                 $_num = 0;
164                 $check = ' checked';
165                 foreach($bases as $base) {
166                         ++$_num;
167                         if (PLUGIN_SEARCH2_MAX_BASE < $_num) break;
168                         $s_base   = htmlsc($base);
169                         $base_str = '<strong>' . $s_base . '</strong>';
170                         $base_label = str_replace('$1', $base_str, $_search_pages);
171                         $base_msg  .=<<<EOD
172  <div>
173   <label>
174    <input type="radio" name="base" value="$s_base" $check> $base_label
175   </label>
176  </div>
177 EOD;
178                         $check = '';
179                 }
180                 $base_msg .=<<<EOD
181 <label><input type="radio" name="base" value=""> $_search_all</label>
182 EOD;
183                 $base_option = '<div class="small">' . $base_msg . '</div>';
184         }
185         $_search2_result_notfound = htmlsc($_msg_notfoundresult);
186         $_search2_result_found = htmlsc($_msg_andresult);
187         $_search2_search_wait_milliseconds = PLUGIN_SEARCH2_SEARCH_WAIT_MILLISECONDS;
188         $result_page_panel =<<<EOD
189 <div id="_plugin_search2_search_status"></div>
190 <div id="_plugin_search2_message"></div>
191 <input type="checkbox" id="_plugin_search2_detail" checked><label for="_plugin_search2_detail">$_search_detail</label>
192 <input type="hidden" id="_plugin_search2_msg_searching" value="$_search_searching">
193 <input type="hidden" id="_plugin_search2_msg_result_notfound" value="$_search2_result_notfound">
194 <input type="hidden" id="_plugin_search2_msg_result_found" value="$_search2_result_found">
195 <input type="hidden" id="_search2_search_wait_milliseconds" value="$_search2_search_wait_milliseconds">
196 EOD;
197         if ($h_search_text == '') {
198                 $result_page_panel = '';
199         }
200
201         $plain_search_link = '<a href="' . $script . '?cmd=search' . '">' . htmlsc($_btn_search) . '</a>';
202         $alt_msg = str_replace('$1', $plain_search_link, $_msg_use_alternative_link);
203         return <<<EOD
204 <noscript>
205  <p>$_msg_unsupported_webbrowser $alt_msg</p>
206 </noscript>
207 <p class="_plugin_search2_nosupport_message" style="display:none;">
208   $_msg_unsupported_webbrowser $alt_msg
209 </p>
210 <form action="$script" method="GET" class="_plugin_search2_form">
211  <div>
212   <input type="hidden" name="cmd" value="search2">
213   <input type="search"  name="q" value="$h_search_text" size="30">
214   <input type="submit" value="$_btn_search">
215  </div>
216 $base_option
217 </form>
218 $result_page_panel
219 <ul id="result-list">
220 </ul>
221 EOD;
222 }