BioTorrents.de’s version of Gazelle
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

advancedsearch.php 39KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  1. <?php
  2. #declare(strict_types = 1);
  3. $ENV = ENV::go();
  4. if (!empty($_GET['search'])) {
  5. if (preg_match('/^'.$ENV->IP_REGEX.'$/', $_GET['search'])) {
  6. $_GET['ip'] = $_GET['search'];
  7. } elseif (preg_match('/^'.EMAIL_REGEX.'$/i', $_GET['search'])) {
  8. $_GET['email'] = $_GET['search'];
  9. } elseif (preg_match(USERNAME_REGEX, $_GET['search'])) {
  10. $DB->query("
  11. SELECT ID
  12. FROM users_main
  13. WHERE Username = '".db_string($_GET['search'])."'");
  14. if (list($ID) = $DB->next_record()) {
  15. header("Location: user.php?id=$ID");
  16. error();
  17. }
  18. $_GET['username'] = $_GET['search'];
  19. } else {
  20. $_GET['comment'] = $_GET['search'];
  21. }
  22. }
  23. define('USERS_PER_PAGE', 30);
  24. function wrap($String, $ForceMatch = '', $IPSearch = false)
  25. {
  26. if (!$ForceMatch) {
  27. global $Match;
  28. } else {
  29. $Match = $ForceMatch;
  30. }
  31. if ($Match == ' REGEXP ') {
  32. if (strpos($String, '\'') !== false || preg_match('/^.*\\\\$/i', $String)) {
  33. error('Regex contains illegal characters.');
  34. }
  35. } else {
  36. $String = db_string($String);
  37. }
  38. if ($Match == ' LIKE ') {
  39. // Fuzzy search
  40. // Stick in wildcards at beginning and end of string unless string starts or ends with |
  41. if (($String[0] != '|') && !$IPSearch) {
  42. $String = "%$String";
  43. } elseif ($String[0] == '|') {
  44. $String = substr($String, 1, strlen($String));
  45. }
  46. if (substr($String, -1, 1) != '|') {
  47. $String = "$String%";
  48. } else {
  49. $String = substr($String, 0, -1);
  50. }
  51. }
  52. $String = "'$String'";
  53. return $String;
  54. }
  55. function date_compare($Field, $Operand, $Date1, $Date2 = '')
  56. {
  57. $Date1 = db_string($Date1);
  58. $Date2 = db_string($Date2);
  59. $Return = [];
  60. switch ($Operand) {
  61. case 'on':
  62. $Return [] = " $Field >= '$Date1 00:00:00' ";
  63. $Return [] = " $Field <= '$Date1 23:59:59' ";
  64. break;
  65. case 'before':
  66. $Return [] = " $Field < '$Date1 00:00:00' ";
  67. break;
  68. case 'after':
  69. $Return [] = " $Field > '$Date1 23:59:59' ";
  70. break;
  71. case 'between':
  72. $Return [] = " $Field >= '$Date1 00:00:00' ";
  73. $Return [] = " $Field <= '$Date2 00:00:00' ";
  74. break;
  75. }
  76. return $Return;
  77. }
  78. function num_compare($Field, $Operand, $Num1, $Num2 = '')
  79. {
  80. if ($Num1 != 0) {
  81. $Num1 = db_string($Num1);
  82. }
  83. if ($Num2 != 0) {
  84. $Num2 = db_string($Num2);
  85. }
  86. $Return = [];
  87. switch ($Operand) {
  88. case 'equal':
  89. $Return [] = " $Field = '$Num1' ";
  90. break;
  91. case 'above':
  92. $Return [] = " $Field > '$Num1' ";
  93. break;
  94. case 'below':
  95. $Return [] = " $Field < '$Num1' ";
  96. break;
  97. case 'between':
  98. $Return [] = " $Field > '$Num1' ";
  99. $Return [] = " $Field < '$Num2' ";
  100. break;
  101. default:
  102. print_r($Return);
  103. error();
  104. }
  105. return $Return;
  106. }
  107. // Arrays, regexes, and all that fun stuff we can use for validation, form generation, etc
  108. $DateChoices = array('inarray'=>array('on', 'before', 'after', 'between'));
  109. $SingleDateChoices = array('inarray'=>array('on', 'before', 'after'));
  110. $NumberChoices = array('inarray'=>array('equal', 'above', 'below', 'between', 'buffer'));
  111. $YesNo = array('inarray'=>array('any', 'yes', 'no'));
  112. $OrderVals = array('inarray'=>array('Username', 'Ratio', 'IP', 'Email', 'Joined', 'Last Seen', 'Uploaded', 'Downloaded', 'Invites', 'Snatches'));
  113. $WayVals = array('inarray'=>array('Ascending', 'Descending'));
  114. if (count($_GET)) {
  115. $DateRegex = array('regex' => '/\d{4}-\d{2}-\d{2}/');
  116. $ClassIDs = [];
  117. $SecClassIDs = [];
  118. foreach ($Classes as $ClassID => $Value) {
  119. if ($Value['Secondary']) {
  120. $SecClassIDs[] = $ClassID;
  121. } else {
  122. $ClassIDs[] = $ClassID;
  123. }
  124. }
  125. $Val->SetFields('comment', '0', 'string', 'Comment is too long.', array('maxlength' => 512));
  126. $Val->SetFields('disabled_invites', '0', 'inarray', 'Invalid disabled_invites field', $YesNo);
  127. $Val->SetFields('joined', '0', 'inarray', 'Invalid joined field', $DateChoices);
  128. $Val->SetFields('join1', '0', 'regex', 'Invalid join1 field', $DateRegex);
  129. $Val->SetFields('join2', '0', 'regex', 'Invalid join2 field', $DateRegex);
  130. $Val->SetFields('lastactive', '0', 'inarray', 'Invalid lastactive field', $DateChoices);
  131. $Val->SetFields('lastactive1', '0', 'regex', 'Invalid lastactive1 field', $DateRegex);
  132. $Val->SetFields('lastactive2', '0', 'regex', 'Invalid lastactive2 field', $DateRegex);
  133. $Val->SetFields('ratio', '0', 'inarray', 'Invalid ratio field', $NumberChoices);
  134. $Val->SetFields('uploaded', '0', 'inarray', 'Invalid uploaded field', $NumberChoices);
  135. $Val->SetFields('downloaded', '0', 'inarray', 'Invalid downloaded field', $NumberChoices);
  136. //$Val->SetFields('snatched', '0', 'inarray', 'Invalid snatched field', $NumberChoices);
  137. $Val->SetFields('matchtype', '0', 'inarray', 'Invalid matchtype field', array('inarray' => array('strict', 'fuzzy', 'regex')));
  138. $Val->SetFields('lockedaccount', '0', 'inarray', 'Invalid locked account field', array('inarray' => array('any', 'locked', 'unlocked')));
  139. $Val->SetFields('enabled', '0', 'inarray', 'Invalid enabled field', array('inarray' => array('', 0, 1, 2)));
  140. $Val->SetFields('class', '0', 'inarray', 'Invalid class', array('inarray' => $ClassIDs));
  141. $Val->SetFields('secclass', '0', 'inarray', 'Invalid class', array('inarray' => $SecClassIDs));
  142. $Val->SetFields('donor', '0', 'inarray', 'Invalid donor field', $YesNo);
  143. $Val->SetFields('warned', '0', 'inarray', 'Invalid warned field', $YesNo);
  144. $Val->SetFields('disabled_uploads', '0', 'inarray', 'Invalid disabled_uploads field', $YesNo);
  145. $Val->SetFields('order', '0', 'inarray', 'Invalid ordering', $OrderVals);
  146. $Val->SetFields('way', '0', 'inarray', 'Invalid way', $WayVals);
  147. $Val->SetFields('passkey', '0', 'string', 'Invalid passkey', array('maxlength' => 32));
  148. $Val->SetFields('avatar', '0', 'string', 'Avatar URL too long', array('maxlength' => 512));
  149. $Val->SetFields('stylesheet', '0', 'inarray', 'Invalid stylesheet', array_unique(array_keys($Stylesheets)));
  150. $Val->SetFields('cc', '0', 'inarray', 'Invalid Country Code', array('maxlength' => 2));
  151. $Err = $Val->ValidateForm($_GET);
  152. if (!$Err) {
  153. // Passed validation. Let's rock.
  154. $RunQuery = false; // if we should run the search
  155. if (isset($_GET['matchtype']) && $_GET['matchtype'] == 'strict') {
  156. $Match = ' = ';
  157. } elseif (isset($_GET['matchtype']) && $_GET['matchtype'] == 'regex') {
  158. $Match = ' REGEXP ';
  159. } else {
  160. $Match = ' LIKE ';
  161. }
  162. $OrderTable = array(
  163. 'Username' => 'um1.Username',
  164. 'Joined' => 'ui1.JoinDate',
  165. 'Email' => 'um1.Email',
  166. 'IP' => 'um1.IP',
  167. 'Last Seen' => 'um1.LastAccess',
  168. 'Uploaded' => 'um1.Uploaded',
  169. 'Downloaded' => 'um1.Downloaded',
  170. 'Ratio' => '(um1.Uploaded / um1.Downloaded)',
  171. 'Invites' => 'um1.Invites',
  172. 'Snatches' => 'Snatches');
  173. $WayTable = array('Ascending'=>'ASC', 'Descending'=>'DESC');
  174. $Where = [];
  175. $Having = [];
  176. $Join = [];
  177. $Group = [];
  178. $Distinct = '';
  179. $Order = '';
  180. $SQL = '
  181. SQL_CALC_FOUND_ROWS
  182. um1.ID,
  183. um1.Username,
  184. um1.Uploaded,
  185. um1.Downloaded,';
  186. if ($_GET['snatched'] == 'off') {
  187. $SQL .= "'X' AS Snatches,";
  188. } else {
  189. $SQL .= "
  190. (
  191. SELECT COUNT(xs.uid)
  192. FROM xbt_snatched AS xs
  193. WHERE xs.uid = um1.ID
  194. ) AS Snatches,";
  195. }
  196. if ($_GET['invitees'] == 'off') {
  197. $SQL .= "'X' AS Invitees,";
  198. } else {
  199. $SQL .= "
  200. (
  201. SELECT COUNT(ui2.UserID)
  202. FROM users_info AS ui2
  203. WHERE um1.ID = ui2.Inviter
  204. ) AS Invitees,";
  205. }
  206. $SQL .= '
  207. um1.PermissionID,
  208. um1.Email,
  209. um1.Enabled,
  210. um1.IP,
  211. um1.Invites,
  212. ui1.DisableInvites,
  213. ui1.Warned,
  214. ui1.Donor,
  215. ui1.JoinDate,
  216. um1.LastAccess
  217. FROM users_main AS um1
  218. JOIN users_info AS ui1 ON ui1.UserID = um1.ID ';
  219. if (!empty($_GET['username'])) {
  220. $Where[] = 'um1.Username'.$Match.wrap($_GET['username']);
  221. }
  222. if (!empty($_GET['email'])) {
  223. $Join['the'] = ' JOIN users_emails_decrypted AS he ON he.ID = um1.ID ';
  224. $Where[] = ' he.Email '.$Match.wrap($_GET['email']);
  225. }
  226. if (!empty($_GET['ip'])) {
  227. $Join['tip'] = ' JOIN users_ips_decrypted AS tip ON tip.ID = um1.ID ';
  228. $Where[] = ' tip.IP '.$Match.wrap($_GET['ip'], '', true);
  229. }
  230. if ($_GET['lockedaccount'] != '' && $_GET['lockedaccount'] != 'any') {
  231. $Join['la'] = '';
  232. if ($_GET['lockedaccount'] == 'unlocked') {
  233. $Join['la'] .= ' LEFT';
  234. $Where[] = ' la.UserID IS NULL';
  235. }
  236. $Join['la'] .= ' JOIN locked_accounts AS la ON la.UserID = um1.ID ';
  237. }
  238. if (!empty($_GET['tracker_ip'])) {
  239. $Distinct = 'DISTINCT ';
  240. $Join['xfu'] = ' JOIN xbt_files_users AS xfu ON um1.ID = xfu.uid ';
  241. $Where[] = ' xfu.ip '.$Match.wrap($_GET['tracker_ip'], '', true);
  242. }
  243. // if (!empty($_GET['tracker_ip'])) {
  244. // $Distinct = 'DISTINCT ';
  245. // $Join['xs'] = ' JOIN xbt_snatched AS xs ON um1.ID = xs.uid ';
  246. // $Where[] = ' xs.IP '.$Match.wrap($_GET['ip']);
  247. // }
  248. if (!empty($_GET['comment'])) {
  249. $Where[] = 'ui1.AdminComment'.$Match.wrap($_GET['comment']);
  250. }
  251. if (strlen($_GET['invites1'])) {
  252. $Invites1 = round($_GET['invites1']);
  253. $Invites2 = round($_GET['invites2']);
  254. $Where[] = implode(' AND ', num_compare('Invites', $_GET['invites'], $Invites1, $Invites2));
  255. }
  256. if (strlen($_GET['invitees1']) && $_GET['invitees'] != 'off') {
  257. $Invitees1 = round($_GET['invitees1']);
  258. $Invitees2 = round($_GET['invitees2']);
  259. $Having[] = implode(' AND ', num_compare('Invitees', $_GET['invitees'], $Invitees1, $Invitees2));
  260. }
  261. if ($_GET['disabled_invites'] == 'yes') {
  262. $Where[] = 'ui1.DisableInvites = \'1\'';
  263. } elseif ($_GET['disabled_invites'] == 'no') {
  264. $Where[] = 'ui1.DisableInvites = \'0\'';
  265. }
  266. if ($_GET['disabled_uploads'] == 'yes') {
  267. $Where[] = 'ui1.DisableUpload = \'1\'';
  268. } elseif ($_GET['disabled_uploads'] == 'no') {
  269. $Where[] = 'ui1.DisableUpload = \'0\'';
  270. }
  271. if ($_GET['join1']) {
  272. $Where[] = implode(' AND ', date_compare('ui1.JoinDate', $_GET['joined'], $_GET['join1'], $_GET['join2']));
  273. }
  274. if ($_GET['lastactive1']) {
  275. $Where[] = implode(' AND ', date_compare('um1.LastAccess', $_GET['lastactive'], $_GET['lastactive1'], $_GET['lastactive2']));
  276. }
  277. if ($_GET['ratio1']) {
  278. $Decimals = strlen(array_pop(explode('.', $_GET['ratio1'])));
  279. if (!$Decimals) {
  280. $Decimals = 0;
  281. }
  282. $Where[] = implode(' AND ', num_compare("ROUND(Uploaded/Downloaded,$Decimals)", $_GET['ratio'], $_GET['ratio1'], $_GET['ratio2']));
  283. }
  284. if (strlen($_GET['uploaded1'])) {
  285. $Upload1 = round($_GET['uploaded1']);
  286. $Upload2 = round($_GET['uploaded2']);
  287. if ($_GET['uploaded'] != 'buffer') {
  288. $Where[] = implode(' AND ', num_compare('ROUND(Uploaded / 1024 / 1024 / 1024)', $_GET['uploaded'], $Upload1, $Upload2));
  289. } else {
  290. $Where[] = implode(' AND ', num_compare('ROUND((Uploaded / 1024 / 1024 / 1024) - (Downloaded / 1024 / 1024 / 1023))', 'between', $Upload1 * 0.9, $Upload1 * 1.1));
  291. }
  292. }
  293. if (strlen($_GET['downloaded1'])) {
  294. $Download1 = round($_GET['downloaded1']);
  295. $Download2 = round($_GET['downloaded2']);
  296. $Where[] = implode(' AND ', num_compare('ROUND(Downloaded / 1024 / 1024 / 1024)', $_GET['downloaded'], $Download1, $Download2));
  297. }
  298. if (strlen($_GET['snatched1'])) {
  299. $Snatched1 = round($_GET['snatched1']);
  300. $Snatched2 = round($_GET['snatched2']);
  301. $Having[] = implode(' AND ', num_compare('Snatches', $_GET['snatched'], $Snatched1, $Snatched2));
  302. }
  303. if ($_GET['enabled'] != '') {
  304. $Where[] = 'um1.Enabled = '.wrap($_GET['enabled'], '=');
  305. }
  306. if ($_GET['class'] != '') {
  307. $Where[] = 'um1.PermissionID = '.wrap($_GET['class'], '=');
  308. }
  309. if ($_GET['secclass'] != '') {
  310. $Join['ul'] = ' JOIN users_levels AS ul ON um1.ID = ul.UserID ';
  311. $Where[] = 'ul.PermissionID = '.wrap($_GET['secclass'], '=');
  312. }
  313. if ($_GET['donor'] == 'yes') {
  314. $Where[] = 'ui1.Donor = \'1\'';
  315. } elseif ($_GET['donor'] == 'no') {
  316. $Where[] = 'ui1.Donor = \'0\'';
  317. }
  318. if ($_GET['warned'] == 'yes') {
  319. $Where[] = 'ui1.Warned IS NOT NULL';
  320. } elseif ($_GET['warned'] == 'no') {
  321. $Where[] = 'ui1.Warned IS NULL';
  322. }
  323. if ($_GET['disabled_ip']) {
  324. $Distinct = 'DISTINCT ';
  325. $Join['um2'] = ' JOIN users_main AS um2 ON um2.IP = um1.IP AND um2.Enabled = \'2\' ';
  326. }
  327. if (!empty($_GET['passkey'])) {
  328. $Where[] = 'um1.torrent_pass'.$Match.wrap($_GET['passkey']);
  329. }
  330. if (!empty($_GET['avatar'])) {
  331. $Where[] = 'ui1.Avatar'.$Match.wrap($_GET['avatar']);
  332. }
  333. if ($_GET['stylesheet'] != '') {
  334. $Where[] = 'ui1.StyleID = '.wrap($_GET['stylesheet'], '=');
  335. }
  336. if ($OrderTable[$_GET['order']] && $WayTable[$_GET['way']]) {
  337. $Order = ' ORDER BY '.$OrderTable[$_GET['order']].' '.$WayTable[$_GET['way']].' ';
  338. }
  339. //---------- Finish generating the search string
  340. $SQL = 'SELECT '.$Distinct.$SQL;
  341. $SQL .= implode(' ', $Join);
  342. if (count($Where)) {
  343. $SQL .= ' WHERE '.implode(' AND ', $Where);
  344. }
  345. if (count($Group)) {
  346. $SQL .= " GROUP BY " . implode(' ,', $Group);
  347. }
  348. if (count($Having)) {
  349. $SQL .= ' HAVING '.implode(' AND ', $Having);
  350. }
  351. $SQL .= $Order;
  352. if (count($Where) > 0 || count($Join) > 0 || count($Having) > 0) {
  353. $RunQuery = true;
  354. }
  355. list($Page, $Limit) = Format::page_limit(USERS_PER_PAGE);
  356. $SQL .= " LIMIT $Limit";
  357. } else {
  358. error($Err);
  359. }
  360. }
  361. View::show_header('User search');
  362. ?>
  363. <div>
  364. <form class="search_form" name="users" action="user.php" method="get">
  365. <input type="hidden" name="action" value="search" />
  366. <table class="layout">
  367. <tr>
  368. <td class="label nobr">Username:</td>
  369. <td width="24%">
  370. <input type="text" name="username" size="20"
  371. value="<?=display_str($_GET['username'])?>" />
  372. </td>
  373. <td class="label nobr">Joined:</td>
  374. <td width="24%">
  375. <select name="joined">
  376. <option value="on" <?php if ($_GET['joined'] === 'on') {
  377. echo ' selected="selected"';
  378. } ?>>On
  379. </option>
  380. <option value="before" <?php if ($_GET['joined'] === 'before') {
  381. echo ' selected="selected"';
  382. } ?>>Before
  383. </option>
  384. <option value="after" <?php if ($_GET['joined'] === 'after') {
  385. echo ' selected="selected"';
  386. } ?>>After
  387. </option>
  388. <option value="between" <?php if ($_GET['joined']==='between') {
  389. echo ' selected="selected"' ;
  390. } ?>>Between
  391. </option>
  392. </select>
  393. <input type="text" name="join1" size="10"
  394. value="<?=display_str($_GET['join1'])?>"
  395. placeholder="YYYY-MM-DD" />
  396. <input type="text" name="join2" size="10"
  397. value="<?=display_str($_GET['join2'])?>"
  398. placeholder="YYYY-MM-DD" />
  399. </td>
  400. <td class="label nobr">Enabled:</td>
  401. <td>
  402. <select name="enabled">
  403. <option value="" <?php if ($_GET['enabled'] === '') {
  404. echo ' selected="selected"';
  405. } ?>>Any
  406. </option>
  407. <option value="0" <?php if ($_GET['enabled']==='0') {
  408. echo ' selected="selected"' ;
  409. } ?>>Unconfirmed
  410. </option>
  411. <option value="1" <?php if ($_GET['enabled']==='1') {
  412. echo ' selected="selected"' ;
  413. } ?>>Enabled
  414. </option>
  415. <option value="2" <?php if ($_GET['enabled']==='2') {
  416. echo ' selected="selected"' ;
  417. } ?>>Disabled
  418. </option>
  419. </select>
  420. </td>
  421. </tr>
  422. <tr>
  423. <td class="label nobr">Email address:</td>
  424. <td>
  425. <input type="text" name="email" size="20"
  426. value="<?=display_str($_GET['email'])?>" />
  427. </td>
  428. <td class="label nobr">Last active:</td>
  429. <td width="30%">
  430. <select name="lastactive">
  431. <option value="on" <?php if ($_GET['lastactive'] === 'on') {
  432. echo ' selected="selected"';
  433. } ?>>On
  434. </option>
  435. <option value="before" <?php if ($_GET['lastactive'] === 'before') {
  436. echo ' selected="selected"';
  437. } ?>>Before
  438. </option>
  439. <option value="after" <?php if ($_GET['lastactive'] === 'after') {
  440. echo ' selected="selected"';
  441. } ?>>After
  442. </option>
  443. <option value="between" <?php if ($_GET['lastactive']==='between') {
  444. echo ' selected="selected"' ;
  445. } ?>
  446. >Between
  447. </option>
  448. </select>
  449. <input type="text" name="lastactive1" size="10"
  450. value="<?=display_str($_GET['lastactive1'])?>"
  451. placeholder="YYYY-MM-DD" />
  452. <input type="text" name="lastactive2" size="10"
  453. value="<?=display_str($_GET['lastactive2'])?>"
  454. placeholder="YYYY-MM-DD" />
  455. </td>
  456. <td class="label nobr">Primary class:</td>
  457. <td>
  458. <select name="class">
  459. <option value="" <?php if ($_GET['class']==='') {
  460. echo ' selected="selected"' ;
  461. } ?>>Any
  462. </option>
  463. <?php foreach ($ClassLevels as $Class) {
  464. if ($Class['Secondary']) {
  465. continue;
  466. } ?>
  467. <option value="<?=$Class['ID'] ?>"
  468. <?php
  469. if ($_GET['class']===$Class['ID']) {
  470. echo ' selected="selected"' ;
  471. } ?>><?=Format::cut_string($Class['Name'], 10, 1, 1).' ('.$Class['Level'].')'?>
  472. </option>
  473. <?php
  474. } ?>
  475. </select>
  476. </td>
  477. </tr>
  478. <tr>
  479. <td class="label tooltip nobr"
  480. title="To fuzzy search (default) for a block of addresses (e.g. 55.66.77.*), enter &quot;55.66.77.&quot; without the quotes">
  481. IP address:</td>
  482. <td>
  483. <input type="text" name="ip" size="20"
  484. value="<?=display_str($_GET['ip'])?>" />
  485. </td>
  486. <td class="label nobr">Locked Account:</td>
  487. <td>
  488. <select name="lockedaccount">
  489. <option value="any" <?php if ($_GET['lockedaccount']=='any') {
  490. echo ' selected="selected"' ;
  491. } ?>>Any
  492. </option>
  493. <option value="locked" <?php if ($_GET['lockedaccount']=='locked') {
  494. echo ' selected="selected"' ;
  495. } ?>>Locked
  496. </option>
  497. <option value="unlocked" <?php if ($_GET['lockedaccount']=='unlocked') {
  498. echo ' selected="selected"' ;
  499. } ?>
  500. >Unlocked
  501. </option>
  502. </select>
  503. </td>
  504. <td class="label nobr">Secondary class:</td>
  505. <td>
  506. <select name="secclass">
  507. <option value="" <?php if ($_GET['secclass']==='') {
  508. echo ' selected="selected"' ;
  509. } ?>>Any
  510. </option>
  511. <?php $Secondaries = [];
  512. // Neither level nor ID is particularly useful when searching secondary classes, so let's do some
  513. // kung-fu to sort them alphabetically.
  514. $fnc = function ($Class1, $Class2) {
  515. return strcmp($Class1['Name'], $Class2['Name']);
  516. };
  517. foreach ($ClassLevels as $Class) {
  518. if (!$Class['Secondary']) {
  519. continue;
  520. }
  521. $Secondaries[] = $Class;
  522. }
  523. usort($Secondaries, $fnc);
  524. foreach ($Secondaries as $Class) {
  525. ?>
  526. <option value="<?=$Class['ID'] ?>"
  527. <?php
  528. if ($_GET['secclass']===$Class['ID']) {
  529. echo ' selected="selected"' ;
  530. } ?>><?=Format::cut_string($Class['Name'], 20, 1, 1)?>
  531. </option>
  532. <?php
  533. } ?>
  534. </select>
  535. </td>
  536. </tr>
  537. <tr>
  538. <td class="label nobr">Ratio:</td>
  539. <td width="30%">
  540. <select name="ratio">
  541. <option value="equal" <?php if ($_GET['ratio'] === 'equal') {
  542. echo ' selected="selected"';
  543. } ?>>Equal
  544. </option>
  545. <option value="above" <?php if ($_GET['ratio'] === 'above') {
  546. echo ' selected="selected"';
  547. } ?>>Above
  548. </option>
  549. <option value="below" <?php if ($_GET['ratio'] === 'below') {
  550. echo ' selected="selected"';
  551. } ?>>Below
  552. </option>
  553. <option value="between" <?php if ($_GET['ratio']==='between') {
  554. echo ' selected="selected"' ;
  555. } ?>>Between
  556. </option>
  557. </select>
  558. <input type="text" name="ratio1" size="6"
  559. value="<?=display_str($_GET['ratio1'])?>" />
  560. <input type="text" name="ratio2" size="6"
  561. value="<?=display_str($_GET['ratio2'])?>" />
  562. </td>
  563. <td class="label nobr">Donor:</td>
  564. <td>
  565. <select name="donor">
  566. <option value="" <?php if ($_GET['donor'] === '') {
  567. echo ' selected="selected"';
  568. } ?>>Any
  569. </option>
  570. <option value="yes" <?php if ($_GET['donor']==='yes') {
  571. echo ' selected="selected"' ;
  572. } ?>>Yes
  573. </option>
  574. <option value="no" <?php if ($_GET['donor'] === 'no') {
  575. echo ' selected="selected"';
  576. } ?>>No
  577. </option>
  578. </select>
  579. </td>
  580. </tr>
  581. <tr>
  582. <?php if (check_perms('users_mod')) { ?>
  583. <td class="label nobr">Staff notes:</td>
  584. <td>
  585. <input type="text" name="comment" size="20"
  586. value="<?=display_str($_GET['comment'])?>" />
  587. </td>
  588. <?php } else { ?>
  589. <td class="label nobr"></td>
  590. <td>
  591. </td>
  592. <?php } ?>
  593. <td class="label tooltip nobr" title="Units are in gibibytes (the base 2 sibling of gigabytes)">Uploaded:</td>
  594. <td width="30%">
  595. <select name="uploaded">
  596. <option value="equal" <?php if ($_GET['uploaded'] === 'equal') {
  597. echo ' selected="selected"';
  598. } ?>>Equal
  599. </option>
  600. <option value="above" <?php if ($_GET['uploaded'] === 'above') {
  601. echo ' selected="selected"';
  602. } ?>>Above
  603. </option>
  604. <option value="below" <?php if ($_GET['uploaded'] === 'below') {
  605. echo ' selected="selected"';
  606. } ?>>Below
  607. </option>
  608. <option value="between" <?php if ($_GET['uploaded']==='between') {
  609. echo ' selected="selected"' ;
  610. } ?>>Between
  611. </option>
  612. <option value="buffer" <?php if ($_GET['uploaded'] === 'buffer') {
  613. echo ' selected="selected"';
  614. } ?>>Buffer
  615. </option>
  616. </select>
  617. <input type="text" name="uploaded1" size="6"
  618. value="<?=display_str($_GET['uploaded1'])?>" />
  619. <input type="text" name="uploaded2" size="6"
  620. value="<?=display_str($_GET['uploaded2'])?>" />
  621. </td>
  622. <td class="label nobr">Warned:</td>
  623. <td>
  624. <select name="warned">
  625. <option value="" <?php if ($_GET['warned'] === '') {
  626. echo ' selected="selected"';
  627. } ?>>Any
  628. </option>
  629. <option value="yes" <?php if ($_GET['warned']==='yes') {
  630. echo ' selected="selected"' ;
  631. } ?>>Yes
  632. </option>
  633. <option value="no" <?php if ($_GET['warned'] === 'no') {
  634. echo ' selected="selected"';
  635. } ?>>No
  636. </option>
  637. </select>
  638. </td>
  639. </tr>
  640. <tr>
  641. <td class="label nobr"># of invites:</td>
  642. <td>
  643. <select name="invites">
  644. <option value="equal" <?php if ($_GET['invites'] === 'equal') {
  645. echo ' selected="selected"';
  646. } ?>>Equal
  647. </option>
  648. <option value="above" <?php if ($_GET['invites'] === 'above') {
  649. echo ' selected="selected"';
  650. } ?>>Above
  651. </option>
  652. <option value="below" <?php if ($_GET['invites'] === 'below') {
  653. echo ' selected="selected"';
  654. } ?>>Below
  655. </option>
  656. <option value="between" <?php if ($_GET['invites']==='between') {
  657. echo ' selected="selected"' ;
  658. } ?>>Between
  659. </option>
  660. </select>
  661. <input type="text" name="invites1" size="6"
  662. value="<?=display_str($_GET['invites1'])?>" />
  663. <input type="text" name="invites2" size="6"
  664. value="<?=display_str($_GET['invites2'])?>" />
  665. </td>
  666. <td class="label tooltip nobr" title="Units are in gibibytes (the base 2 sibling of gigabytes)">Downloaded:</td>
  667. <td width="30%">
  668. <select name="downloaded">
  669. <option value="equal" <?php if ($_GET['downloaded'] === 'equal') {
  670. echo ' selected="selected"';
  671. } ?>>Equal
  672. </option>
  673. <option value="above" <?php if ($_GET['downloaded'] === 'above') {
  674. echo ' selected="selected"';
  675. } ?>>Above
  676. </option>
  677. <option value="below" <?php if ($_GET['downloaded'] === 'below') {
  678. echo ' selected="selected"';
  679. } ?>>Below
  680. </option>
  681. <option value="between" <?php if ($_GET['downloaded']==='between') {
  682. echo ' selected="selected"' ;
  683. } ?>
  684. >Between
  685. </option>
  686. </select>
  687. <input type="text" name="downloaded1" size="6"
  688. value="<?=display_str($_GET['downloaded1'])?>" />
  689. <input type="text" name="downloaded2" size="6"
  690. value="<?=display_str($_GET['downloaded2'])?>" />
  691. </td>
  692. <td class="label tooltip nobr" title="Only display users that have a disabled account linked by IP address">
  693. <label for="disabled_ip">Disabled accounts<br />linked by IP:</label>
  694. </td>
  695. <td>
  696. <input type="checkbox" name="disabled_ip" id="disabled_ip" <?php if ($_GET['disabled_ip']) {
  697. echo ' checked="checked"' ;
  698. } ?> />
  699. </td>
  700. </tr>
  701. <tr>
  702. <td class="label nobr">Disabled invites:</td>
  703. <td>
  704. <select name="disabled_invites">
  705. <option value="" <?php if ($_GET['disabled_invites'] === '') {
  706. echo ' selected="selected"';
  707. } ?>>Any
  708. </option>
  709. <option value="yes" <?php if ($_GET['disabled_invites']==='yes') {
  710. echo ' selected="selected"' ;
  711. } ?>>Yes
  712. </option>
  713. <option value="no" <?php if ($_GET['disabled_invites'] === 'no') {
  714. echo ' selected="selected"';
  715. } ?>>No
  716. </option>
  717. </select>
  718. </td>
  719. <td class="label nobr">Snatched:</td>
  720. <td width="30%">
  721. <select name="snatched">
  722. <option value="equal" <?php if (isset($_GET['snatched']) && $_GET['snatched'] === 'equal') {
  723. echo ' selected="selected"';
  724. } ?>>Equal
  725. </option>
  726. <option value="above" <?php if (isset($_GET['snatched']) && $_GET['snatched'] === 'above') {
  727. echo ' selected="selected"';
  728. } ?>>Above
  729. </option>
  730. <option value="below" <?php if (isset($_GET['snatched']) && $_GET['snatched'] === 'below') {
  731. echo ' selected="selected"';
  732. } ?>>Below
  733. </option>
  734. <option value="between" <?php if (isset($_GET['snatched']) && $_GET['snatched']==='between') {
  735. echo ' selected="selected"' ;
  736. } ?>>Between
  737. </option>
  738. <option value="off" <?php if (!isset($_GET['snatched']) || $_GET['snatched'] === 'off') {
  739. echo ' selected="selected"';
  740. } ?>>Off
  741. </option>
  742. </select>
  743. <input type="text" name="snatched1" size="6"
  744. value="<?=display_str($_GET['snatched1'])?>" />
  745. <input type="text" name="snatched2" size="6"
  746. value="<?=display_str($_GET['snatched2'])?>" />
  747. </td>
  748. <td class="label nobr">Disabled uploads:</td>
  749. <td>
  750. <select name="disabled_uploads">
  751. <option value="" <?php if (isset($_GET['disabled_uploads']) && $_GET['disabled_uploads'] === '') {
  752. echo ' selected="selected"';
  753. } ?>>Any
  754. </option>
  755. <option value="yes" <?php if (isset($_GET['disabled_uploads']) && $_GET['disabled_uploads']==='yes') {
  756. echo ' selected="selected"' ;
  757. } ?>>Yes
  758. </option>
  759. <option value="no" <?php if (isset($_GET['disabled_uploads']) && $_GET['disabled_uploads'] === 'no') {
  760. echo ' selected="selected"';
  761. } ?>>No
  762. </option>
  763. </select>
  764. </td>
  765. </tr>
  766. <tr>
  767. <td width="30%" class="label nobr"># of invitees:</td>
  768. <td>
  769. <select name="invitees">
  770. <option value="equal" <?=isset($_GET['invitees']) && $_GET['invitees'] == 'equal' ? 'selected' : ''?>>Equal
  771. </option>
  772. <option value="above" <?=isset($_GET['invitees']) && $_GET['invitees'] == 'above' ? 'selected' : ''?>>Above
  773. </option>
  774. <option value="below" <?=isset($_GET['invitees']) && $_GET['invitees'] == 'below' ? 'selected' : ''?>>Below
  775. </option>
  776. <option value="between" <?=isset($_GET['invitees']) && $_GET['invitees'] == 'between' ? 'selected' : ''?>>Between
  777. </option>
  778. <option value="off" <?=!isset($_GET['invitees']) || $_GET['invitees'] == 'off' ? 'selected' : ''?>>Off
  779. </option>
  780. </select>
  781. <input type="text" name="invitees1" size="6"
  782. value="<?=display_str($_GET['invitees1'])?>" />
  783. <input type="text" name="invitees2" size="6"
  784. value="<?=display_str($_GET['invitees2'])?>" />
  785. </td>
  786. <td class="label nobr">Passkey:</td>
  787. <td>
  788. <input type="text" name="passkey" size="20"
  789. value="<?=display_str($_GET['passkey'])?>" />
  790. </td>
  791. <td class="label nobr">Tracker IP:</td>
  792. <td>
  793. <input type="text" name="tracker_ip" size="20"
  794. value="<?=display_str($_GET['tracker_ip'])?>" />
  795. </td>
  796. </tr>
  797. <tr>
  798. <td class="label tooltip nobr"
  799. title="Supports partial URL matching, e.g. entering &quot;&#124;https://whatimg.com&quot; will search for avatars hosted on https://whatimg.com">
  800. Avatar URL:</td>
  801. <td>
  802. <input type="text" name="avatar" size="20"
  803. value="<?=display_str($_GET['avatar'])?>" />
  804. </td>
  805. <td class="label nobr">Stylesheet:</td>
  806. <td>
  807. <select name="stylesheet" id="stylesheet">
  808. <option value="">Any</option>
  809. <?php foreach ($Stylesheets as $Style) { ?>
  810. <option value="<?=$Style['ID']?>"
  811. <?Format::selected('stylesheet', $Style['ID'])?>><?=$Style['ProperName']?>
  812. </option>
  813. <?php } ?>
  814. </select>
  815. </td>
  816. <td class="label tooltip nobr" title="Two-letter codes as defined in ISO 3166-1 alpha-2">Country code:</td>
  817. <td width="30%">
  818. <select name="cc_op">
  819. <option value="equal" <?php if ($_GET['cc_op'] === 'equal') {
  820. echo ' selected="selected"';
  821. } ?>>Equals
  822. </option>
  823. <option value="not_equal" <?php if ($_GET['cc_op']==='not_equal') {
  824. echo ' selected="selected"' ;
  825. } ?>>Not
  826. equal
  827. </option>
  828. </select>
  829. <input type="text" name="cc" size="2"
  830. value="<?=display_str($_GET['cc'])?>" />
  831. </td>
  832. </tr>
  833. <tr>
  834. <td class="label nobr">Search type:</td>
  835. <td>
  836. <ul class="options_list nobullet">
  837. <li>
  838. <input type="radio" name="matchtype" id="strict_match_type" value="strict" <?php if ($_GET['matchtype']=='strict' || !$_GET['matchtype']) {
  839. echo ' checked="checked"' ;
  840. } ?> />
  841. <label class="tooltip"
  842. title="A &quot;strict&quot; search uses no wildcards in search fields, and it is analogous to &#96;grep -E &quot;&circ;SEARCHTERM&#36;&quot;&#96;"
  843. for="strict_match_type">Strict</label>
  844. </li>
  845. <li>
  846. <input type="radio" name="matchtype" id="fuzzy_match_type" value="fuzzy" <?php if ($_GET['matchtype']=='fuzzy' || !$_GET['matchtype']) {
  847. echo ' checked="checked"' ;
  848. } ?> />
  849. <label class="tooltip"
  850. title="A &quot;fuzzy&quot; search automatically prepends and appends wildcards to search strings, except for IP address searches, unless the search string begins or ends with a &quot;&#124;&quot; (pipe). It is analogous to a vanilla grep search (except for the pipe stuff)."
  851. for="fuzzy_match_type">Fuzzy</label>
  852. </li>
  853. <li>
  854. <input type="radio" name="matchtype" id="regex_match_type" value="regex" <?php if ($_GET['matchtype']=='regex') {
  855. echo ' checked="checked"' ;
  856. } ?> />
  857. <label class="tooltip" title="A &quot;regex&quot; search uses MySQL's regular expression syntax."
  858. for="regex_match_type">Regex</label>
  859. </li>
  860. </ul>
  861. </td>
  862. <td class="label nobr">Order:</td>
  863. <td class="nobr">
  864. <select name="order">
  865. <?php
  866. foreach (array_shift($OrderVals) as $Cur) { ?>
  867. <option value="<?=$Cur?>" <?php if (isset($_GET['order']) &&
  868. $_GET['order']==$Cur || (!isset($_GET['order']) && $Cur=='Joined')) {
  869. echo ' selected="selected"' ;
  870. } ?>
  871. ><?=$Cur?>
  872. </option>
  873. <?php } ?>
  874. </select>
  875. <select name="way">
  876. <?php foreach (array_shift($WayVals) as $Cur) { ?>
  877. <option value="<?=$Cur?>" <?php if (isset($_GET['way']) &&
  878. $_GET['way']==$Cur || (!isset($_GET['way']) && $Cur=='Descending')) {
  879. echo ' selected="selected"' ;
  880. } ?>
  881. ><?=$Cur?>
  882. </option>
  883. <?php } ?>
  884. </select>
  885. </td>
  886. <td class="label nobr"># of emails:</td>
  887. <td>
  888. <select name="emails_opt">
  889. <option value="equal" <?php if ($_GET['emails_opt']==='equal') {
  890. echo ' selected="selected"' ;
  891. } ?>>Equal
  892. </option>
  893. <option value="above" <?php if ($_GET['emails_opt']==='above') {
  894. echo ' selected="selected"' ;
  895. } ?>>Above
  896. </option>
  897. <option value="below" <?php if ($_GET['emails_opt']==='below') {
  898. echo ' selected="selected"' ;
  899. } ?>>Below
  900. </option>
  901. </select>
  902. <input type="text" name="email_cnt" size="6"
  903. value="<?=display_str($_GET['email_cnt'])?>" />
  904. </td>
  905. </tr>
  906. <tr>
  907. <td colspan="6" class="center">
  908. <input type="submit" value="Search users" />
  909. </td>
  910. </tr>
  911. </table>
  912. </form>
  913. </div>
  914. <?php
  915. if ($RunQuery) {
  916. if (!empty($_GET['ip'])) {
  917. $DB->query("SELECT ID, IP FROM users_main");
  918. while (list($ID, $EncIP) = $DB->next_record()) {
  919. $IPs[] = $ID.", '".Crypto::decrypt($EncIP)."'";
  920. }
  921. $DB->query("CREATE TEMPORARY TABLE users_ips_decrypted (ID INT(10) UNSIGNED NOT NULL, IP VARCHAR(45) NOT NULL, PRIMARY KEY (ID,IP)) ENGINE=MEMORY");
  922. $DB->query("INSERT IGNORE INTO users_ips_decrypted (ID, IP) VALUES(".implode("),(", $IPs).")");
  923. }
  924. if (!empty($_GET['email'])) {
  925. $DB->query("SELECT ID, Email FROM users_main");
  926. while (list($ID, $EncEmail) = $DB->next_record()) {
  927. $Emails[] = $ID.", '".Crypto::decrypt($EncEmail)."'";
  928. }
  929. $DB->query("CREATE TEMPORARY TABLE users_emails_decrypted (ID INT(10) UNSIGNED NOT NULL, Email VARCHAR(255) NOT NULL, PRIMARY KEY (ID,Email)) ENGINE=MEMORY");
  930. $DB->query("INSERT IGNORE INTO users_emails_decrypted (ID, Email) VALUES(".implode("),(", $Emails).")");
  931. }
  932. $Results = $DB->query($SQL);
  933. $DB->query('SELECT FOUND_ROWS()');
  934. list($NumResults) = $DB->next_record();
  935. if (!empty($_GET['ip'])) {
  936. $DB->query("DROP TABLE users_ips_decrypted");
  937. }
  938. if (!empty($_GET['email'])) {
  939. $DB->query("DROP TABLE users_emails_decrypted");
  940. }
  941. $DB->set_query_id($Results);
  942. } else {
  943. $DB->query('SET @nothing = 0');
  944. $NumResults = 0;
  945. }
  946. ?>
  947. <div class="linkbox">
  948. <?php
  949. $Pages = Format::get_pages($Page, $NumResults, USERS_PER_PAGE, 11);
  950. echo $Pages;
  951. ?>
  952. </div>
  953. <div class="box pad center">
  954. <h2><?=number_format($NumResults)?> results</h2>
  955. <table width="100%">
  956. <tr class="colhead">
  957. <td>Username</td>
  958. <td>Ratio</td>
  959. <td>IP address</td>
  960. <td>Email</td>
  961. <td>Joined</td>
  962. <td>Last seen</td>
  963. <td>Upload</td>
  964. <td>Download</td>
  965. <td>Downloads</td>
  966. <td>Snatched</td>
  967. <td>Invites</td>
  968. <?php if (isset($_GET['invitees']) && $_GET['invitees'] != 'off') { ?>
  969. <td>Invitees</td>
  970. <?php } ?>
  971. </tr>
  972. <?php
  973. while (list($UserID, $Username, $Uploaded, $Downloaded, $Snatched, $Invitees, $Class, $Email, $Enabled, $IP, $Invites, $DisableInvites, $Warned, $Donor, $JoinDate, $LastAccess) = $DB->next_record()) {
  974. $IP = apcu_exists('DBKEY') ? Crypto::decrypt($IP) : '[Encrypted]';
  975. $Email = apcu_exists('DBKEY') ? Crypto::decrypt($Email) : '[Encrypted]'; ?>
  976. <tr>
  977. <td><?=Users::format_username($UserID, true, true, true, true)?>
  978. </td>
  979. <td><?=Format::get_ratio_html($Uploaded, $Downloaded)?>
  980. </td>
  981. <td style="word-break: break-all;"><?=display_str($IP)?>
  982. </td>
  983. <td><?=display_str($Email)?>
  984. </td>
  985. <td><?=time_diff($JoinDate)?>
  986. </td>
  987. <td><?=time_diff($LastAccess)?>
  988. </td>
  989. <td><?=Format::get_size($Uploaded)?>
  990. </td>
  991. <td><?=Format::get_size($Downloaded)?>
  992. </td>
  993. <?php $DB->query("
  994. SELECT COUNT(ud.UserID)
  995. FROM users_downloads AS ud
  996. JOIN torrents AS t ON t.ID = ud.TorrentID
  997. WHERE ud.UserID = $UserID");
  998. list($Downloads) = $DB->next_record();
  999. $DB->set_query_id($Results); ?>
  1000. <td><?=number_format((int)$Downloads)?>
  1001. </td>
  1002. <td><?=(is_numeric($Snatched) ? number_format($Snatched) : display_str($Snatched))?>
  1003. </td>
  1004. <td>
  1005. <?php if ($DisableInvites) {
  1006. echo 'X';
  1007. } else {
  1008. echo number_format($Invites);
  1009. } ?>
  1010. </td>
  1011. <?php if (isset($_GET['invitees']) && $_GET['invitees'] != 'off') { ?>
  1012. <td><?=number_format($Invitees)?>
  1013. </td>
  1014. <?php } ?>
  1015. </tr>
  1016. <?php
  1017. }
  1018. ?>
  1019. </table>
  1020. </div>
  1021. <div class="linkbox">
  1022. <?=$Pages?>
  1023. </div>
  1024. <?php View::show_footer();