text.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <?php
  2. function get_engines() {
  3. return array("google", "duckduckgo", "brave", "yandex", "ecosia", "mojeek");
  4. }
  5. class TextSearch extends EngineRequest {
  6. protected $cache_key, $engine, $engines, $engine_request, $special_request;
  7. public function __construct($opts, $mh) {
  8. $this->engines = get_engines();
  9. shuffle($this->engines);
  10. $this->query = $opts->query;
  11. $this->cache_key = "text:" . $this->query . "p" . $opts->page . "l" . $opts->language;
  12. $this->page = $opts->page;
  13. $this->opts = $opts;
  14. $this->engine = $opts->engine;
  15. $query_parts = explode(" ", $this->query);
  16. $last_word_query = end($query_parts);
  17. if (substr($this->query, 0, 1) == "!" || substr($last_word_query, 0, 1) == "!")
  18. check_ddg_bang($this->query, $opts);
  19. if (has_cached_results($this->cache_key))
  20. return;
  21. if ($this->engine == "auto")
  22. $this->engine = $this->select_engine();
  23. // no engine was selected
  24. if (is_null($this->engine))
  25. return;
  26. // this only happens if a specific engine was selected, not if auto is used
  27. if (has_cooldown($this->engine, $this->opts->cooldowns))
  28. return;
  29. $this->engine_request = $this->get_engine_request($this->engine, $opts, $mh);
  30. if (is_null($this->engine_request))
  31. return;
  32. require_once "engines/special/special.php";
  33. $this->special_request = get_special_search_request($opts, $mh);
  34. }
  35. private function select_engine() {
  36. if (sizeof($this->engines) == 0)
  37. return null;
  38. $engine = array_pop($this->engines);
  39. // if this engine is on cooldown, try again
  40. if (!has_cooldown($engine, $this->opts->cooldowns))
  41. return $engine;
  42. return $this->select_engine();
  43. }
  44. private function get_engine_request($engine, $opts, $mh) {
  45. if ($engine == "google") {
  46. require_once "engines/text/google.php";
  47. return new GoogleRequest($opts, $mh);
  48. }
  49. if ($engine == "duckduckgo") {
  50. require_once "engines/text/duckduckgo.php";
  51. return new DuckDuckGoRequest($opts, $mh);
  52. }
  53. if ($engine == "brave") {
  54. require_once "engines/text/brave.php";
  55. return new BraveSearchRequest($opts, $mh);
  56. }
  57. if ($engine == "yandex") {
  58. require_once "engines/text/yandex.php";
  59. return new YandexSearchRequest($opts, $mh);
  60. }
  61. if ($engine == "ecosia") {
  62. require_once "engines/text/ecosia.php";
  63. return new EcosiaSearchRequest($opts, $mh);
  64. }
  65. if ($engine == "mojeek") {
  66. require_once "engines/text/mojeek.php";
  67. return new MojeekSearchRequest($opts, $mh);
  68. }
  69. // if an invalid engine is selected, don't give any results
  70. return null;
  71. }
  72. public function parse_results($response) {
  73. if (has_cached_results($this->cache_key))
  74. return fetch_cached_results($this->cache_key);
  75. if (!isset($this->engine_request))
  76. return array();
  77. $results = $this->engine_request->get_results();
  78. if (empty($results)) {
  79. set_cooldown($this->engine, ($this->opts->request_cooldown ?? "1") * 60, $this->opts->cooldowns);
  80. } else {
  81. if ($this->special_request) {
  82. $special_result = $this->special_request->get_results();
  83. if ($special_result)
  84. $results = array_merge(array($special_result), $results);
  85. }
  86. }
  87. if (!empty($results)) {
  88. $results["results_source"] = parse_url($this->engine_request->url)["host"];
  89. store_cached_results($this->cache_key, $results);
  90. }
  91. return $results;
  92. }
  93. public static function print_results($results, $opts) {
  94. if (empty($results)) {
  95. echo "<div class=\"text-result-container\"><p>An error occured fetching results</p></div>";
  96. return;
  97. }
  98. if (array_key_exists("error", $results)) {
  99. echo "<div class=\"text-result-container\"><p>" . $results["error"]["message"] . "</p></div>";
  100. return;
  101. }
  102. $special = $results[0];
  103. if (array_key_exists("did_you_mean", $special)) {
  104. $didyoumean = $special["did_you_mean"];
  105. $new_url = "/search.php?q=" . urlencode($didyoumean);
  106. echo "<p class=\"did-you-mean\">Did you mean ";
  107. echo "<a href=\"$new_url\">$didyoumean</a>";
  108. echo "?</p>";
  109. }
  110. if (array_key_exists("special_response", $special)) {
  111. $response = $special["special_response"]["response"];
  112. $source = $special["special_response"]["source"];
  113. echo "<p class=\"special-result-container\">";
  114. if (array_key_exists("image", $special["special_response"])) {
  115. $image_url = $special["special_response"]["image"];
  116. echo "<img src=\"image_proxy.php?url=$image_url\">";
  117. }
  118. echo $response;
  119. if ($source) {
  120. $source = check_for_privacy_frontend($source, $opts);
  121. echo "<a href=\"$source\" rel=\"noreferer noopener\" target=\"_blank\">$source</a>";
  122. }
  123. echo "</p>";
  124. }
  125. echo "<div class=\"text-result-container\">";
  126. foreach($results as $result) {
  127. if (!is_array($result))
  128. continue;
  129. if (!array_key_exists("title", $result))
  130. continue;
  131. $title = $result["title"];
  132. $url = $result["url"];
  133. $url = check_for_privacy_frontend($url, $opts);
  134. $base_url = get_base_url($url);
  135. $description = $result["description"];
  136. echo "<div class=\"text-result-wrapper\">";
  137. echo "<a rel=\"noreferer noopener\" href=\"$url\">";
  138. echo "$base_url";
  139. echo "<h2>$title</h2>";
  140. echo "</a>";
  141. echo "<span>$description</span>";
  142. echo "</div>";
  143. }
  144. echo "</div>";
  145. }
  146. }
  147. function check_ddg_bang($query, $opts) {
  148. $bangs_json = file_get_contents("static/misc/ddg_bang.json");
  149. $bangs = json_decode($bangs_json, true);
  150. if (substr($query, 0, 1) == "!")
  151. $search_word = substr(explode(" ", $query)[0], 1);
  152. else
  153. $search_word = substr(end(explode(" ", $query)), 1);
  154. $bang_url = null;
  155. foreach($bangs as $bang) {
  156. if ($bang["t"] == $search_word) {
  157. $bang_url = $bang["u"];
  158. break;
  159. }
  160. }
  161. if ($bang_url) {
  162. $bang_query_array = explode("!" . $search_word, $query);
  163. $bang_query = trim(implode("", $bang_query_array));
  164. $request_url = str_replace("{{{s}}}", str_replace('%26quot%3B','%22', urlencode($bang_query)), $bang_url);
  165. header("Location: " . $request_url);
  166. die();
  167. }
  168. }
  169. ?>