Subversion Repositories oidplus

Rev

Rev 1219 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
635 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
1086 daniel-mar 5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
635 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
1050 daniel-mar 20
namespace ViaThinkSoft\OIDplus;
635 daniel-mar 21
 
1086 daniel-mar 22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
25
 
635 daniel-mar 26
class OIDplusPagePublicSearch extends OIDplusPagePluginPublic {
27
 
1116 daniel-mar 28
        /**
29
         * @param bool $html
30
         * @return void
31
         * @throws OIDplusException
32
         */
33
        public function init(bool $html=true) {
635 daniel-mar 34
                OIDplus::config()->prepareConfigKey('search_min_term_length', 'Minimum length of a search term', '3', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
35
                        if (!is_numeric($value) || ($value < 0)) {
36
                                throw new OIDplusException(_L('Please enter a valid value.'));
37
                        }
38
                });
39
        }
40
 
1116 daniel-mar 41
        /**
1130 daniel-mar 42
         * @param array $params
43
         * @param bool $is_searching
1116 daniel-mar 44
         * @return void
45
         */
1130 daniel-mar 46
        private function prepareSearchParams(array &$params, bool $is_searching) {
635 daniel-mar 47
                $params['term'] = isset($params['term']) ? trim($params['term']) : '';
48
                $params['namespace'] = isset($params['namespace']) ? trim($params['namespace']) : '';
49
 
50
                // Default criteria selection:
51
                if ($is_searching) {
52
                        $params['search_title'] = isset($params['search_title']) && $params['search_title'];
53
                        $params['search_description'] = isset($params['search_description']) && $params['search_description'];
54
                        $params['search_asn1id'] = isset($params['search_asn1id']) && $params['search_asn1id'];
55
                        $params['search_iri'] = isset($params['search_iri']) && $params['search_iri'];
56
                } else {
57
                        $params['search_title'] = true;
58
                        $params['search_description'] = false;
59
                        $params['search_asn1id'] = true;
60
                        $params['search_iri'] = true;
61
                }
62
        }
63
 
1116 daniel-mar 64
        /**
1130 daniel-mar 65
         * @param string $html
66
         * @param string $term
67
         * @return string
1116 daniel-mar 68
         */
1130 daniel-mar 69
        private function highlight_match(string $html, string $term): string {
704 daniel-mar 70
                return str_replace(htmlentities($term), '<font color="red">'.htmlentities($term).'</font>', $html);
71
        }
72
 
1116 daniel-mar 73
        /**
1130 daniel-mar 74
         * @param array $params
1116 daniel-mar 75
         * @return string
76
         * @throws OIDplusException
77
         */
1130 daniel-mar 78
        private function doSearch(array $params): string {
635 daniel-mar 79
                $output = '';
80
 
81
                // Note: The SQL collation defines if search is case sensitive or case insensitive
82
 
83
                $min_length = OIDplus::config()->getValue('search_min_term_length');
84
 
85
                $this->prepareSearchParams($params, true);
86
 
87
                if (strlen($params['term']) == 0) {
88
                        $output .= '<p><font color="red">'._L('Error: You must enter a search term.').'</font></p>';
89
                } else if (strlen($params['term']) < $min_length) {
90
                        $output .= '<p><font color="red">'._L('Error: Search term minimum length is %1 characters.',$min_length).'</font></p>';
91
                } else {
92
                        // TODO: case insensitive comparison (or should we leave that to the DBMS?)
93
 
94
                        if ($params['namespace'] == 'oidplus:ra') {
704 daniel-mar 95
                                $output .= '<h2>'._L('Search results for RA %1','<font color="red">'.htmlentities($params['term']).'</font>').'</h2>';
635 daniel-mar 96
 
97
                                $sql_where = array(); $prep_where = array();
98
                                $sql_where[] = "email like ?";   $prep_where[] = '%'.$params['term'].'%';
99
                                $sql_where[] = "ra_name like ?"; $prep_where[] = '%'.$params['term'].'%';
100
 
101
                                if (count($sql_where) == 0) $sql_where[] = '1=0';
102
                                $res = OIDplus::db()->query("select * from ###ra where (".implode(' or ', $sql_where).")", $prep_where);
103
 
104
                                $count = 0;
105
                                while ($row = $res->fetch_object()) {
106
                                        $email = str_replace('@', '&', $row->email);
1219 daniel-mar 107
                                        $output .= '<p><a '.OIDplus::gui()->link('oidplus:rainfo$'.str_replace('@','&',$email)).'>'.$this->highlight_match(htmlentities($email),$params['term']).'</a>: <b>'.$this->highlight_match(htmlentities($row->ra_name??''),$params['term']).'</b></p>';
635 daniel-mar 108
                                        $count++;
109
                                }
110
                                if ($count == 0) {
111
                                        $output .= '<p>'._L('Nothing found').'</p>';
112
                                }
113
                        } else {
704 daniel-mar 114
                                $output .= '<h2>'._L('Search results for %1 (%2)','<font color="red">'.htmlentities($params['term']).'</font>',htmlentities($params['namespace'])).'</h2>';
635 daniel-mar 115
 
116
                                $sql_where = array(); $prep_where = array();
117
                                $sql_where[] = "id like ?"; $prep_where[] = '%'.$params['term'].'%'; // TODO: should we rather do findFitting(), so we can e.g. find GUIDs with different notation?
118
                                if ($params["search_title"])       { $sql_where[] = "title like ?";       $prep_where[] = '%'.$params['term'].'%'; }
119
                                if ($params["search_description"]) { $sql_where[] = "description like ?"; $prep_where[] = '%'.$params['term'].'%'; }
120
 
121
                                if ($params["search_asn1id"]) {
122
                                        $res = OIDplus::db()->query("select * from ###asn1id where name like ?", array('%'.$params['term'].'%'));
123
                                        while ($row = $res->fetch_object()) {
124
                                                $sql_where[] = "id = ?"; $prep_where[] = $row->oid;
125
                                        }
126
                                }
127
 
128
                                if ($params["search_iri"]) {
129
                                        $res = OIDplus::db()->query("select * from ###iri where name like ?", array('%'.$params['term'].'%'));
130
                                        while ($row = $res->fetch_object()) {
131
                                                $sql_where[] = "id = ?"; $prep_where[] = $row->oid;
132
                                        }
133
                                }
134
 
135
                                if (count($sql_where) == 0) $sql_where[] = '1=0';
136
                                array_unshift($prep_where, $params['namespace'].':%');
137
 
138
                                $res = OIDplus::db()->query("select * from ###objects where id like ? and (".implode(' or ', $sql_where).")", $prep_where);
139
 
140
                                $count = 0;
141
                                while ($row = $res->fetch_object()) {
704 daniel-mar 142
                                        $output .= '<p><a '.OIDplus::gui()->link($row->id).'>'.$this->highlight_match(htmlentities($row->id),$params['term']).'</a>';
635 daniel-mar 143
 
144
                                        $asn1ids = array();
145
                                        $res2 = OIDplus::db()->query("select name from ###asn1id where oid = ?", array($row->id));
146
                                        while ($row2 = $res2->fetch_object()) {
147
                                                $asn1ids[] = $row2->name;
148
                                        }
149
                                        if (count($asn1ids) > 0) {
150
                                                $asn1ids = implode(', ', $asn1ids);
704 daniel-mar 151
                                                $output .= ' ('.$this->highlight_match(htmlentities($asn1ids),$params['term']).')';
635 daniel-mar 152
                                        }
153
 
1219 daniel-mar 154
                                        if (htmlentities($row->title) != '') $output .= ': <b>'.$this->highlight_match(htmlentities($row->title??''),$params['term']).'</b></p>';
635 daniel-mar 155
                                        $count++;
156
                                }
157
                                if ($count == 0) {
158
                                        $output .= '<p>'._L('Nothing found').'</p>';
159
                                }
160
                        }
161
                }
162
 
163
                return $output;
164
        }
165
 
1116 daniel-mar 166
        /**
1293 daniel-mar 167
         * @param array $params
168
         * @return array
169
         * @throws OIDplusException
170
         */
171
        private function action_Search(array $params): array {
172
                $ret = $this->doSearch($params);
173
                return array("status" => 0, "output" => $ret);
174
        }
175
 
176
        /**
1116 daniel-mar 177
         * @param string $actionID
178
         * @param array $params
179
         * @return array
180
         * @throws OIDplusException
181
         */
182
        public function action(string $actionID, array $params): array {
635 daniel-mar 183
                if ($actionID == 'search') {
1293 daniel-mar 184
                        return $this->action_Search($params);
1116 daniel-mar 185
                } else {
186
                        return parent::action($actionID, $params);
635 daniel-mar 187
                }
188
        }
189
 
1116 daniel-mar 190
        /**
191
         * @param string $id
192
         * @param array $out
193
         * @param bool $handled
194
         * @return void
195
         * @throws OIDplusException
196
         */
197
        public function gui(string $id, array &$out, bool &$handled) {
635 daniel-mar 198
                if (explode('$',$id)[0] == 'oidplus:search') {
199
                        $handled = true;
200
 
201
                        $out['title'] = _L('Search');
801 daniel-mar 202
                        $out['icon'] = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : '';
635 daniel-mar 203
 
204
                        $out['text'] = '';
205
 
206
                        try {
207
                                $params = $_POST;
208
 
209
                                $this->prepareSearchParams($params, isset($params['search']));
210
 
962 daniel-mar 211
                                $out['text'] .= '<form id="searchForm" action="?goto=oidplus%3Asearch" method="POST">
635 daniel-mar 212
                                                 <input type="hidden" name="search" value="1">
213
                                                 '._L('Search for').': <input type="text" id="term" name="term" value="'.htmlentities($params['term']).'"><br><br>
214
                                                 <script>
215
                                                 function searchNsSelect(ns) {
216
                                                     $("#search_options_oid")[0].style.display = (ns == "oid") ? "block" : "none";
217
                                                     $("#search_options_object")[0].style.display = (ns == "oidplus:ra") ? "none" : "block";
218
                                                     $("#search_options_ra")[0].style.display = (ns == "oidplus:ra") ? "block" : "none";
219
                                                 }
220
                                                 $( document ).ready(function() {
221
                                                     searchNsSelect($("#namespace")[0].value);
222
                                                 });
223
                                                 </script>
224
                                                 '._L('Search in').': <select name="namespace" id="namespace" onchange="searchNsSelect(this.value);"><br><br>';
225
 
226
                                foreach (OIDplus::getEnabledObjectTypes() as $ot) {
227
                                        $out['text'] .= '<option value="'.htmlentities($ot::ns()).'"'.(($params['namespace'] == $ot::ns()) ? ' selected' : '').'>'.htmlentities($ot::objectTypeTitle()).'</option>';
228
                                }
229
                                $out['text'] .= '<option value="oidplus:ra"'.(($params['namespace'] == 'oidplus:ra') ? ' selected' : '').'>'._L('Registration Authority').'</option>
230
                                                 </select><br><br>
231
                                <div id="search_options_ra">
232
                                <!-- TODO: RA specific selection criterias -->
233
                                </div>
234
                                <div id="search_options_object">
235
                                            <input type="checkbox" name="search_title" id="search_title" value="1"'.($params["search_title"] ? ' checked' : '').'> <label for="search_title">'._L('Search in field "Title"').'</label><br>
236
                                            <input type="checkbox" name="search_description" id="search_description" value="1"'.($params["search_description"] ? ' checked' : '').'> <label for="search_description">'._L('Search in field "Description"').'</label><br>
237
                                <div id="search_options_oid">
238
                                    <input type="checkbox" name="search_asn1id" id="search_asn1id" value="1"'.($params["search_asn1id"] ? ' checked' : '').'> <label for="search_asn1id">'._L('Search in field "ASN.1 identifier" (only OIDs)').'</label><br>
239
                                    <input type="checkbox" name="search_iri" id="search_iri" value="1"'.($params["search_iri"] ? ' checked' : '').'> <label for="search_iri">'._L('Search in field "Unicode label" (only OIDs)').'</label><br>
240
                                </div>
241
                                </div>
242
                                 <br>
243
 
244
                                <input type="submit" value="'._L('Search').'" onclick="return OIDplusPagePublicSearch.search_button_click()">
245
                                </form>';
246
 
247
                                $out['text'] .= '<div id="search_output">'; // will be filled with either AJAX or staticly (HTML form submit)
248
                                if (isset($params['search'])) {
249
                                        // Search with NoJS/HTML
250
                                        $out['text'] .= $this->doSearch($params);
251
                                }
252
                                $out['text'] .= '</div>';
1050 daniel-mar 253
                        } catch (\Exception $e) {
1201 daniel-mar 254
                                $htmlmsg = $e instanceof OIDplusException ? $e->getHtmlMessage() : htmlentities($e->getMessage());
255
                                $out['text'] = _L('Error: %1',$htmlmsg);
635 daniel-mar 256
                        }
257
                }
258
        }
259
 
1116 daniel-mar 260
        /**
261
         * @param array $out
262
         * @return void
263
         */
264
        public function publicSitemap(array &$out) {
635 daniel-mar 265
                $out[] = 'oidplus:search';
266
        }
267
 
1116 daniel-mar 268
        /**
269
         * @param array $json
270
         * @param string|null $ra_email
271
         * @param bool $nonjs
272
         * @param string $req_goto
273
         * @return bool
274
         * @throws OIDplusException
275
         */
276
        public function tree(array &$json, string $ra_email=null, bool $nonjs=false, string $req_goto=''): bool {
800 daniel-mar 277
                if (file_exists(__DIR__.'/img/main_icon16.png')) {
801 daniel-mar 278
                        $tree_icon = OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon16.png';
635 daniel-mar 279
                } else {
280
                        $tree_icon = null; // default icon (folder)
281
                }
282
 
283
                $json[] = array(
284
                        'id' => 'oidplus:search',
285
                        'icon' => $tree_icon,
286
                        'text' => _L('Search')
287
                );
288
 
289
                return true;
290
        }
291
 
1116 daniel-mar 292
        /**
293
         * @param string $request
294
         * @return array|false
295
         */
296
        public function tree_search(string $request) {
635 daniel-mar 297
                return false;
298
        }
299
}