index.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. <?php
  2. header('HTTP/1.1 404 Not Found');
  3. header('Referrer-Policy: no-referrer');
  4. define('NOWTIME_U', gmdate('U'));
  5. $vi_json = $_GET['json']??$_POST['json'];
  6. $vi_query = $_GET['q']??$_POST['q'];
  7. $vi_opt_sm = ($_GET['sm'] == 'a' || $_POST['sm'] == 'a') ? 'a' : 't';
  8. $vi_opt_inclcf = $_GET['cf']??$_POST['cf'];
  9. $vi_opt_inclcf = isset($vi_opt_inclcf) ? true : false;
  10. $vi_opt_limitlg = $_GET['lg']??$_POST['lg'];
  11. if (!preg_match("/^([a-z]{2})$/", $vi_opt_limitlg)) {
  12. $vi_opt_limitlg = '';
  13. }
  14. $vi_opt_timeA = $_GET['tia']??$_POST['tia'];
  15. if (!preg_match("/^2([0-9]{3})\-([0-9]{2})\-([0-9]{2})$/", $vi_opt_timeA)) {
  16. $vi_opt_timeA = '';
  17. } //A->
  18. $vi_opt_timeB = $_GET['tib']??$_POST['tib'];
  19. if (!preg_match("/^2([0-9]{3})\-([0-9]{2})\-([0-9]{2})$/", $vi_opt_timeB)) {
  20. $vi_opt_timeB = '';
  21. } //<-B
  22. $vi_internal_tia = $vi_internal_tib = '';
  23. if ($vi_opt_timeA != '') {
  24. $vi_internal_tia = gmdate('U', strtotime($vi_opt_timeA . ' 00:00:00'));
  25. if ($vi_internal_tia > NOWTIME_U) {
  26. $vi_internal_tia = NOWTIME_U;
  27. }
  28. }
  29. if ($vi_opt_timeB != '') {
  30. $vi_internal_tib = gmdate('U', strtotime($vi_opt_timeB . ' 23:59:59'));
  31. if ($vi_internal_tib > NOWTIME_U) {
  32. $vi_internal_tib = NOWTIME_U;
  33. }
  34. }
  35. if (isset($vi_query)) {
  36. $vi_query = cleanse_str($vi_query);
  37. if (is_attackable_str($vi_query)) {
  38. $vi_query = '';
  39. }
  40. }
  41. $vi_showquery = htmlspecialchars($vi_query, ENT_QUOTES);
  42. $sql_Result = [];
  43. if (strlen($vi_query) >= 2) {
  44. $sqlme = @new mysqli('localhost', 'REDACTED', 'REDACTED', 'REDACTED');
  45. if ($sqlme->connect_errno) {
  46. echo ('DB ERROR TRY AGAIN LATER');
  47. exit;
  48. }
  49. $sql_Query = 'SELECT * FROM REDACTED WHERE ';
  50. $sql_Pcs = [];
  51. $sql_smt = ($vi_opt_sm == 'a') ? 'who' : 'body';
  52. if (!$vi_opt_inclcf) {
  53. $sql_Pcs[] = "iscf = '0' ";
  54. }
  55. if ($vi_opt_limitlg != '') {
  56. $sql_Pcs[] = "lang = '{$vi_opt_limitlg}' ";
  57. }
  58. if ($vi_internal_tia != '') {
  59. $sql_Pcs[] = "`when` >= '{$vi_internal_tia}' ";
  60. }
  61. if ($vi_internal_tib != '') {
  62. $sql_Pcs[] = "`when` <= '{$vi_internal_tib}' ";
  63. }
  64. foreach (explode(' ', $vi_query) as $w) {
  65. if (strlen($w) <= 1) {
  66. continue;
  67. }
  68. if (strpos($w, 'author:') === 0) {
  69. $w = str_replace('author:', '', $w);
  70. if (strlen($w) < 2) {
  71. continue;
  72. }
  73. $sql_Pcs[] = "who LIKE '%{$w}%' ";
  74. continue;
  75. }
  76. if (strpos($w, '-author:') === 0) {
  77. $w = str_replace('-author:', '', $w);
  78. if (strlen($w) < 2) {
  79. continue;
  80. }
  81. $sql_Pcs[] = "who NOT LIKE '%{$w}%' ";
  82. continue;
  83. }
  84. if (strpos($w, '-') === 0) {
  85. $w = str_replace('-', '', $w);
  86. if (strlen($w) < 2) {
  87. continue;
  88. }
  89. $sql_Pcs[] = "{$sql_smt} NOT LIKE '%{$w}%' ";
  90. continue;
  91. }
  92. $sql_Pcs[] = "{$sql_smt} LIKE '%{$w}%' ";
  93. }
  94. if ($result = $sqlme->query($sql_Query . implode('AND ', $sql_Pcs) . ' ORDER BY `when` DESC LIMIT 500;')) {
  95. while ($g = $result->fetch_array()) {
  96. $sql_Result[] = $g;
  97. }
  98. }
  99. $sqlme->close();
  100. }
  101. if (isset($vi_json)) {
  102. header('Content-Type: application/json; charset=utf-8');
  103. $finalRESP = [];
  104. if ($vi_showquery == '') {
  105. $finalRESP = ['method' => ['POST', 'GET'], 'accept_param' => ['q' => ['type' => 'string', 'value' => 'any', 'note' => 'Required'], 'sm' => ['type' => 'string', 'value' => ['a' => 'Account', 't' => 'Toot'], 'note' => 'default is t'], 'cf' => ['type' => 'existence', 'value' => 'any'], 'lg' => ['type' => 'string', 'value' => '2 letter'], 'tia' => ['type' => 'date', 'value' => 'Y-m-d'], 'tib' => ['type' => 'date', 'value' => 'Y-m-d']], 'example' => ['GET' => ['/?json&q=friend', '/?json&cf&lg=en&q=news']]];
  106. } else {
  107. foreach ($sql_Result as $g) {
  108. $finalRESP[] = ['url' => $g['url'], 'who' => $g['who'], 'when' => $g['when'], 'iscf' => $g['iscf'], 'lang' => $g['lang'], 'body' => str_replace('&nbsp;', ' ', $g['body']) ];
  109. }
  110. }
  111. echo (json_encode($finalRESP));
  112. exit;
  113. } else {
  114. header('Content-Type: text/html; charset=UTF-8');
  115. $finalRESP = '';
  116. foreach ($sql_Result as $g) {
  117. $finalRESP.= '<tr><td class="sh"><a href="' . $g['url'] . '" rel="noreferer" target="_blank">' . $g['who'] . '</a>' . ($g['iscf'] ? '&#127785;' : '') . '<br><i>' . humanTiming($g['when']) . ' ago / ' . $g['lang'] . '</i></td><td class="xp">' . htmlspecialchars(htmlspecialchars_decode(str_replace('&nbsp;', ' ', $g['body']), ENT_QUOTES), ENT_QUOTES) . '</td></tr>';
  118. }
  119. $ui_sma = ($vi_opt_sm == 'a') ? ['', ' selected'] : [' selected', ''];
  120. $ui_cfc = ($vi_opt_inclcf) ? ' checked' : '';
  121. $finish = <<<HTMLDATA
  122. <html>
  123. <head>
  124. <title>&#x1F418;</title>
  125. <style>
  126. html{background:#f3f6fa}div#ha{background:#e4e9f0;position:fixed;top:0;left:0;right:0;padding:18px 0;z-index:10}div#ha form{padding:0 20px}div#ub{margin-top:40px;background:#e4e9f0;position:absolute;left:0;right:0}details summary,button[type=submit]{cursor:pointer}form input[name=q],button[type=submit]{font-size:20px}button[type=submit]{background:transparent;border:0}div#mb table{width:80%;border-collapse:collapse}div#mb table tr:nth-child(2n){background:#f8fbff}div#mb td.sh{white-space:nowrap}div#mb td.xp{width:99%;padding:10px 0 10px 20px;word-wrap:anywhere}
  127. </style>
  128. </head>
  129. <body>
  130. <div id="ha">
  131. <form action="./" method="POST">
  132. <input type="text" name="q" size="60" minlength="2" value="{$vi_showquery}" autofocus required>
  133. <button type="submit">&#x1F50E;</button><br>
  134. <details>
  135. <summary>Advanced</summary>
  136. <p>
  137. Search mode: <select name="sm">
  138. <option value="t"{$ui_sma[0]}>Toots</option>
  139. <option value="a"{$ui_sma[1]}>Account</option>
  140. </select><br>
  141. <br><br>
  142. <label><input type="checkbox" name="cf"{$ui_cfc}> Include <a href="http://crimeflare.eu.org/" target="_blank">Cloudflared Mastodon</a> servers to search result</label><br>
  143. <br><br>
  144. Limit language code: <input type="text" name="lg" size="4" minlength="2" maxlength="2" value="{$vi_opt_limitlg}"> (e.g <i>de</i>)<br>
  145. <br><br>
  146. Limit time range:<br>
  147. <label for="tia">Newer than </label><input type="date" id="tia" name="tia" value="{$vi_opt_timeA}"><br>
  148. <label for="tib">Older than </label><input type="date" id="tib" name="tib" value="{$vi_opt_timeB}"><br>
  149. <br>
  150. <hr>
  151. <ul>
  152. <li> cat pic (search toots about "cat" and "pic")</li>
  153. <li> my friend <b>-</b>enemy <b>-</b>joke (search "my" and "friend" toots but not include "enemy" "joke")</li>
  154. <li> news <b>-author</b>:bot <b>-author</b>:blog (search "news" but not from author named "*bot*" "*blog*")</li>
  155. <li> <b>author</b>:friend@my.site (show only about friend@my.site)</li>
  156. <li> Max limit: 500 search results</li>
  157. </ul>
  158. </p>
  159. </details>
  160. </form>
  161. </div>
  162. <br><br><br><br><br><br><br><br>
  163. <div id="mb">
  164. <table>{$finalRESP}</table>
  165. </div>
  166. <div id="ub">
  167. <ul>
  168. <li> Search: Mastodon public toots & Accounts</li>
  169. <li> API: <a href="./?json">API guide</a></li>
  170. <li> Index: Toots older than 7 months will be removed</li>
  171. <li> Privacy: No collection (search keyword, IP, whatever)</li>
  172. <li> <a href="http://qyo4hcmvxiysc6zrxdn6rhofgkroyoygszkljw5izwdqklxfantseiyd.onion/">Tor</a>
  173. </ul>
  174. </div>
  175. </body>
  176. </html>
  177. HTMLDATA;
  178. }
  179. echo (str_replace("\n", '', $finish));