index.php (15944B)
1 <!doctype html>
2 <html>
3
4 <!-- Process input (if given) -->
5 <?php
6
7 /* Load Configuration */
8 include("config/config.php");
9 include("lib/read_mappings.php");
10
11 /* Fetch and sanitize search query via GET request
12 * Allow both "query" and "q"
13 */
14 $_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
15 if (!is_null($_GET["query"])) {
16 $query = rawurldecode($_GET["query"]);
17 } else if (!is_null($_GET["q"])) {
18 $query = rawurldecode($_GET["q"]);
19 } else {
20 $query = null;
21 }
22
23 /* Handle Fallback Search Engine via cookie or GET argument
24 * Fallback is always defined in config/configs.php
25 */
26 if (!is_null($_GET["fallback"])) {
27 $fallback = $_GET["fallback"];
28 } elseif (!is_null($_COOKIE["fallback"])) {
29 $fallback = $_COOKIE["fallback"];
30 /* refresh cookie */
31 header(
32 "Set-Cookie: " .
33 "fallback=" . $fallback . "; " .
34 "Max-Age=" . 31536000 . "; " . /* 60 x 60 x 24 x 365 = 1 year */
35 "Domain=" . $_SERVER["SERVER_NAME"] . "; " .
36 "SameSite=Strict;"
37 );
38 }
39
40 if (strlen($query) > 0) {
41
42 /* Find keywords (only first one is considered) */
43 $keyword = preg_replace(
44 '/^.*?\!([A-Za-z0-9_\-\.]+).*$/',
45 '${1}',
46 $query
47 );
48 $keyword = strtolower($keyword);
49
50 /* Based on given keyword, choose a search engine or the fallback */
51 if (array_search($keyword, array_keys($searchkeys)) !== false) {
52 $search = $searchkeys[$keyword];
53 } else {
54 $search = $fallback;
55 }
56
57 /* Get options from keyword (syntax: !key:opt)*/
58 if (preg_match('/\![A-Za-z0-9_\-\.]+:[A-Za-z0-9_\-\.\/]+/', $query) === 1) {
59 $keyoption = preg_replace(
60 '/^.*?\![A-Za-z0-9_\-\.]+:([A-Za-z0-9_\-\.\/]+).*$/',
61 '${1}',
62 $query
63 );
64 $keyoption = strtolower($keyoption);
65 } elseif (array_key_exists("default_opts", $searches[$search])) {
66 $keyoption = $searches[$search]["default_opts"];
67 } else {
68 $keyoption = "";
69 }
70
71 /* Strip keyword from search term */
72 $search_term = preg_replace(
73 '/\![A-Za-z0-9_\-\.]+:{0,1}[A-Za-z0-9_\-\.\/]*/',
74 '',
75 $query
76 );
77
78 /* Remove preceding and trailing spaces */
79 $search_term = preg_replace(
80 '/^\s+|\s+$/',
81 '',
82 $search_term
83 );
84
85 /* Construct search query */
86 $target = str_replace(
87 '%s',
88 rawurlencode($search_term),
89 /* insert keyoption */
90 str_replace(
91 '%opt',
92 $keyoption,
93 $searches[$search]["query"]
94 )
95 );
96
97 /* Redirect to target search engine: 307 - Temporary Redirect */
98 header("Location: " . $target, true, 307);
99 die();
100 }
101
102 ?>
103
104 <!-- Head -->
105 <head>
106 <meta charset=utf-8>
107 <meta name=viewport content="width=device-width,initial-scale=1">
108 <link rel=icon href=/assets/img/favicon.png type=image/png>
109 <link rel=icon href=/assets/img/favicon.ico type=x-image/ico>
110 <link rel=stylesheet href=/assets/css/simple.min.css media=all>
111 <link rel=stylesheet href=/assets/css/custom.css>
112 <link rel="manifest" href="manifest.json">
113 <link
114 rel="search"
115 type="application/opensearchdescription+xml"
116 href="/opensearch.xml"
117 title="serĉi - search with !keywords"
118 >
119 <script async src=/assets/js/filter_engines.js></script>
120 <title>serĉi - search with !keywords</title>
121 </head>
122
123 <!-- Body -->
124 <body>
125
126 <!-- Header -->
127 <header>
128 <nav>
129 <a href="#engines">
130 Engines
131 </a>
132 <a href="#faqs">
133 FAQs
134 </a>
135 <a href="https://src.jayvii.de/pub/serci/" target="_blank">
136 Development
137 </a>
138 </nav>
139 <h1>serĉi</h1>
140 <p>Search with Keywords</p>
141 </header>
142
143 <!-- Search Bar -->
144 <form id="searchform" action="/" method="get">
145 <input
146 id="searchbar"
147 name="query"
148 type="text"
149 autofocus
150 placeholder="I am thinking about... !keyword"
151 alt="Search the web"
152 onkeydown="if(event.keyCode===13)return this.form.submit(),!1"
153 >
154 <input
155 name="fallback"
156 id="fallback"
157 type="hidden"
158 value="<?php echo $fallback; ?>"
159 >
160 <input
161 id="searchbutton"
162 name="submit"
163 type="submit"
164 value="🔎 Search"
165 >
166 </form>
167
168 <!-- Description -->
169 <div class="description">
170 <strong style="font-size: 133%;">
171 The keyword engine for power users that sits on top of your
172 favorite search engines!
173 </strong>
174 <p>
175 Have all your favorite search providers right at your finger
176 tips all the time and use them directly via
177 <code>!keywords</code> within your search query. Serĉi uses
178 your favorite search engine as fallback, whenever you do not
179 provide a keyword.
180 </p>
181 <a href="#engines" class="button">
182 Explore
183 </a>
184 <a href="#faqs" class="button">
185 Learn more
186 </a>
187 </div>
188
189 <!-- Search Engine Lists -->
190 <h3 id="engines">Available Search Engines</h3>
191
192 <p>
193 This serĉi instance supports
194 <mark><?php echo count($searches); ?> search engines</mark> within
195 <mark><?php echo count($categories); ?> categories</mark> and
196 <mark><?php echo count($searchkeys); ?> keywords</mark>.
197 </p>
198
199 <!-- Search Engine Filterbar -->
200 <input
201 id="engines_filterbar"
202 name="engines"
203 type="text"
204 placeholder="Filter available Search Engines..."
205 oninput="filter_engines('engines_filterbar');"
206 >
207 <noscript>
208 <div class="notice">
209 <p>
210 Exploring the available search engines with the filter bar
211 above as well as choosing your fallback search engine
212 requires javascript.
213 <strong>However, using serĉi itself does not</strong>!
214 </p>
215 <p>
216 Read the <a href="#faqs">FAQs</a> on how to choose a
217 fallback search engine when javascript or cookies are
218 disabled.
219 </p>
220 </div>
221 </noscript>
222
223 <!-- Search Engine Category Buttons -->
224 <details id="categories">
225 <summary>Categories</summary>
226
227 <div class="row">
228
229 <!-- Always insert a "Fallback" category button -->
230 <button
231 onclick="filter_category('Fallback');"
232 title="Search Engine that is choosen as fallback"
233 >
234 #Fallback
235 </button>
236
237 <!-- List all configured categories -->
238 <?php
239 foreach (array_keys($categories) as $cid) {
240 $cat_name = $categories[$cid]["name"];
241 ?>
242 <button
243 onclick="filter_category('<?php echo $cat_name; ?>');"
244 title="<?php echo $categories[$cid]["description"]; ?>"
245 >
246 <?php echo "#" . $cat_name; ?>
247 </button>
248 <?php
249 }
250 ?>
251
252 </div>
253
254 </details>
255
256 <!-- Search Engine List -->
257 <?php
258 foreach (array_keys($searches) as $sid) {
259 $search = $searches[$sid];
260 ?>
261 <article
262 id="<?php echo $sid; ?>"
263 class="<?php if ($sid == $fallback) { echo "selected"; }?>"
264 >
265 <!-- Entry-Head -->
266 <h3>
267 <a href="<?php echo $search["website"]; ?>" target="_blank">
268 <?php echo $search["name"]; ?>
269 </a>
270 </h3>
271
272 <!-- Entry-Description -->
273 <p><?php echo $search["description"]; ?></p>
274
275 <!-- Entry-Categories -->
276 <div class="categories">
277
278 <?php
279 /* If current entry is the fallback search, add the Mark */
280 if ($sid == $fallback) {
281 ?>
282 <mark id="fallback_marker">#Fallback</mark>
283 <?php
284 }
285 ?>
286
287 <?php
288 /* List all categories of current entry */
289 foreach ($search["categories"] as $cid) {
290 ?>
291 <mark title="<?php echo $categories[$cid]["description"];?>">
292 <?php echo "#" . $categories[$cid]["name"]; ?>
293 </mark>
294 <?php
295 }
296 ?>
297
298 </div>
299
300 <!-- Entry-Keywords -->
301 <strong>Keywords: </strong>
302 <code>
303 <?php
304 echo "!" .
305 implode(
306 "</code><code>!",
307 $search["keywords"]
308 );
309 ?>
310 </code>
311 <br><br>
312
313 <!-- "Make-Fallback" Button -->
314 <button onclick="make_fallback('<?php echo $sid; ?>')">
315 Choose as fallback
316 </button>
317
318 </article>
319 <?php
320 }
321 ?>
322
323 <!-- FAQs / About-Section -->
324 <section id="faqs">
325
326 <?php
327 /* Random entry from search array: used within examples below */
328 $rsi = array_rand($searches, 1);
329 ?>
330
331 <h3>About serĉi</h3>
332
333 <!-- meaning of name -->
334 <details>
335 <summary>What does serĉi mean?</summary>
336 <p>
337 It is the Esperanto term for "to search".This may not be the
338 most creative name for such a software project but to the
339 best of my knowledge, it is a unique one.
340 </p>
341 </details>
342
343 <!-- what are keywords -->
344 <details>
345 <summary>What are keywords?</summary>
346 <p>
347 An idea lent from the search Engine
348 <a href="https://duckduckgo.com/bangs" target="_blank">
349 DuckDuckGo
350 </a>, which has been utilized by many others since. They
351 call their keywords bangs, but it is the same concept and
352 usability. In essence, keywords are shortcuts for searching
353 on other websites.
354 </p>
355 <p>
356 For example, you can conduct a search on the website
357 <a
358 href="<?php echo $searches[$rsi]["website"]; ?>"
359 target="_blank"
360 >
361 <?php echo $searches[$rsi]["name"]; ?>
362 </a>
363 directly from <?php echo $_SERVER["SERVER_NAME"]; ?> by
364 adding the keyword
365 <code>!<?php echo $searches[$rsi]["keywords"][0]; ?></code>
366 to your search query.
367 </p>
368 <p>
369 You can find all keywords associated with each search engine
370 in the <a href="#engines">list above</a>.
371 </p>
372 </details>
373
374 <!-- how to use -->
375 <details>
376 <summary>How can I use serĉi?</summary>
377 <p>
378 You can try serĉi directly
379 <a href="#searchbar">on this site</a> or
380 <a
381 href="https://src.jayvii.de/pub/serci/#hosting"
382 target="_blank"
383 >
384 host it yourself
385 </a>!
386 It barely needs any server resources, no database or lots of
387 RAM. serĉi has minimal footprint (also on user data: there
388 are <strong>none</strong>).
389 </p>
390 <p>
391 Either type your search directly into the
392 <a href="#searchbar">search bar at the very top</a>
393 or add the search to your browser by rightclicking in the
394 URL-bar of your web browser and choose
395 <emph>add serĉi - Search with !keywords</emph>.
396 </p>
397 <p>
398 Some browsers (for example Firefox on Android / Fennec)
399 allow to configure custom search engines via a so-called
400 search URL. Simply list following URL as
401 <emph>search-URL</emph> there and choose it as your fallback
402 search option:
403 </p>
404 <pre>https://<?php echo $_SERVER["SERVER_NAME"]; ?>/?q=%s</pre>
405 <p>
406 You can also choose the fallback search engine, used by
407 serĉi as fallback, when no keyword is given, through the URL
408 instead of choosing it from the
409 <a href="#engines">list above</a>, in case you do not want
410 serĉi to store any cookie on your device. For example, if
411 you wanted to use
412 <a
413 href="<?php echo $searches[$rsi]["website"]; ?>"
414 target="_blank"
415 >
416 <?php echo $searches[$rsi]["name"]; ?>
417 </a>
418 as your fallback search, you could use following search-URL:
419 </p>
420 <pre><?php
421 echo "https://" . $_SERVER["SERVER_NAME"] .
422 "/?fallback=" . $rsi . "&q=%s";
423 ?></pre>
424 </details>
425
426 <!-- no js or cookies -->
427 <details>
428 <summary>
429 Choosing a fallback search without cookies or Javascript
430 </summary>
431 <p>
432 You can simply choose a fallback search by adding the
433 <code>fallback</code> URL parameter. For example, if you
434 wanted to use
435 <a
436 href="<?php echo $searches[$rsi]["website"]; ?>"
437 target="_blank"
438 >
439 <?php echo $searches[$rsi]["name"]; ?>
440 </a>
441 as your fallback search, you can simply add
442 <code>/?fallback=<?php echo $rsi; ?></code> to the serĉi
443 URL:
444 <br>
445 <a href="/?fallback=<?php echo $rsi; ?>">
446 <?php
447 echo "https://" . $_SERVER["SERVER_NAME"] .
448 "/?fallback=" . $rsi;
449 ?>
450 </a>
451 </p>
452 </details>
453
454 </section>
455
456 </body>
457
458 </html>