tools.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. <?php
  2. /* ------------------------------------------------------------------------------------
  3. * Goosle - The fast, privacy oriented search tool that just works.
  4. *
  5. * COPYRIGHT NOTICE
  6. * Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
  7. *
  8. * COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
  9. * By using this code you agree to indemnify Arnan de Gans from any
  10. * liability that might arise from its use.
  11. ------------------------------------------------------------------------------------ */
  12. /*--------------------------------------
  13. // Verify the hash, or not, and let people in, or not
  14. --------------------------------------*/
  15. function verify_hash($use_hash, $hash, $auth) {
  16. if(($use_hash == 'on' && strtolower($hash) === strtolower($auth)) || $use_hash == 'off') return true;
  17. return false;
  18. }
  19. /*--------------------------------------
  20. // Load and make config available, pass around variables
  21. --------------------------------------*/
  22. function load_opts() {
  23. $config_file = ABSPATH.'config.php';
  24. if(!is_file($config_file)) {
  25. echo "<h3>config.php is missing!</h3>";
  26. echo "<p>Please check the readme.md file for complete installation instructions.</p>";
  27. echo "<p>Configure Goosle properly by copying config.default.php to config.php. In config.php you can set your preferences.</p>";
  28. die();
  29. } else {
  30. $opts = require $config_file;
  31. // From the url/request
  32. if(!isset($_REQUEST['s'])) {
  33. $opts->query = (isset($_REQUEST['q'])) ? trim($_REQUEST['q']) : '';
  34. $opts->type = (isset($_REQUEST['t'])) ? sanitize($_REQUEST['t']) : 0;
  35. $opts->user_auth = (isset($_REQUEST['a'])) ? sanitize($_REQUEST['a']) : '';
  36. $opts->share = '';
  37. } else {
  38. $share_string = explode('||', base64_url_decode(sanitize($_REQUEST['s'])));
  39. if(is_array($share_string) && count($share_string) === 4) {
  40. $opts->query = trim($share_string[2]);
  41. $opts->type = sanitize($share_string[0]);
  42. $opts->user_auth = sanitize($share_string[1]);
  43. $opts->share = sanitize($share_string[3]);
  44. }
  45. unset($share_string);
  46. }
  47. // Force a few defaults and safeguards
  48. if(empty($opts->colorscheme)) $opts->colorscheme = 'default';
  49. if($opts->cache_type == 'file' && !is_dir(ABSPATH.'cache/')) $opts->cache_type = 'off';
  50. if($opts->cache_type == 'apcu' && !function_exists('apcu_exists')) $opts->cache_type = 'off';
  51. if($opts->enable_image_search == 'off' && $opts->type == 1) $opts->type = 0;
  52. if($opts->enable_magnet_search == 'off' && $opts->type == 9) $opts->type = 0;
  53. if($opts->cache_time < 1 || ($opts->cache_type == 'apcu' && $opts->cache_time > 8) || ($opts->cache_type == 'file' && $opts->cache_time > 48)) $opts->cache_time = 8;
  54. if(!is_numeric($opts->social_media_relevance) || ($opts->social_media_relevance > 10 || $opts->social_media_relevance < 0)) $opts->social_media_relevance = 8;
  55. // Remove ! at the start of queries to prevent DDG Bangs (!g, !c and crap like that)
  56. if(substr($opts->query, 0, 1) == '!') $opts->query = substr($opts->query, 1);
  57. return $opts;
  58. }
  59. }
  60. /*--------------------------------------
  61. // Standardized cURL requests that support both POST and GET
  62. // For Box Office, Update checks and oAUTH
  63. // NOT (YET?) USED FOR ENGINE REQUESTS!!
  64. // NOT (YET?) USED FOR ENGINE REQUESTS!!
  65. --------------------------------------*/
  66. function do_curl_request($url, $headers, $method, $post_fields) {
  67. $ch = curl_init();
  68. curl_setopt($ch, CURLOPT_URL, $url);
  69. if($method == 'post' && !empty($post_fields)) {
  70. curl_setopt($ch, CURLOPT_POST, 1);
  71. curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
  72. } else {
  73. curl_setopt($ch, CURLOPT_HTTPGET, 1);
  74. }
  75. curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
  76. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  77. curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
  78. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  79. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  80. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  81. curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
  82. curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
  83. curl_setopt($ch, CURLOPT_TIMEOUT, 3);
  84. curl_setopt($ch, CURLOPT_VERBOSE, false);
  85. $response = curl_exec($ch);
  86. curl_close($ch);
  87. return $response;
  88. }
  89. /*--------------------------------------
  90. // Load pages into a DOM
  91. --------------------------------------*/
  92. function get_xpath($response) {
  93. if(!$response) return null;
  94. $htmlDom = new DOMDocument;
  95. @$htmlDom->loadHTML($response);
  96. $xpath = new DOMXPath($htmlDom);
  97. return $xpath;
  98. }
  99. /*--------------------------------------
  100. // Format search result urls
  101. --------------------------------------*/
  102. function get_formatted_url($url) {
  103. $url = parse_url($url);
  104. $formatted_url = $url['scheme'] . '://' . $url['host'];
  105. if(array_key_exists('path', $url)) {
  106. $formatted_url .= str_replace('/', ' &rsaquo; ', urldecode(str_replace('%20', ' ', rtrim($url['path'], '/'))));
  107. }
  108. return $formatted_url;
  109. }
  110. /*--------------------------------------
  111. // Get Goosle's base url
  112. --------------------------------------*/
  113. function get_base_url($siteurl) {
  114. // Figure out server protocol
  115. $protocol = empty($_SERVER['HTTPS']) ? 'http' : 'https';
  116. return $protocol.'://'.$siteurl;
  117. }
  118. /*--------------------------------------
  119. // URL Safe base64 encoding
  120. --------------------------------------*/
  121. function base64_url_encode($input) {
  122. return strtr(base64_encode($input), '+/=', '-_.');
  123. }
  124. function base64_url_decode($input) {
  125. return base64_decode(strtr($input, '-_.', '+/='));
  126. }
  127. function share_encode($opts, $magnet_hash) {
  128. return get_base_url($opts->siteurl).'/results.php?s='.base64_url_encode($opts->type.'||'.$opts->hash.'||'.$opts->query.'||'.$magnet_hash);
  129. }
  130. /*--------------------------------------
  131. // Result Caching
  132. --------------------------------------*/
  133. function has_cached_results($cache_type, $hash, $url, $ttl) {
  134. $ttl = intval($ttl * 3600); // Make it hours
  135. if($cache_type == 'apcu') {
  136. return apcu_exists($hash.':'.$url);
  137. }
  138. if($cache_type == 'file') {
  139. $cache_file = ABSPATH.'cache/'.md5($hash.':'.$url).'.result';
  140. if(is_file($cache_file)) {
  141. if(filemtime($cache_file) >= (time() - $ttl)) {
  142. return true;
  143. }
  144. }
  145. }
  146. return false;
  147. }
  148. function store_cached_results($cache_type, $hash, $url, $results, $ttl) {
  149. $ttl = intval($ttl * 3600); // Make it hours
  150. if($cache_type == 'apcu') {
  151. apcu_store($hash.':'.$url, $results, $ttl);
  152. }
  153. if($cache_type == 'file') {
  154. $cache_file = ABSPATH.'cache/'.md5($hash.':'.$url).'.result';
  155. file_put_contents($cache_file, serialize($results));
  156. }
  157. }
  158. function fetch_cached_results($cache_type, $hash, $url) {
  159. if($cache_type == 'apcu') {
  160. return apcu_fetch($hash.':'.$url);
  161. }
  162. if($cache_type == 'file') {
  163. $cache_file = ABSPATH.'cache/'.md5($hash.':'.$url).'.result';
  164. if(is_file($cache_file)) {
  165. return unserialize(file_get_contents($cache_file));
  166. }
  167. }
  168. return array();
  169. }
  170. function delete_cached_results($ttl) {
  171. $ttl = intval($ttl * 3600); // Make it hours
  172. $folder = ABSPATH.'cache/';
  173. if(is_dir($folder)) {
  174. if($handle = opendir($folder)) {
  175. // Loop through all files
  176. while(($file = readdir($handle)) !== false) {
  177. // Skip some of them
  178. $extension = pathinfo($file, PATHINFO_EXTENSION);
  179. if($file == '.' OR $file == '..' OR $extension != 'result') continue;
  180. // Delete if expired
  181. if(filemtime($folder.$file) < (time() - $ttl)) {
  182. unlink($folder.$file);
  183. }
  184. }
  185. closedir($handle);
  186. }
  187. }
  188. }
  189. /*--------------------------------------
  190. // Store generated tokens
  191. --------------------------------------*/
  192. function oauth_store_token($token_file, $connect, $token) {
  193. if(!is_file($token_file)){
  194. // Create token file
  195. file_put_contents($token_file, serialize(array($connect => $token)));
  196. } else {
  197. // Update token file
  198. $tokens = unserialize(file_get_contents($token_file));
  199. $tokens[$connect] = $token;
  200. file_put_contents($token_file, serialize($tokens));
  201. }
  202. }
  203. /*--------------------------------------
  204. // Sanitize/format variables
  205. --------------------------------------*/
  206. function sanitize($variable) {
  207. switch(gettype($variable)) {
  208. case 'string':
  209. $variable = htmlspecialchars(trim($variable), ENT_QUOTES);
  210. break;
  211. case 'integer':
  212. $variable = preg_replace('/[^0-9]/', '', $variable);
  213. if(strlen($variable) == 0) $variable = 0;
  214. break;
  215. case 'boolean':
  216. $variable = ($variable === FALSE) ? 0 : 1;
  217. break;
  218. default:
  219. $variable = ($variable === NULL) ? 'NULL' : htmlspecialchars(strip_tags(trim($variable)), ENT_QUOTES);
  220. break;
  221. }
  222. return $variable;
  223. }
  224. function strip_newlines($string) {
  225. return preg_replace('/<br>|\n/', '', $string);
  226. }
  227. function limit_string_length($string, $length = 100, $append = '&hellip;') {
  228. $string = trim($string);
  229. if(str_word_count($string, 0) > $length) {
  230. $words = str_word_count($string, 2);
  231. $pos = array_keys($words);
  232. $string = substr($string, 0, $pos[$length]) . $append;
  233. }
  234. return $string;
  235. }
  236. /*--------------------------------------
  237. // Search result match counter
  238. --------------------------------------*/
  239. function match_count($string, $query) {
  240. if(empty($string)) return 0;
  241. $string = strtolower($string);
  242. if(filter_var($string, FILTER_VALIDATE_URL)) {
  243. $string = preg_replace('/[^a-z0-9]+/', ' ', $string);
  244. }
  245. // Replace anything but alphanumeric with a space
  246. $string = preg_replace('/\s{2,}|[^a-z0-9]+/', ' ', $string);
  247. $matches = array_intersect(array_filter(array_unique(explode(' ', $string))), $query);
  248. $matches = count($matches);
  249. return $matches;
  250. }
  251. /*--------------------------------------
  252. // Detect social media results
  253. --------------------------------------*/
  254. function is_social_media($string) {
  255. $string = strtolower($string);
  256. // Borrowed from https://github.com/lorey/social-media-profiles-regexs
  257. if(preg_match('/(?:https?:)?\/\/(?:www\.)?(?:facebook|fb)\.com\/(?P<profile>(?![A-z]+\.php)(?!marketplace|gaming|watch|me|messages|help|search|groups)[A-z0-9_\-\.]+)\/?/', $string)
  258. || preg_match('/(?:https?:)?\/\/(?:www\.)facebook.com\/(?:profile.php\?id=)?(?P<id>[0-9]+)/', $string)
  259. || preg_match('/(?:https?:)?\/\/(?:www\.)?(?:instagram\.com|instagr\.am)\/(?P<username>[A-Za-z0-9_](?:(?:[A-Za-z0-9_]|(?:\.(?!\.))){0,28}(?:[A-Za-z0-9_]))?)/', $string)
  260. || preg_match('/(?:https?:)?\/\/(?:[A-z]+\.)?twitter\.com\/@?(?P<username>[A-z0-9_]+)\/status\/(?P<tweet_id>[0-9]+)\/?/', $string)
  261. || preg_match('/(?:https?:)?\/\/(?:[A-z]+\.)?twitter\.com\/@?(?!home|share|privacy|tos)(?P<username>[A-z0-9_]+)\/?/', $string)
  262. || preg_match('/(?:https?:)?\/\/(?:[a-z]+\.)?reddit\.com\/(?:u(?:ser)?)\/(?P<username>[A-z0-9\-\_]*)\/?/', $string)
  263. || preg_match('/(?:https?:)?\/\/(?:www\.)?snapchat\.com\/add\/(?P<username>[A-z0-9\.\_\-]+)\/?/', $string)
  264. || preg_match('/^.*https:\/\/(?:m|www|vm)?\.?tiktok\.com\/((?:.*\b(?:(?:usr|v|embed|user|video)\/|\?shareId=|\&item_id=)(\d+))|\w+)/', $string)
  265. || preg_match('/(?:https?:)?\/\/(?:[\w]+\.)?linkedin\.com\/(?P<company_type>(company)|(school))\/(?P<company_permalink>[A-z0-9-À-ÿ\.]+)\/?/', $string)
  266. || preg_match('/(?:https?:)?\/\/(?:[\w]+\.)?linkedin\.com\/feed\/update\/urn:li:activity:(?P<activity_id>[0-9]+)\/?/', $string)
  267. || preg_match('/(?:https?:)?\/\/(?:[\w]+\.)?linkedin\.com\/in\/(?P<permalink>[\w\-\_À-ÿ%]+)\/?/', $string)
  268. // || preg_match('/(?:https?:)?\/\/(?:[A-z]+\.)?youtube.com\/(?:c(?:hannel)?)\/(?P<id>[A-z0-9-\_]+)\/?/', $string)
  269. || preg_match('/(?:https?:)?\/\/(?:[A-z]+\.)?youtube.com\/(?:u(?:ser)?)\/(?P<username>[A-z0-9]+)\/?/', $string)
  270. // || preg_match('/(?:https?:)?\/\/(?:(?:www\.)?youtube\.com\/(?:watch\?v=|embed\/)|youtu\.be\/)(?P<id>[A-z0-9\-\_]+)/', $string)
  271. ) return true;
  272. return false;
  273. }
  274. /*--------------------------------------
  275. // Search suggestions
  276. --------------------------------------*/
  277. function search_suggestion($opts, $results) {
  278. $specific_result = $specific_result2 = '';
  279. if(array_key_exists('search_specific', $results)) {
  280. if($opts->type == 3 && count($results['search_specific']) > 1) {
  281. // Format query url
  282. $search_specific_url2 = './results.php?q='.urlencode($results['search_specific'][1]).'&t='.$opts->type.'&a='.$opts->hash;
  283. $specific_result2 = ' or <a href="'.$search_specific_url2.'">'.$results['search_specific'][1].'</a>';
  284. }
  285. // Format query url
  286. $search_specific_url = './results.php?q='.urlencode($results['search_specific'][0]).'&t='.$opts->type.'&a='.$opts->hash;
  287. $specific_result = '<br /><small>Or instead search for <a href="'.$search_specific_url.'">'.$results['search_specific'][0].'</a>'.$specific_result2.'.</small>';
  288. unset($search_specific_url, $search_specific_url2, $specific_result2);
  289. }
  290. return $specific_result;
  291. }
  292. /*--------------------------------------
  293. // Count and format search sources
  294. --------------------------------------*/
  295. function search_sources($results) {
  296. $sources = array();
  297. foreach($results as $source => $amount) {
  298. $plural = ($amount > 1) ? 'results' : 'result';
  299. $sources[] = $amount.' '.$plural.' from '.$source;
  300. }
  301. $sources = replace_last_comma(implode(', ', $sources));
  302. $sources = 'Includes '.$sources.'.';
  303. return $sources;
  304. }
  305. /*--------------------------------------
  306. // Find and replace the last comma in a string
  307. --------------------------------------*/
  308. function replace_last_comma($string) {
  309. $last_comma = strrpos($string, ', ');
  310. if($last_comma !== false) {
  311. $string = substr_replace($string, ' and ', $last_comma, 2);
  312. }
  313. return $string;
  314. }
  315. /*--------------------------------------
  316. // Human readable file sizes from bytes
  317. --------------------------------------*/
  318. function human_filesize($bytes, $dec = 2) {
  319. $size = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
  320. $factor = floor((strlen($bytes) - 1) / 3);
  321. return sprintf("%.{$dec}f ", $bytes / pow(1024, $factor)) . @$size[$factor];
  322. }
  323. /*--------------------------------------
  324. // Apply timezone setting
  325. --------------------------------------*/
  326. function timezone_offset($timestamp, $timezone_offset) {
  327. if(strpos($timezone_offset, 'UTC') === false) return $timestamp;
  328. if($timezone_offset == 'UTC') return $timestamp;
  329. $timezone_offset = intval(substr($timezone_offset, 3));
  330. if($timezone_offset > 0) {
  331. return abs($timestamp + (intval(substr($timezone_offset, 1)) * 3600));
  332. }
  333. if($timezone_offset < 0) {
  334. return abs($timestamp - (intval(substr($timezone_offset, 1)) * 3600));
  335. }
  336. }
  337. /*--------------------------------------
  338. // Turn a string size (600 MB) into bytes (int)
  339. --------------------------------------*/
  340. function filesize_to_bytes($num) {
  341. preg_match('/(b|kb|mb|gb|tb|pb|eb|zb|yb)/', strtolower($num), $match);
  342. $num = floatval(preg_replace('/[^0-9.]+/', '', $num));
  343. $match = $match[0];
  344. if($match == 'kb') {
  345. $num = $num * 1024;
  346. } else if($match == 'mb') {
  347. $num = $num * pow(1024, 2);
  348. } else if($match == 'gb') {
  349. $num = $num * pow(1024, 3);
  350. } else if($match == 'tb') {
  351. $num = $num * pow(1024, 4);
  352. } else if($match == 'pb') {
  353. $num = $num * pow(1024, 5);
  354. } else if($match == 'eb') {
  355. $num = $num * pow(1024, 6);
  356. } else if($match == 'zb') {
  357. $num = $num * pow(1024, 7);
  358. } else if($match == 'yb') {
  359. $num = $num * pow(1024, 8);
  360. } else {
  361. $num = $num;
  362. }
  363. return intval($num);
  364. }
  365. /*--------------------------------------
  366. // Generate random strings for passwords
  367. --------------------------------------*/
  368. function string_generator($length, $separator) {
  369. $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
  370. $password = array();
  371. $rand = strlen($characters) - 1;
  372. for($i = 0; $i < $length; $i++) {
  373. $n = rand(0, $rand);
  374. $password[] = $characters[$n];
  375. }
  376. if(!empty($separator)) {
  377. array_splice($password, 6, 0, $separator);
  378. array_splice($password, 13, 0, $separator);
  379. array_splice($password, 20, 0, $separator);
  380. }
  381. return implode($password);
  382. }
  383. ?>